<![CDATA[Yashints | Blog]]>https://yashints.devGatsbyJSFri, 07 Jun 2024 03:42:12 GMT<![CDATA[🖥️ Use local AI to supercharge your coding skills]]>https://yashints.dev/blog/2024/06/07/ollama-continuehttps://yashints.dev/blog/2024/06/07/ollama-continueFri, 07 Jun 2024 00:00:00 GMT<p>Are you a developer who wants to use AI in their day to day coding but don’t have access to tools like <a href="https://github.com/features/copilot" target="_blank" rel="nofollow noopener noreferrer">GitHub Copilot</a>, <a href="https://github.blog/2024-04-29-github-copilot-workspace/" target="_blank" rel="nofollow noopener noreferrer">GitHub Copilot Workspace</a> or Cloud based services like <a href="https://azure.microsoft.com/en-au/products/ai-services/openai-service" target="_blank" rel="nofollow noopener noreferrer">Azure OpenAI</a>? If yes, read on and you’re going to have super powers by the end of this post.</p> <!--more--> <h2 id="why-bother" style="position:relative;"><a href="#why-bother" aria-label="why bother permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 bother?</h2> <p>If you’re wondering what is all the fuss and why should I bother, I have to tell you AI is moving like a speed train and if you don’t jump in, you’ll be left behind and it would be very hard to catch on later. AI can help you enhance your coding skills, increase your productivity, and help you learn a great deal more than you do in your job.</p> <p>Here are some reasons why any developer needs to use AI:</p> <ul> <li><strong>Automated code generation</strong>: AI can generate code and save you time and effort. You can get suggestions with snippets of code and even get the rest of your code completed as soon as you have some of it written. This can speed up your coding and development process by a great deal.</li> <li><strong>Code review</strong>: AI can help to review code and identify potential issues, bugs, security vulnerabilities and code smells before they even become problems. This can improve the overall quality of your code and products and reduce time spent fixing bugs after go live.</li> <li><strong>Personalised learning</strong>: AI can provide personalised learning experience for you and help improve your skills and knowledge in a way which is tailored to your needs and learning style.</li> <li><strong>Natural language (NLP)</strong>: In addition to all of the previous points, you get to use your natural language to interact with AI using prompts, voice etc which makes the whole process even faster.</li> </ul> <h2 id="setup---lets-get-cracking" style="position:relative;"><a href="#setup---lets-get-cracking" aria-label="setup lets get cracking permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup - let’s get cracking</h2> <p>Enough talk, let’s get into the action. You will need these before you can leverage AI in your development environment:</p> <ul> <li><a href="https://ollama.com/" target="_blank" rel="nofollow noopener noreferrer">Ollama</a> which is an open source project allowing you to interact with LLMs locally. If you don’t have it setup, <a href="/blog/2024/05/28/local-llms/">use my earlier post</a> to get setup. We also need to have a model installed which supports code generation.</li> <li><a href="https://code.visualstudio.com/" target="_blank" rel="nofollow noopener noreferrer">VS Code</a> which is also an open source code editor which has billions of users globally. <em>You can use <a href="https://www.jetbrains.com/" target="_blank" rel="nofollow noopener noreferrer">JetBrains</a> if you are using that already BTW</em>.</li> <li><a href="https://www.continue.dev/" target="_blank" rel="nofollow noopener noreferrer">Continue</a> which is an extension which allows you to leverage LLMs in your code editors using cloud or local hosted models.</li> </ul> <h3 id="install-the-code-generation-model" style="position:relative;"><a href="#install-the-code-generation-model" aria-label="install the code generation model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the code generation model</h3> <p>Go into the environment which you have Ollama installed and install the <code class="language-text">starcoder</code> model. You can get the 3b parameter version or if you’re adventurous like me, get the 7b version which is roughly 4GB.</p> <div class="gatsby-code-button-container" data-toaster-id="19696139080787380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ollama pull starcoder2:7b`, `19696139080787380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ollama pull starcoder2:7b</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And you should see the model being pulled and installed.</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/f80157b18b008a25f3bf964a2fb98e78/ab98c/pullmodel.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 20.740740740740744%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA+klEQVR42j3P7UuDUBQGcD/Worex0pmZXl/urjZd6qblxojqSxCtFdXofwgGo1W46D9/Ol5iH36cBw48nKPEaYEo6YMHEaKzAeI0RxCl6FL2RATGT2F5Ag4PYfsB2qZDGEzGYblird7VlN5giGJ4iXJ8DVfEVJbhfb5A9fOL5VdFVvggy+/Vf64wX3wi7pfQ7Q5aRwwHhkNcSQmTc8TZBZJiBDfowWACN7cT3D28SPePr2uTpxmmz2+UZ/C7GRUKqKYP7aTG5VTy0RXycizfrDE/hGrY0Om1pnqMxp6GjZ1DbO6qaOxr2Grq2G4ZdJlDZR40i6NtdaS69A9FZIBrryy18wAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Pulling down the startcode model in Ollama" title="" src="/static/f80157b18b008a25f3bf964a2fb98e78/302a4/pullmodel.png" srcset="/static/f80157b18b008a25f3bf964a2fb98e78/01bf6/pullmodel.png 270w, /static/f80157b18b008a25f3bf964a2fb98e78/07484/pullmodel.png 540w, /static/f80157b18b008a25f3bf964a2fb98e78/302a4/pullmodel.png 1080w, /static/f80157b18b008a25f3bf964a2fb98e78/0d292/pullmodel.png 1620w, /static/f80157b18b008a25f3bf964a2fb98e78/b3608/pullmodel.png 2160w, /static/f80157b18b008a25f3bf964a2fb98e78/ab98c/pullmodel.png 2356w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h3 id="install-the-extension" style="position:relative;"><a href="#install-the-extension" aria-label="install the 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>Install the extension</h3> <p>First you need to install <a href="https://marketplace.visualstudio.com/items?itemName=Continue.continue" target="_blank" rel="nofollow noopener noreferrer">Continue extension</a> in VS Code. You can click on the link from here or go into your VS Code extensions and get it installed.</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/2ec0daeea40fd60badd27bb93e4b4058/6114f/vscodeext.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 31.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABbElEQVR42k2RzUvjQBiH+3eYNMlkkjaJaTr90K2KSlUW9qiC4HXvHhT/Hi/Cssv+AQoLWvqBsAseBC8e9KQHK5hLLUrhcRL82IGHl5dhnnfmNwUhfYIoRvplpFfC07jSo9GcIUkShBBI3ZfLek8KXNfFtm0Mw/igWCziOE5eCwvtb6xu7VBpb6O+fkeGtfzg0dExu3v7+EGMUnVUtUpdxcSxHi4llmXl4kyU1fe+0GoqVlbaJLUmanaZUhjnkzbXN5hfWsOWEaYxhWmaGBrzjUyQybL6LsuFSVJlOgqRwsELKjiuh1fyOfhxSOf0JKfb7dHv9zU9Op0Og8GAn79/6dtWCMNQx+R9CucW2zRb89hWkVKkEK7ONAj4d3NJtsZPY25v7xgOH7i/H/Ly8sxkAhdX11RrNZ27n+f8IazPfEE1ZnFsC+FH2EJS9kPOzi8YjUekaaplw5xMmKaPPI2e+TP4S5jUsR39Sf89+RUAsOoevZeb5QAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Installing continue extension in VS Code" title="" src="/static/2ec0daeea40fd60badd27bb93e4b4058/302a4/vscodeext.png" srcset="/static/2ec0daeea40fd60badd27bb93e4b4058/01bf6/vscodeext.png 270w, /static/2ec0daeea40fd60badd27bb93e4b4058/07484/vscodeext.png 540w, /static/2ec0daeea40fd60badd27bb93e4b4058/302a4/vscodeext.png 1080w, /static/2ec0daeea40fd60badd27bb93e4b4058/0d292/vscodeext.png 1620w, /static/2ec0daeea40fd60badd27bb93e4b4058/b3608/vscodeext.png 2160w, /static/2ec0daeea40fd60badd27bb93e4b4058/6114f/vscodeext.png 3823w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h3 id="configuring-the-extension" style="position:relative;"><a href="#configuring-the-extension" aria-label="configuring the 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>Configuring the extension</h3> <p>Once you have both of those installed, you can go ahead and configure your extension to use your local Ollama instance. Open the <code class="language-text">config.json</code> settings for Continue using <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>, then typing <code class="language-text">> continue: open config.json</code>. Keep in mind that Continue supports a <a href="https://docs.continue.dev/setup/select-provider" target="_blank" rel="nofollow noopener noreferrer">whole host of providers</a> other than local ones. Go ahead and add the models you want to the config file. Do not forget to change the IP address to match your own instance if it is not available on <code class="language-text">localhost</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="6950079955447253000" data-toaster-class="gatsby-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;models&quot;: [ { &quot;title&quot;: &quot;Llama 3&quot;, &quot;provider&quot;: &quot;ollama&quot;, &quot;model&quot;: &quot;llama3&quot;, &quot;apiBase&quot;: &quot;http://localhost:11434/&quot; }, { &quot;title&quot;: &quot;Starcoder 7b&quot;, &quot;provider&quot;: &quot;ollama&quot;, &quot;model&quot;: &quot;starcoder2:7b&quot;, &quot;apiBase&quot;: &quot;http://localhost:11434/&quot; } ], &quot;customCommands&quot;: [ { &quot;name&quot;: &quot;test&quot;, &quot;prompt&quot;: &quot;{{{ input }}}\n\nWrite a comprehensive set of unit tests for the selected code. It should setup, run tests that check for correctness including important edge cases, and teardown. Ensure that the tests are complete and sophisticated. Give the tests just as chat output, don't edit any file.&quot;, &quot;description&quot;: &quot;Write unit tests for highlighted code&quot; } ], &quot;tabAutocompleteModel&quot;: { &quot;title&quot;: &quot;Starcoder 7b&quot;, &quot;provider&quot;: &quot;ollama&quot;, &quot;model&quot;: &quot;starcoder2:7b&quot;, &quot;apiBase&quot;: &quot;http://localhost:11434/&quot; }, &quot;allowAnonymousTelemetry&quot;: true, &quot;embeddingsProvider&quot;: { &quot;provider&quot;: &quot;transformers.js&quot; } }`, `6950079955447253000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"models"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Llama 3"</span><span class="token punctuation">,</span> <span class="token property">"provider"</span><span class="token operator">:</span> <span class="token string">"ollama"</span><span class="token punctuation">,</span> <span class="token property">"model"</span><span class="token operator">:</span> <span class="token string">"llama3"</span><span class="token punctuation">,</span> <span class="token property">"apiBase"</span><span class="token operator">:</span> <span class="token string">"http://localhost:11434/"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Starcoder 7b"</span><span class="token punctuation">,</span> <span class="token property">"provider"</span><span class="token operator">:</span> <span class="token string">"ollama"</span><span class="token punctuation">,</span> <span class="token property">"model"</span><span class="token operator">:</span> <span class="token string">"starcoder2:7b"</span><span class="token punctuation">,</span> <span class="token property">"apiBase"</span><span class="token operator">:</span> <span class="token string">"http://localhost:11434/"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"customCommands"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"test"</span><span class="token punctuation">,</span> <span class="token property">"prompt"</span><span class="token operator">:</span> <span class="token string">"{{{ input }}}\n\nWrite a comprehensive set of unit tests for the selected code. It should setup, run tests that check for correctness including important edge cases, and teardown. Ensure that the tests are complete and sophisticated. Give the tests just as chat output, don't edit any file."</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Write unit tests for highlighted code"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"tabAutocompleteModel"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Starcoder 7b"</span><span class="token punctuation">,</span> <span class="token property">"provider"</span><span class="token operator">:</span> <span class="token string">"ollama"</span><span class="token punctuation">,</span> <span class="token property">"model"</span><span class="token operator">:</span> <span class="token string">"starcoder2:7b"</span><span class="token punctuation">,</span> <span class="token property">"apiBase"</span><span class="token operator">:</span> <span class="token string">"http://localhost:11434/"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"allowAnonymousTelemetry"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token property">"embeddingsProvider"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"provider"</span><span class="token operator">:</span> <span class="token string">"transformers.js"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="testing" style="position:relative;"><a href="#testing" aria-label="testing permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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</h2> <p>Let’s test our setup, go ahead and open a file in which you have any code written. Select a code block and press <kbd>Ctrl</kbd> + <kbd>L</kbd> which opens the chat window, type <code class="language-text">Explain this code to me in a few sentences</code> and press enter. You should see the explanation getting generated in the chat window:</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/90a091790edb4e4bfc9a3317d27a018d/38abd/explain.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 73.7037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAACHElEQVR42p1UWa6jMBDkFtnY4hVjbCAhb6KR5v7Hqqk2eVE0X6P3UQLs7uqlKql6ZaC1Qtt2aJoGSilYa6GVhup7XM5nNHXN+/YNiXHOoef95/mZsZUcDmEsJNfrleQaxlgmeIQQMUwZfhzRdT3RoSUudYPL5YKahaQJQds2hbRS7GRdV6SUSlUhlg4E2gX4dMc4z5iWGcvGuCUheEs4aKPQs4m9066gknGXZXmTeu9fXRoobeHjjHT7wsiYtGas84jHMuFG5Byx5AlxHOBIrtUVlbED5pzweGxvYiHTeicclhXz7z+Y1lu5+7U9EGMssSlyAqPhrSlQQqiZvG0b7vd7SRi5LxlX9nglqWF1HSzs4GF8QK8szDCy88yVeJ6PEI76JVwle3s+n9gej0Iqlb0fyi6tk5ETFt7FG0dfE7Z7ZkxEThw1kpjCBYoq4jmuqxJlnSRzl4rvstiaCnonS6d9DLtgAUVyNzikKWAMns4IGAaec98irNa7mFVgYpbgvoPp6LFuJxRhFEfePbbbQuxR1/JsC76tsltnt1Al5rViEdkbSTS7FIPu3hLP1WU/7+fLf/XH9/F4fKOSCpZdLjnjNkUqFwvh4XAokKDP9+/v4+vs87wQSnKgsjeKsdCHEwkbFvk38H9RdRxtoiUynT9yZCvOF8IfkBVC+eEbkqQwILPTidLX7Pr4U8L+qor07uV0+RMQQU6n04/wFxOIojU4QUrfAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Local LLM being used in VS Code using the Continue extension" title="" src="/static/90a091790edb4e4bfc9a3317d27a018d/302a4/explain.png" srcset="/static/90a091790edb4e4bfc9a3317d27a018d/01bf6/explain.png 270w, /static/90a091790edb4e4bfc9a3317d27a018d/07484/explain.png 540w, /static/90a091790edb4e4bfc9a3317d27a018d/302a4/explain.png 1080w, /static/90a091790edb4e4bfc9a3317d27a018d/0d292/explain.png 1620w, /static/90a091790edb4e4bfc9a3317d27a018d/b3608/explain.png 2160w, /static/90a091790edb4e4bfc9a3317d27a018d/38abd/explain.png 2766w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="using-tab-for-auto-completion" style="position:relative;"><a href="#using-tab-for-auto-completion" aria-label="using tab for auto completion permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 tab for auto completion</h2> <p>You can use tab to complete code in your code file. Create a new file called <code class="language-text">index.js</code>, enter below comments:</p> <div class="gatsby-code-button-container" data-toaster-id="14147949573603547000" data-toaster-class="gatsby-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 function which calculates fibonacci sequence // and returns the nth number in the sequence`, `14147949573603547000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token comment">// a function which calculates fibonacci sequence</span> <span class="token comment">// and returns the nth number in the sequence</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Go to the next line and wait until your see the function name getting generated, if it didn’t type the function name and wait, it should generate the function and show you in highlighted grey text:</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/944e3c4cc7a9ee991cfb44aef5fb39dc/8ae78/codecompletion.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 35.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAA40lEQVR42o1R2W7DIBDkPxpzGLDNYRtI4tZR+/+fNQUalLSylD4Me2p2hyVfnyv8GmHWDZPz2PeA/SPgelnwvnmkMCLFEYJzMMZegsRoEc8p44w1zNiuM257ynbJRBPCouGsAhccnL8GYYxWxxoD5xy0HtH3Ct2J4i3j1FF0Gc9bPBPUmD22JyUppYT3Htba6nPOQCmtOJLVakc9pDxCCLhMWEi11nXTNsC5nyFSKYzjcB8+w+ceYyxstlL2ULk+DANICUpTI25Sil/B7zn2kNhqv2S3P7ykKa/N/nXBQ/l/rvwNPdDFs73BBzQAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Continue generating code from comment" title="" src="/static/944e3c4cc7a9ee991cfb44aef5fb39dc/302a4/codecompletion.png" srcset="/static/944e3c4cc7a9ee991cfb44aef5fb39dc/01bf6/codecompletion.png 270w, /static/944e3c4cc7a9ee991cfb44aef5fb39dc/07484/codecompletion.png 540w, /static/944e3c4cc7a9ee991cfb44aef5fb39dc/302a4/codecompletion.png 1080w, /static/944e3c4cc7a9ee991cfb44aef5fb39dc/8ae78/codecompletion.png 1096w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Press <kbd>Tab</kbd> and the code should be persisted.</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/9478b770b792262cc21c73a5266cd384/cd536/compleetedcode.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 34.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAA+0lEQVR42pVR7W6DMAzkQdZ8QTCkQJNSaAntD/b+73QzaZnGpknbj5OjO/lsXzJqB1TdgPoUQXWD+2PAfL9gHAPi5NH3Dq6SkPJvyKg6IrBpw+hCgA8tbmGEoxrWGhSFgTH/MNRagQrCzU+4+isbezYiiDeBw0FAML43CfGV2+uZzS2OJZ/aP3B2ZzavoHjI2qSUZGxv9WxiTqvfdd5QJ5MYZgzr6a7Gstwwxwti7OHHGUVJcG0Hci3apsb7MrHeY5peemFZP6U/yIjPs6ZME7Q2qeb5ml2e6pPTid+w6cawbsxOyyrSEFJ9ZrCtLsQ+N/WCVOpHplvPGsEH8F7IN0UNhFEAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Getting autocomplete on tab" title="" src="/static/9478b770b792262cc21c73a5266cd384/302a4/compleetedcode.png" srcset="/static/9478b770b792262cc21c73a5266cd384/01bf6/compleetedcode.png 270w, /static/9478b770b792262cc21c73a5266cd384/07484/compleetedcode.png 540w, /static/9478b770b792262cc21c73a5266cd384/302a4/compleetedcode.png 1080w, /static/9478b770b792262cc21c73a5266cd384/cd536/compleetedcode.png 1114w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="refactor-code" style="position:relative;"><a href="#refactor-code" aria-label="refactor 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>Refactor code</h2> <p>When you’re writing code, you could ask AI to refactor the code for you. Go ahead and clear the content of the file and replace it with below:</p> <div class="gatsby-code-button-container" data-toaster-id="77809810022103630000" data-toaster-class="gatsby-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 calculateTotal(items) { let total = 0; for (let i = 0; i < items.length; i++) { total += items[i]; } return total; }`, `77809810022103630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">calculateTotal</span><span class="token punctuation">(</span><span class="token parameter">items</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> total <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> items<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> total <span class="token operator">+=</span> items<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> total<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now press <kbd>Ctrl</kbd> + <kbd>I</kbd> and type refactor this code in the prompt and press <kbd>Enter</kbd>. Wait for the model to do its thing and you should see the result which you can accept or reject:</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/e7877870f4f16f7ba767c9e1abc90f81/082c8/refactor.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 27.40740740740741%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAwklEQVR42o3O206DUBCFYV5ECvsEe1eIRNNCBam2VAgl8f1f5ncwva3pxZeszExWJlIqpSm2tOUq0BaeTvIhOJrcUmeaOjc03vJmEl715q5KJ0QqTRmfHT8vnqXMuRaO69YwB82UJYw2fsgkTiZeCxVfwTJJybdXXNyGQZztk4gfNoh+LdTG8HncM44ty3JgmRumuWO47Oj7SnYVp/OO40dJ+x7u6tpAvfdERgozr8nkyyyYG/vHSXa3vM6d3P3H5opfYo2Z7MBe/BUAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Code refactoring using local LLMs" title="" src="/static/e7877870f4f16f7ba767c9e1abc90f81/302a4/refactor.png" srcset="/static/e7877870f4f16f7ba767c9e1abc90f81/01bf6/refactor.png 270w, /static/e7877870f4f16f7ba767c9e1abc90f81/07484/refactor.png 540w, /static/e7877870f4f16f7ba767c9e1abc90f81/302a4/refactor.png 1080w, /static/e7877870f4f16f7ba767c9e1abc90f81/0d292/refactor.png 1620w, /static/e7877870f4f16f7ba767c9e1abc90f81/b3608/refactor.png 2160w, /static/e7877870f4f16f7ba767c9e1abc90f81/082c8/refactor.png 2734w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="ask-questions-about-your-codebase" style="position:relative;"><a href="#ask-questions-about-your-codebase" aria-label="ask questions about your codebase permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Ask questions about your codebase</h2> <p>You can also ask questions about your codebase by pressing <kbd>Ctrl</kbd> + <kbd>L</kbd> and typing <code class="language-text">@codebase</code> and then your question.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 829px; " > <a class="gatsby-resp-image-link" href="/static/6eb6420cf2603c3e0a390bcdd9c65f8b/9d76a/codebase.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 192.962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAnCAYAAAAPZ2gOAAAACXBIWXMAABYlAAAWJQFJUiTwAAAE1UlEQVR42oWW2VbjSAyG/Q4QCCGbs4fYsePsCWFNoLnkDbjlnsPra/Qpkcfd05y50KkqVZXWX6oKepOd9JOl9Ltt6XS6MhqNdOzIcDjM575ut9vS7Xal1+sZwb+5uTFijzFo3UwlHCTSabckbLXsUKPRkH6/b0JYt5Q/GAwkDENbu2DWCGbebDbtTNCoV2XQ68rF5aUJHMdjScZjqVarcnFxIeVy2ehS930OsReGTVM8n89MWK1WkwANLLhQqVwbE7q85FLJ+E4IKc4RjGI8qOud6+trCWBeXV3ZIk1TmU6nRlk2kTiO8xhBxLS4jqLIeFgJEaoA32Ei+OPjQ76/v+Xr60s+Pz/l7e1NXl5e5Pn5WQ6Hg7y+vtoIwXfabrdqQGaxDSqVipRKJTN9t9vZ5SRJcppMJmZ5kX7i4XpApiDihqtsoA06uv7feZHn/NlsdhToeCKOrRNsMB1yZUUiRD8RXgaetWJyIEJxfn5uREiK82K2i8SdAFCSMbeQbDFiOcBmjdVAy4Fer9dNKXecMMgE4gamukAyjrtcRBk8iLmvi9YXwW8CSQb4QSDusEHWPMME3DPOnL35fC7L5VI2m41hFYNyl3GFQ66Fzfv7+xx3wOjx8VH2+72Rz29vby2z3CUEuUCfYCFzBN7d3cnT05MBdrVa2RwFCGHv4eFBFotFDpnfBBJoXHML2QTgWIEgiDXuoQCh6/XaiDPwfhPo+EIYMcRSjx+xglAKzkjIv3gMNfZNnWuSNOO5QNJfO3UKb6JFEIfNhrS0TXU6mvl2aOu2jr2uFkCLcw1LKtnGmMC7MdK99Ah0RnymmuFsIeNsJd1hLOOpZlXnUbqQZLqWdL41XhTF1hutH3qzZOH1icDZJJN5mkg8WUm8+iXR8iDj9atEi73E618SL/cyWhx0/irZbGFN1mqZKsEqsmtFr4K6WiWJgng10r6nrmaTVAZ9rahBX6KbgcTRUNIklqHyWE/Vk1rtmJgA/719A9Kxtv+2ajpXq0t0Zu3cJZ3zRDDa/ELnpeMIUTEIs46NZV563hR8hO/N4ideMakmEFjgMnGkpbMGtICXcBAGygzcAWr2wSK4JNYAn8RyBg8DLEMY0r2vARngQzh8DTkOvWGwxzkf2csbLNmmVRFDNP0fcY7zVAkCUc7cgI1k4gMzNCtaf+3WRbKnUwVwz8li6G0fRqxaI4XLNhpJqpb3T50Ia4gn3hBn1pQn3YaRNXwrPVrV+/u7xRFXZgBbDzFPNVkcHusagbFegj86vdEkMzrxcJuwBW4qRJVwkItJkkrU78lcwR3rmNB0lfBioKXKWUoWYYwoNgv97UAgwlyzuaWCZ1p+2cnKTNeLcSzLOJI0jo7u4okq8pfTmoN/I9AKzsAY74e9K6qwraNBSZMw1A4z4B1XgDsfo7DOXPZK8U+Pf9nKvDGFJ9RGpbPTSMzhOeXtCxfJFrWIlU4OVEeBE9b4R8BfRz9jOCxfVUwY0skYwnGbMvPngVBQjpQca0JCyRFD+AjkHsYF292DvnJ3KrCSl56jvrh2XtELiFAx0iDsK7La7PSh2ZiVuONALdKfPy3/bdH2UOKKrGOXtJ+dnZ3ZwmNiJXh6U3AHzf73+ZOK32RLSrV6BDVaiKET8SCGWOM/g+LlvxEC/wHidWhQmGvB8wAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="using context to ask question about the codebase" title="" src="/static/6eb6420cf2603c3e0a390bcdd9c65f8b/9d76a/codebase.png" srcset="/static/6eb6420cf2603c3e0a390bcdd9c65f8b/01bf6/codebase.png 270w, /static/6eb6420cf2603c3e0a390bcdd9c65f8b/07484/codebase.png 540w, /static/6eb6420cf2603c3e0a390bcdd9c65f8b/9d76a/codebase.png 829w" sizes="(max-width: 829px) 100vw, 829px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="use-documentation-as-context-for-your-questions" style="position:relative;"><a href="#use-documentation-as-context-for-your-questions" aria-label="use documentation as context for your questions permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 documentation as context for your questions</h2> <p>You can use documentation when interacting with AI which adds more accuracy to the response. The team have done a fantastic job and have pretty much any language or framework you can think of linked. You can use the <code class="language-text">@docs</code> and then select your preferred documentation, or just simply type the doc name if you know it.</p> <p>Let’s open the chat window using <kbd>Ctrl</kbd> + <kbd>L</kbd>, then type <code class="language-text">@react</code> and then <code class="language-text">How do I update the page based on a parameter?</code> then press <kbd>Enter</kbd>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 784px; " > <a class="gatsby-resp-image-link" href="/static/7c25b147c7111cd502e4fd4fede99b5c/4971b/docs.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 135.92592592592595%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAYAAAB836/YAAAACXBIWXMAABYlAAAWJQFJUiTwAAADYUlEQVR42oWVyU7jQBCG/QwsWQjZnDibY8fZE7IAAiQkDtwQF8Qj8P6nmvqKlGXQjObwu7qrq/+urdtBs9mUdrst1WpVWq2W9Ho9Q73RMN3V1dU/cX19Lc1mQ8bjWDG2fQGD0WgkpVJJwrAjSZIqEmko4eXlpZTL5b8Ce0ixi+ORDIdD6YShBLVaTSqVii3iUelEwukYg3q9bnPkb7CffUjmASF3u11TvL+/y9fXl3x8fMjt7a08PDzI3d2d3N/fy8vLi83B4+OjPD095UB3PBxkPp9LQP4gxYPX11f5/PyUt7c3eX5+loMarddrubm5kePxKNvt1oB+v9/LbrczbDYbw3Q6lQB3CRFS3+CGGGRZZphMJj/GPneJ7Ww2+y5Kv9+3kBnHcWxFAhQnTdP/wu2QAa3ihcHLUCuFzvXFNiGaYisV5z4OvDquKILWoHWQFxcX+dzB3HU4BAJi9yrjMv1EgxIyqSANg8HAQkICbIohkybqYIRUlwleLpdLA4mmBcBisbBNq9XK5p58iseYFOFMToh3AGKIfINXzz3AU8bofIwNe4nEHQsIjzBQeFsQOpuclAPwDsmBxepiQ1SdTsfyGcBKASAkPAebfaPnEkBCfllHkk9IccwIWcAIUgw8FEjOz8+tulQRWcTZ2VmudzsLGVe9bfwhQNKT/jj8hvcptkh0XGGk9SHwopAzckLOKIZfK9ZIhReNdSLz60cXYB/wIQ+U3MP1yroxc7+ipKWYS3LHIVEUWdiBP5Z4SG9BgAd4iUccBopechivEICYq5ffFD+tWq3kZGCop1sf6hoESyXiEPOa6qt+TugK8pc3tl8rTsnwQjFUHQmu8SLzWtc16XojGhRKwf8GNCmIztlLlEbIJw9ZyRbkUfMS6c9n0G7JKGxLTzcxj3jdG98y1INAX0k7QLsF4oCXN9a/VkVd3hCGhrpJxrJOE9lnE9kptnrIYZqZbqG220kq09FQ56nZjrltmmd7vug378Mk1aRrnlLypOhGPUlpJc1TNtM2Gicy5YbwCCvmahtp5cungljINKa9Nhry6vTaUADagDB6KrNTdSkI/YZkPj/dMr+qRuj3EQ95ORhTVSpefCBcsgYJje09Chl6I/THgbD5c7EIkfchIAr/L/utKs6tI06/kT/9TBQXoJ8adgAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Using documentation when interacting with AI" title="" src="/static/7c25b147c7111cd502e4fd4fede99b5c/4971b/docs.png" srcset="/static/7c25b147c7111cd502e4fd4fede99b5c/01bf6/docs.png 270w, /static/7c25b147c7111cd502e4fd4fede99b5c/07484/docs.png 540w, /static/7c25b147c7111cd502e4fd4fede99b5c/4971b/docs.png 784w" sizes="(max-width: 784px) 100vw, 784px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="perform-actions-with-slash" style="position:relative;"><a href="#perform-actions-with-slash" aria-label="perform actions with slash permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Perform actions with slash</h2> <p>You can kick off an action using the slash in the chat window, this could be edit, comment, share, commit, test (which I had in the config and shows you how to do custom ones) or any predefined custom command.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 703px; " > <a class="gatsby-resp-image-link" href="/static/b00b9ec1b0c6178195d8bc356933be1e/242e2/slash.png" 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/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB9klEQVR42qVUXW8SURDlN0jLfl8WlkB3Yb93KWzpUiVEoVCMaaqJNqkf0fTF+KA+1EQb+8OPM9diTB9U8OHkzsydOXNmZ3crQgjYto16vQ7DMKBp2l+hqiqEZcEidDodNBoNCa6vxFGCJE2RJgkazSZqtZos+BM4p9VqwXFamE4n2HP30O160HUdFUVRZMK/EP0OrlvXrmNSYa/XI/buf8N1XZimicpwOEQcx8iyDCmPvgW4Nooi+UwrnueBVXIH7sT+JuBa3/elLQnDMEQQBBiPx8jzXMrmra83twkkIUtlQpae0Ka5AXflhCZtfRNIQiZjAlbHz5OV9vt9qXIrQp6fVRVFgbIs5YvKF47jbEfIIzN4U4PBAO12e2OiO4QxbSkgsiEyGtuiT7HZdLbALWEah0gjH2kcYFTs46gsYAsDwtRgWwbqlv4Ld31hUkyQLU8TQvBSDhboFifIJ6eIj57ASR/BLxaIyhU6+zP0yPYPfsIbzil3gXC0REAID0/gDuZ0t0Qnm8C0BP0c5peIF+8xPf+C/PEHVJNnKE4/4vj1NUZnn3D/+RUeXnzF7OU3GX/w4gqrdzdYvb3B8s13HD79jNmra2THl9ANUqgZJlTdxL1dFbuKDo2C1ZpGvkK+hh2yq3RXranYYf82xuc6h/P5NA0DPwD0uNZ9K6j/wQAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Slash actions in using continued" title="" src="/static/b00b9ec1b0c6178195d8bc356933be1e/242e2/slash.png" srcset="/static/b00b9ec1b0c6178195d8bc356933be1e/01bf6/slash.png 270w, /static/b00b9ec1b0c6178195d8bc356933be1e/07484/slash.png 540w, /static/b00b9ec1b0c6178195d8bc356933be1e/242e2/slash.png 703w" sizes="(max-width: 703px) 100vw, 703px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>I will use the test command, select the code in your file and press <kbd>Ctrl</kbd> + <kbd>I</kbd>, then <code class="language-text">/test</code> and finally <kbd>Enter</kbd>.</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/03718092b6ae83d66dbc3f9bb03f008a/5df5d/test.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 55.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB70lEQVR42o2T2ZKaUBCGeYmMC7sLCWcTBEsWRcEAOhljKsm8/6P86YMzk6kkF7n46L+76IU+B4NxhnWyQRAwuI4Dy5xiMnrA6OEDxq+MRhiPx5hMp5gSk8mEuOs3Jve4EQQ+lBLgYg2mYogogdjswNKS2IOvtwi5QMg+wvdMONTUdWyyhK2x7lbHXReG63pYLudIkhWSqMQqzpD3N+y7R5weL8jrM9LigDQvsN5mCFiEIJQIhaJGEqs0B1cr8JDB8zwY+rFYLDDzqJN172pbGhOefY/ZtkO+A8+f0xQ+HBrCpTyd6/kz0j70YDblDgV934dQEut0DRVJRDF1JssFg1xxSMWhtJXhb02W8U8QQ4wNvtZU0B8mLE4Vum8tup9XtE8lukuMqlEoKoHyqAaKoyQrX3yJ4vDqy7d3hgln8zkOdYn+VqP52uHy/IT2esDxesKJilc1R7YXyKu/yf7whwmXesKdQH0psa9jHM8FDl2G7Y69KyQHvd3xAa3/heHTUoMgoFOt0FwbtN97+uwL6luLllZw/tGiv+7QfslQfY7Q9wku5xT7JkLTxuj6FGV9X4fG8GczLKmgogNJyxybPEa2SxHlOaJCX5WIDiYAk8sBoYIBrfkL7B2Gvox6j/oPMacac8AirTFNC5a+Nv/JL9Q8T4bUI1i1AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Using commands to perform an action" title="" src="/static/03718092b6ae83d66dbc3f9bb03f008a/302a4/test.png" srcset="/static/03718092b6ae83d66dbc3f9bb03f008a/01bf6/test.png 270w, /static/03718092b6ae83d66dbc3f9bb03f008a/07484/test.png 540w, /static/03718092b6ae83d66dbc3f9bb03f008a/302a4/test.png 1080w, /static/03718092b6ae83d66dbc3f9bb03f008a/5df5d/test.png 1572w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="use-files-as-context" style="position:relative;"><a href="#use-files-as-context" aria-label="use files as 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>Use files as context</h2> <p>You can use files in your context by using the <code class="language-text">@files</code> tag. Simply type that in the search box and you will get prompted to select a file, or you can type the file name directly. Then type your question and press <kbd>Enter</kbd>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 814px; " > <a class="gatsby-resp-image-link" href="/static/651042de665bf6ed228b76a388626396/a4262/file.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 158.14814814814815%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAgCAYAAAASYli2AAAACXBIWXMAABYlAAAWJQFJUiTwAAAEfUlEQVR42m2W2XbiRhCG9Qg+XgEJAxJoA4FYBAzYYx/b8ULmzm+QuZpcJXn/cyr1ldTE48lFUdXb37X81cLLti8Sj0vJs1Si4VCKopBhoyeTiYxGI4njWMbjsURRJEmS2FyWZTZ2+zjDHm+QLWQwTGQYhXJ9fS1hOJBut3sECsNQBoOBHUAD4sa9Xs/Gbg+2N4xYjOTy8lIBEpnNSpmVM/ED3+ZaVy25uroyabUarXOXF5fmQKaRbTYbSdNU+v2+eKm6zm1sCjq+XAdd6aq0W+0GDGk30pJWu32Uju9LV0EHg1CCbk98PxCvzWKrJcN+T76sKtlVG9ks11IWc5lOkIUUKmO1i+lC8slUcs3beFaYzsaFJNlEPZ1KFJbixZorPIw1D398/y5//fO3/Pjzh3z79rscDm/y8vIsT08P8vj4YPZiPv9VFnNZLvWydCdep9OxXOXRSNbLlSznC1ktVCPLSnWlBxp7pVqjWFaqq6q2EV1brdYKuBePypDcnsafKmgSxRKrjMJEwn5sMhiohGrrfKgRRfHIdDjU+aheY0+vm4gHdyg5SR6EdemNCkqjQCsddINaB432G/snXYsftMWDBoTMIrwbNTkFFI2MRvGRl0g9V++D6FAGgY/mIQuOa4Sf57lJOaeyUwPhIB3BfjTrU12DIScnJ3J6emrnPTbiHQtoPJuVpUz0wCxNZJpC9pms12tN/lLmVlUtnBaIeeYYY3Pe44dWc3zEZnGinuR6WdF4Q8+WehHe4hljwsQmKodhISOA4TILHORWFzYXMIdXAGAz54BdugwQIF8rxYBJbDYDyIvC7a4gpAPbadKFzbmLiwtzysNtFhggvCAOEA9dSmraBEIjcAmCzRpnoB62R8UYcAsbeDFcKISGVNoVFANhnvF2u5VpkwpLjWqjDV4RrgsZUAA5zGUIm4ca4rTJG3NJmslUwQmdcI8hs0h+7O1rqMMhQgYUWsDFuaalyjPJtINWqiuePQ015XVv+GhFoQifiwKIqybA5rHaeFSSX72o0orPm5TAUZwyYlMU3HZlJ4cOEDA2EwXhVmqTO3LFXucMaXJp81zyyYFrIb9pfOe5SwcHmXOc/SwG6B4HKr3f72W321kl8ZDq4ZFVVMes4TEeuks+igEC4r5or6+v8vb2Jg8PvNCPdsH7+7u+1C82fn5+tj10FhG5dv0JEDBIysTZ2ZmF7Ghwfn5+nPuoOQiJXWo+igfLXfvRauTTFYTPI2HXvVy/LO4bzDkK+FGY8wCh0txK7ngA7u/v5ebmxnL29e5e7lSefns2XqZK6KL4j6eu9Zx4hOUqBMfW+gH6okXY72/s8Gq9lcV6I/uvd/Z1i0eRRpJY/+O9+wdxBDwcDuYRwHP96j2+HGS1wbNbub3ZqcdLLciterxW2cjt7VYrXRo4KYGj9pFzgLhOqPzNiLOxFPqRz6dz/bDn6m39FiL8TbGXSSXQfxbuUf0IZoBUpmZ9/Uz5nbZ+yTrNU+Ufu4G1bjf4JWdOKArgRw8hqmsfx6//G38m82f5F50ImtN4ShJhAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Using files as context" title="" src="/static/651042de665bf6ed228b76a388626396/a4262/file.png" srcset="/static/651042de665bf6ed228b76a388626396/01bf6/file.png 270w, /static/651042de665bf6ed228b76a388626396/07484/file.png 540w, /static/651042de665bf6ed228b76a388626396/a4262/file.png 814w" sizes="(max-width: 814px) 100vw, 814px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="understand-errors-in-terminal" style="position:relative;"><a href="#understand-errors-in-terminal" aria-label="understand errors in terminal permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Understand errors in terminal</h2> <p>When you get any errors or issues in your terminal, select the error text and press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>R</kbd> and you will get an explanation:</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/821cb30d4dd42dfbf54bfb70b1814401/2bfae/terminalerror.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 48.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABuElEQVR42mVS7Y6jMAzkHVY0pYWEkITwWaBbtqraql2pf/r+DzRrB3Hau/sxMnHweMZO5LxHVVVwzoVYOh++pVLI85ygoLWGMSbEJZcjy7K/UBQF5TWiz+MRz+cTl8sFp3mGpcKy6eHaAb5pUbUNtHFQRCJlRpD/I5N0r9A0FtFMJO/3G6/XC+fzGZo62bpDM5zQTp9E3sGUJXWnIlL9Gyvhei60QjRNEx6PB263WyAsTAFXkbJ+Qj0QDiOsK/9YZev8D1u01gZwLg8OJKIjWWZ11+sVrNZaA1838N2Icf7C6XKG9TWRUJGSYY6/wcQcV5VRXdcYhgFt24al5HRpfYu6PwZ1VT/C+SoQLkuhZakF/9oPhLzR1c5qyZQe2vqgzDAZbb6wvHmNNN1jv1+QpmnAShYss0KeIyvk9feNxzweMJLtjp6U2u2QCgGZJAEq2SHnHH1vt1vCEhM+EyJPRUzYd91il7ocCnp3iYDeCiJIAgFDig2UiKHiOOTFJsYm/oCghoLuGBHbZNs8XEkK86rE9PWgZ3NH1YxhEVyw3yWYxhPmw51exJ2sZlB2gum+IbVFVtBIcosfkCgcf+5wqSkAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Getting terminal errors explained" title="" src="/static/821cb30d4dd42dfbf54bfb70b1814401/302a4/terminalerror.png" srcset="/static/821cb30d4dd42dfbf54bfb70b1814401/01bf6/terminalerror.png 270w, /static/821cb30d4dd42dfbf54bfb70b1814401/07484/terminalerror.png 540w, /static/821cb30d4dd42dfbf54bfb70b1814401/302a4/terminalerror.png 1080w, /static/821cb30d4dd42dfbf54bfb70b1814401/0d292/terminalerror.png 1620w, /static/821cb30d4dd42dfbf54bfb70b1814401/b3608/terminalerror.png 2160w, /static/821cb30d4dd42dfbf54bfb70b1814401/2bfae/terminalerror.png 3804w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </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>This was another exciting step towards enabling everyone around the world to use AI in their day to day tasks without having to pay any fees or be dependant to any cloud provider. I hope you enjoyed and could get the setup up and running, and stay tuned for more AI content.</p><![CDATA[🔮 fabric, augmenting humans using AI]]>https://yashints.dev/blog/2024/06/01/fabrichttps://yashints.dev/blog/2024/06/01/fabricSat, 01 Jun 2024 00:00:00 GMT<p>If you have worked with <a href="https://openai.com/" target="_blank" rel="nofollow noopener noreferrer">OpenAI</a> or any other <a href="https://en.wikipedia.org/wiki/Generative_artificial_intelligence" target="_blank" rel="nofollow noopener noreferrer">Generative AI</a> model aka <em>LLMs</em>, you would know that writing a good <strong>prompt</strong> is a very key part of how we interact with those models. However, it’s often ignored which most probably means people are not getting the most out of these super capable models.</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>The most important part of interacting with LLMs is writing a good prompt, and that’s why it is important to make sure not only you know how to write a good prompt, but also are aware of what tools are available which might help you do just that. I wrote this post to introduce <a href="https://github.com/danielmiessler/fabric" target="_blank" rel="nofollow noopener noreferrer">fabric</a> to you all since it has changed the way I personally use my local models and I can’t believe how did I not know about it before.</p> <h2 id="introducing-fabric" style="position:relative;"><a href="#introducing-fabric" aria-label="introducing fabric permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Introducing fabric</h2> <p><strong>fabric</strong> is an open source tool which augments humans using AI. I know it sounds a little fancy, but believe me when you get to know its features and usefulness, you would totally be onboard with the definition.</p> <p>In short, fabric is a tool which not only has many patterns (a comprehensive prompt for a specific purpose) already baked in, but also allows you to use them with LLMs like OpenAI or even local LLMs (<a href="/blog/2024/05/28/local-llms/">read my last post on how to install Ollama</a>) if you have them handy. Furthermore, you can add your own patterns if you like to the mix too and contribute back to the community if your pattern deemed useful to others.</p> <p>Enough talking, let’s get it installed and show you some cool features.</p> <h2 id="prerequisites" style="position:relative;"><a href="#prerequisites" aria-label="prerequisites permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prerequisites</h2> <p>You would need a few things installed to be able to seamlessly install fabric. I am using WSL to install it, but you can install it in a <em>linux</em> distro of your choice.</p> <ul> <li><strong>pipx</strong>: fabric uses pipx to install itself, so get it installed by running: <div class="gatsby-code-button-container" data-toaster-id="51675442216674990000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo apt install pipx`, `51675442216674990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> pipx</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> </li> <li><strong>python3-dev</strong>: Since it is using Python extensions, you would need to install the header files: <div class="gatsby-code-button-container" data-toaster-id="49138736706630115000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo apt-get install python3-dev`, `49138736706630115000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> python3-dev</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> </li> <li><strong>ffmpeg</strong>: Fabric depends on this library and <strong>libavcodec-extra</strong> when handling multimedia: <div class="gatsby-code-button-container" data-toaster-id="86824776593957060000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo apt-get install ffmpeg libavcodec-extra`, `86824776593957060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> ffmpeg libavcodec-extra</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> </li> </ul> <h2 id="installing-fabric" style="position:relative;"><a href="#installing-fabric" aria-label="installing fabric permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 fabric</h2> <p>You wouldn’t believe how simple the installation process is. First navigate to a folder where you intend to clone the repository, clone the repo and then navigate into the fabric folder:</p> <div class="gatsby-code-button-container" data-toaster-id="83135264709770700000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`cd /where/you/keep/code # if the path is a mounted drive you might have to run this with sudo git clone https://github.com/danielmiessler/fabric.git cd fabric`, `83135264709770700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">cd</span> /where/you/keep/code <span class="token comment"># if the path is a mounted drive you might have to run this with sudo</span> <span class="token function">git</span> clone https://github.com/danielmiessler/fabric.git <span class="token builtin class-name">cd</span> fabric</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Now use <em>pipx</em> to install fabric:</p> <div class="gatsby-code-button-container" data-toaster-id="76392123523447910000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`pipx install .`, `76392123523447910000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">pipx <span class="token function">install</span> <span class="token builtin class-name">.</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once installed, call the setup function where you have provide four API keys for OpenAI, Claude APIs, Google and YouTube APIs which you can get them from their respective consoles.</p> <div class="gatsby-code-button-container" data-toaster-id="86980674132153600000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`fabric --setup`, `86980674132153600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">fabric <span class="token parameter variable">--setup</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>When you are finished, you need to exit bash and go back in to have access to fabric:</p> <div class="gatsby-code-button-container" data-toaster-id="84884581177546980000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`exit`, `84884581177546980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">exit</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And in your terminal:</p> <div class="gatsby-code-button-container" data-toaster-id="33645144932961178000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`bash`, `33645144932961178000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">bash</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now you can run fabric and see the list of available patterns:</p> <div class="gatsby-code-button-container" data-toaster-id="7337565610330676000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`fabric --list`, `7337565610330676000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">fabric <span class="token parameter variable">--list</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Which should show you the list of available patterns.</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/35df9457c4ff4bceaf77c02c94cf0afe/6edca/fabric-list.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 75.18518518518519%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAABgUlEQVR42p1T2W7CMBDMF/QAUaClIRDClZA4zuE4IQEK5aWq1P//manXhapIVG3yMFpblkezM7tGtXvF2/sHdvsjsryEUPB5gjAR8HwOxlOEsQCLvmoYCcj1Rr2FsGcuxnMfo+kKj9YUo9kKRpiu4SwZJgqOG6LzNEa7N0S7b6Glaut0PqPVs66+6bOCkeQbMEUaJAVkdUDPnOCua35/+In77mW9BiOIcxD8SCKWG5j2Un0wf/3wFwymlLETKc9K9E0HN51Bc0JZ7ZEWO1Cllv1YwlZGN1WpPYyyClyUuk49jmd70ZzQC4X2b8Uz0NllAtbUU8ldJv1vwlhWCMUaND6kMi22WAaJHp/bBl4aWak8zLfax6x8gVT3SBEPRnMMxnOttBYhqSJ1lDZV8pFUEhZ+jIeBXd9Dl6V6dHwu9cbQLFqOB3Oy1CtVJyCD2hOqXVJKZEPHRX/onDbCrJ22Qa3RDHIVTLE9It8cNM7B1CYMklx7R2Oj91p5SRZQKE1m8RMKKaJKvrPzSQAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Getting the list of available patterns from fabric" title="" src="/static/35df9457c4ff4bceaf77c02c94cf0afe/302a4/fabric-list.png" srcset="/static/35df9457c4ff4bceaf77c02c94cf0afe/01bf6/fabric-list.png 270w, /static/35df9457c4ff4bceaf77c02c94cf0afe/07484/fabric-list.png 540w, /static/35df9457c4ff4bceaf77c02c94cf0afe/302a4/fabric-list.png 1080w, /static/35df9457c4ff4bceaf77c02c94cf0afe/6edca/fabric-list.png 1351w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></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> <p>Now let’s explore some cool features that will change they way you use LLMs forever. But first, we need to set our default model to make sure we are not charged by OpenAI or other available online models:</p> <div class="gatsby-code-button-container" data-toaster-id="22542208310267896000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ollama list # replace the name of the model with whatever you have available fabric --setDefaultModel llama3:latest`, `22542208310267896000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ollama list <span class="token comment"># replace the name of the model with whatever you have available</span> fabric <span class="token parameter variable">--setDefaultModel</span> llama3:latest</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Now we’re ready to go. First off, let’s use one of the features which I use almost every day. I have subscribed to many YouTube channels be it tech or not, and many of those post long videos on a daily basis. You can summarise the whole video using one command:</p> <div class="gatsby-code-button-container" data-toaster-id="25596707080494686000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`yt --transcript https://youtube.com/watch?v=uXs-zPc63kM | fabric --stream --pattern extract_wisdom`, `25596707080494686000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">yt <span class="token parameter variable">--transcript</span> https://youtube.com/watch?v<span class="token operator">=</span>uXs-zPc63kM <span class="token operator">|</span> fabric <span class="token parameter variable">--stream</span> <span class="token parameter variable">--pattern</span> extract_wisdom</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>We’re using the <code class="language-text">extract_wisdom</code> pattern here, but you can use any other pattern you want. The API key you provided for YouTube is used here to get the transcript and pass it to the LLM using the pattern you have chosen. Super cool and fast response makes this a really great setup.</p> <p>Let’s try something different:</p> <div class="gatsby-code-button-container" data-toaster-id="62348650753619890000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`echo &quot;An idea that coding is like speaking with rules.&quot; | fabric -sp write_essay`, `62348650753619890000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">echo</span> <span class="token string">"An idea that coding is like speaking with rules."</span> <span class="token operator">|</span> fabric <span class="token parameter variable">-sp</span> write_essay</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Here we’re passing an idea and ask fabric to call our model and ask for an essay. The result will truly amaze you.</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/4e68d6bbc83aa0b72e598ada2b89ab6a/f1f01/fabric-essay.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABm0lEQVR42jWS3XKbMBCFeZLWiTEgQBLi3wa7buOpO81FOrnITN7/QU7PEfHFeiVZnP32rJLb/RXr9Yb1xwum5QLb9LBhhO8mtOMJoZ+RGoddZrE3HlndorA9DlWHwg+owgzjR+Rc73KH5Ik/aRl4sUPOy4eKof1XfqbIY59TyPDDut1E6va4RXdCxbznvaRqRigK28G4Hq6bUYeJZxMLdNwfUao6CUUnSglnjEJkbohitl94NiDJKZRFshA/1Do1DakaUoWY068QZclClkSGWYISc8MKP55Rch0JC5JJLAb3ypZtRb/439biEIUUzXSOAs10QTNfMKwvMfx4QSIKRf4wmz7sCx/b15kKSixXUVph+80vP65wFFWrw/oL3eknTCChPBKNqB5riRl6o6x9DJFRRIKBVO3pGgnn+x+0H+9o7n8RjlckEtJAvqUlnguH72mF3aHGU263dVbz3EOvQS9AQ5B/hs+lalj89hvZ5weWt3/08oxEFAe2JmG1uNFthLJAQ9Mg/LAgpTUKiWrKuYbSLSjZriN13Z/xH0lDGTrscRk5AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="writing an essay based on a prompt via fabric" title="" src="/static/4e68d6bbc83aa0b72e598ada2b89ab6a/302a4/fabric-essay.png" srcset="/static/4e68d6bbc83aa0b72e598ada2b89ab6a/01bf6/fabric-essay.png 270w, /static/4e68d6bbc83aa0b72e598ada2b89ab6a/07484/fabric-essay.png 540w, /static/4e68d6bbc83aa0b72e598ada2b89ab6a/302a4/fabric-essay.png 1080w, /static/4e68d6bbc83aa0b72e598ada2b89ab6a/0d292/fabric-essay.png 1620w, /static/4e68d6bbc83aa0b72e598ada2b89ab6a/b3608/fabric-essay.png 2160w, /static/4e68d6bbc83aa0b72e598ada2b89ab6a/f1f01/fabric-essay.png 2212w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="taking-it-to-next-level" style="position:relative;"><a href="#taking-it-to-next-level" aria-label="taking it to next level permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Taking it to next level</h2> <p>There are two library in macOS called <code class="language-text">pbcopy</code> and <code class="language-text">pbpaste</code> which allow you to copy text from and paste text into your terminal, but at large. Fortunately we can leverage a library which allows us to do exactly that in WSL or any other linux distro called <code class="language-text">xclip</code>. Let’s get it installed and running:</p> <div class="gatsby-code-button-container" data-toaster-id="55998817889630855000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo apt install xclip nano ~/.bashrc`, `55998817889630855000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> xclip <span class="token function">nano</span> ~/.bashrc</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Now paste these two lines at the end of the file:</p> <div class="gatsby-code-button-container" data-toaster-id="66697224717259720000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`alias pbcopy='xclip -selection clipboard' alias pbpaste='xclip -selection clipboard -o'`, `66697224717259720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">alias</span> <span class="token assign-left variable">pbcopy</span><span class="token operator">=</span><span class="token string">'xclip -selection clipboard'</span> <span class="token builtin class-name">alias</span> <span class="token assign-left variable">pbpaste</span><span class="token operator">=</span><span class="token string">'xclip -selection clipboard -o'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Exit nano with <kbd>Ctrl</kbd> + <kbd>X</kbd>, then enter Y and press <kbd>Enter</kbd>. Last we need to refresh our terminal:</p> <div class="gatsby-code-button-container" data-toaster-id="9274365862766420000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`source ~/.bashrc`, `9274365862766420000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">source</span> ~/.bashrc</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>We’re good to go. Navigate to any site which has a long article, I use <a href="https://www.abc.net.au/news/2024-05-30/rba-should-hike-interest-rates-in-june-but-will-it/103909992" target="_blank" rel="nofollow noopener noreferrer">this one talking about interest rates in Australia and what might happen in June</a>. Copy all the text in that page and then type this in your terminal:</p> <div class="gatsby-code-button-container" data-toaster-id="57436933276993176000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`pbpaste | fabric -sp extract_insights`, `57436933276993176000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">pbpaste <span class="token operator">|</span> fabric <span class="token parameter variable">-sp</span> extract_insights</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <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/cb088eba0d396238922477c8812e1fe5/e1190/pbpaste.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 26.666666666666668%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA/UlEQVR42j2P2U7DMBBF8xEIBI3akjhestjOYmdpAlRC/P8fXWYM6sPRjCfj45tsXHa4cUk0PuAiDArZolSE7iCI/F0hLwxOV4W3q0z9WTSJV5q9nCs85wJPpxKZ7iZ0w0osqGpPEgdBtdCWcKianuZ9+iapl+1AswHaBhgfUfsZLd2V3Yi8bJAN84E+7o9Lf1ILYfy/zEPTsiKRbEcYF6EoBEu7cYN2IVVD4ou0yOy4wk0b2n4G9+kcbvAE94aScGr+E0GPGhLUtMuwhGWMiweUjciW7Qv75zfCcqCmZUVpGlpkAafis3ykCylRvN1x3H8Q1g9MxDDvqdppxS9sE5k7BtHZ4AAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="using pbpaste to get an entire article in the terminal and pass it to fabric" title="" src="/static/cb088eba0d396238922477c8812e1fe5/302a4/pbpaste.png" srcset="/static/cb088eba0d396238922477c8812e1fe5/01bf6/pbpaste.png 270w, /static/cb088eba0d396238922477c8812e1fe5/07484/pbpaste.png 540w, /static/cb088eba0d396238922477c8812e1fe5/302a4/pbpaste.png 1080w, /static/cb088eba0d396238922477c8812e1fe5/0d292/pbpaste.png 1620w, /static/cb088eba0d396238922477c8812e1fe5/b3608/pbpaste.png 2160w, /static/cb088eba0d396238922477c8812e1fe5/e1190/pbpaste.png 2203w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="what-next" style="position:relative;"><a href="#what-next" aria-label="what 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>What next</h2> <p>There are many cool features you might be interested in, but I just highlight two more which I think are the most practical. Setting a <em>context</em>, and adding <em>custom patters</em>. Setting a context is done by adding a markdown file called <code class="language-text">context.md</code> in the <code class="language-text">./config/fabric/</code> directory to add context to your pattern. This could be anything you like, for example you might add your goals or the essence of your existence and why you do what you do day to day.</p> <p>From the custom patterns perspective you can always add your custom patterns which you do not want to upload to fabric in the <code class="language-text">~/.config/custom-fabric-patterns</code> directory. However, whenever you want to use them with fabric you need to move them into the <code class="language-text">~/.config/fabric/patterns</code> directory. Just beware that any time you update fabric, the folder get updated and every custom pattern will be deleted, so you need to copy them from the custom folder before using them.</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 you now have a good cause to go setup fabric and spend a little bit more time with your local LLMs and get better at writing prompts and extracting information or getting what you need faster and more effectively. Stay tuned for more AI content 👋🏽.</p><![CDATA[🥇 Run your generative AI model locally 🥇]]>https://yashints.dev/blog/2024/05/28/local-llmshttps://yashints.dev/blog/2024/05/28/local-llmsTue, 28 May 2024 00:00:00 GMT<p>Many learners ask me how they can get access to <a href="https://azure.microsoft.com/en-au/products/ai-services/openai-service" target="_blank" rel="nofollow noopener noreferrer">Azure OpenAI</a> and <a href="https://en.wikipedia.org/wiki/Generative_artificial_intelligence" target="_blank" rel="nofollow noopener noreferrer">Generative AI</a> since they don’t have access to an enabled subscription. I knew there are open source tools which allow people to work with these models, but I never had a use case to go and try this out.</p> <!--more--> <h2 id="-the-need" style="position:relative;"><a href="#-the-need" aria-label=" the need permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 need</h2> <p>I have a kid in high school and she wanted to give <a href="https://chat.openai.com/" target="_blank" rel="nofollow noopener noreferrer">ChatGPT</a> a try for a task she was working on, I was afraid she would use it to get the answer right away instead of figuring out how to solve the problem. This forced me to look into how I can have a better control over how she could use LLMs without “cheating”.</p> <p>That’s when I stumbled upon <a href="https://ollama.com/" target="_blank" rel="nofollow noopener noreferrer">Ollama</a>, a great cross-platform, open source project which happens to be the easiest way you can get an engine running with many available models. Although their Windows version is experimental and in development, you can install it on <a href="https://learn.microsoft.com/en-us/windows/wsl/about" target="_blank" rel="nofollow noopener noreferrer">Windows Subsystem for Linux aka WSL</a>.</p> <h2 id="️-prerequisites" style="position:relative;"><a href="#%EF%B8%8F-prerequisites" aria-label="️ prerequisites permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>🖥️ Prerequisites</h2> <p>Before we start our process, you need to know that you will need a system which has a decent GPU since running AI locally demands that. This could even be your laptop which has a graphic card, or even better your gaming PC with that crazy spec you spent that much money on.</p> <p>You most likely need docker installed as well since I will use it to run the web UI, but this is not mandatory.</p> <h2 id="️-installation" style="position:relative;"><a href="#%EF%B8%8F-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>Of course you need WSL enabled and a distro installed, but don’t worry as soon as you enable <strong>Virtual Machine Platform</strong> and <strong>Windows Subsystem for Linux</strong> in your windows features, all it takes is a few commands:</p> <div class="gatsby-code-button-container" data-toaster-id="75297141955843490000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`wsl -- install -d ubuntu wsl --update wsl --set-default-version 2`, `75297141955843490000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">wsl -- <span class="token function">install</span> <span class="token parameter variable">-d</span> ubuntu wsl <span class="token parameter variable">--update</span> wsl --set-default-version <span class="token number">2</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Before we install any packages, it’s always a good idea to update the current ones, this becomes more important if you have had WSL enabled for a while.</p> <div class="gatsby-code-button-container" data-toaster-id="35780843537718910000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo apt update && sudo apt upgrade`, `35780843537718910000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt</span> update <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">apt</span> upgrade</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now it’s time to install Ollama:</p> <div class="gatsby-code-button-container" data-toaster-id="80519799398246300000" data-toaster-class="gatsby-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 -fsSL https://ollama.com/install.sh | sh`, `80519799398246300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">-fsSL</span> https://ollama.com/install.sh <span class="token operator">|</span> <span class="token function">sh</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This will take a while to finish, so get a coffee and be patient. Once it is installed it will start the Ollama engine and shows you it’s running. To test it you can open a browser and navigate to <code class="language-text">http://localhost:11434</code> which should show you it’s running:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 487px; " > <a class="gatsby-resp-image-link" href="/static/a1ef1bb866740823f28c1122cc093f34/7b439/ollama-running.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 34.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAABa0lEQVR42o2OWU/bUBCF/UwdZ6NCJSAUoqQxDkGNs1wHsUbgBMeBbDSYkAXMvrV9qvjzH9dUrcRD1T58OnPmjDRHsepHCLtFZa/5i30Xc7eB2G9Rqh1gbtcxdxoUtmwK27b0NkWZF+WutHtAuea8Q+ldPtI8u6LuXeBIbZz6TL/9pNYf0Z7c0B5fYXc8umc+naGPOxixd/SVes9jy2ljyRJVWeI3yvHtDw7P72mOb2hN73And0y+v2B7Pv3LJ/r+A+7JlOH1MwN5153IB70hrjel1h6w4XTYbHb/oOiFMnqhQqBG0Xoj8Dmpn9eKZNZMsl9K6JIVeRMQZIYpyJUsVsvVdyipZJJsJo2uZ1mY/8RiIsHcx1mSS0tk0mlSqWUWFxJoqko4FHpDC6l/Rcnn81REBbvhkMutYBgGy/KJEAJRXUdYAsuyiEajxOPxf6JomkZIfv0wM0Mwh8MakUgEVe5U2SrIAh+Lxf6LV8no4FvZ7msgAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Ollama running in WSL" title="" src="/static/a1ef1bb866740823f28c1122cc093f34/7b439/ollama-running.png" srcset="/static/a1ef1bb866740823f28c1122cc093f34/01bf6/ollama-running.png 270w, /static/a1ef1bb866740823f28c1122cc093f34/7b439/ollama-running.png 487w" sizes="(max-width: 487px) 100vw, 487px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Now you can pull down a model and interact with it:</p> <div class="gatsby-code-button-container" data-toaster-id="42559587643281450000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ollama run llama3`, `42559587643281450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ollama run llama3</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once it’s done, it will wait for you to enter your prompt:</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/898b49ba227947039dc7028e714f2526/b4904/ollama-waiting.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 5.185185185185186%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAYAAADeko4lAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAU0lEQVR42h3DMQqAIBiA0S7RUg0WIhGmqZQODeX+n6Kh+5/gC3rwGhGh3pVSCjlnQoiklPDeY63FOUc8ds554+0vnsUha0vsBsZpQmv9N8aglOIDD9wfYloWc+AAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Ollama waiting for a prompt" title="" src="/static/898b49ba227947039dc7028e714f2526/302a4/ollama-waiting.png" srcset="/static/898b49ba227947039dc7028e714f2526/01bf6/ollama-waiting.png 270w, /static/898b49ba227947039dc7028e714f2526/07484/ollama-waiting.png 540w, /static/898b49ba227947039dc7028e714f2526/302a4/ollama-waiting.png 1080w, /static/898b49ba227947039dc7028e714f2526/0d292/ollama-waiting.png 1620w, /static/898b49ba227947039dc7028e714f2526/b4904/ollama-waiting.png 1768w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>And upon <kbd>Enter<kbd> it shows you the response:</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/508037ed321b1d8cdc8a23680350a727/54421/pentagons-area.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 32.96296296296297%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAz0lEQVR42nWRSxKEIAxEuYXAKF9F3Ize/3IZOiCl1rjoSgzy0iFi3790HEdXSomC87QURe/I2SLnKARP1lpSSpGU8lUixkjLstA8z4Qcl40xZMplADhvwnc9r3Xk0FlHFOu6Us6ZEMdxfHXwr47aUwzcto1yERwCOk0Td+PO3rMb1K8ufanjv2EY7iNjXEBDCDw6IgT42VWquyOtNQs5gFeowBLWVICxgAokNgEKF6f62zaXz3fFBAAzMM51MXUUx7C62dDBWn+6s6c+7QwOf/ssvVdPUOA3AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Ollama answering to prompts using Llama3 model" title="" src="/static/508037ed321b1d8cdc8a23680350a727/302a4/pentagons-area.png" srcset="/static/508037ed321b1d8cdc8a23680350a727/01bf6/pentagons-area.png 270w, /static/508037ed321b1d8cdc8a23680350a727/07484/pentagons-area.png 540w, /static/508037ed321b1d8cdc8a23680350a727/302a4/pentagons-area.png 1080w, /static/508037ed321b1d8cdc8a23680350a727/0d292/pentagons-area.png 1620w, /static/508037ed321b1d8cdc8a23680350a727/b3608/pentagons-area.png 2160w, /static/508037ed321b1d8cdc8a23680350a727/54421/pentagons-area.png 3009w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="running-as-service" style="position:relative;"><a href="#running-as-service" aria-label="running as service permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Running as service</h2> <p>Another issue I was facing now was that I didn’t want to keep my terminal running, so a better way would be to run Ollama as a service. Since WSL does not use the <code class="language-text">systemd</code>, you can’t run services by default. So we have to first enable it:</p> <div class="gatsby-code-button-container" data-toaster-id="17593283199507814000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`nano /etc/wsl.conf`, `17593283199507814000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">nano</span> /etc/wsl.conf</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Then enter these lines anywhere in the file:</p> <div class="gatsby-code-button-container" data-toaster-id="14650802523029550000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[boot] systemd=true`, `14650802523029550000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token punctuation">[</span>boot<span class="token punctuation">]</span> <span class="token assign-left variable">systemd</span><span class="token operator">=</span>true</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>And finally exit the nano with <kbd>Ctrl</kbd> + <kbd>X</kbd>, select Y to save your changes. Now we have to restart our WSL. Exit our of WSL by typing exit, and then run:</p> <div class="gatsby-code-button-container" data-toaster-id="72017630228423690000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`wsl --shutdown wsl -l wsl run Ubuntu-22.04`, `72017630228423690000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">wsl <span class="token parameter variable">--shutdown</span> wsl <span class="token parameter variable">-l</span> wsl run Ubuntu-22.04</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> Replace the name of the distro with whatever you have which is shown from the list command.</div></div> <p>And finally start the service:</p> <div class="gatsby-code-button-container" data-toaster-id="53763259411597100000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo systemctl enable ollama sudo systemctl start ollama`, `53763259411597100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> ollama <span class="token function">sudo</span> systemctl start ollama</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <h2 id="-user-interface" style="position:relative;"><a href="#-user-interface" aria-label=" user interface permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>📱 User interface</h2> <p>This is great, but my kiddo can’t use my terminal to interact with these models. So I went on a hunt to find a user interface which can use Ollama, and not long after I found <a href="https://openwebui.com/" target="_blank" rel="nofollow noopener noreferrer">Open WebUI</a> which allows you to leverage Ollama and interact with it via a user friendly UI. Plus it has the benefit of persisting your conversation history.</p> <p>You can install it directly on the WSL, but I’d much prefer to use the docker version of it, but first you need to enable the WSL integration on the Docker Desktop app:</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/a2008c9803a34cfc3f3665c7f0630bc6/99375/wsl-docker.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 68.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAABj0lEQVR42pWT6W7jMBCD/Q7bnLYlH5Is+U7SAn3/F+NyxmmALbZo8uODZDgmSM4kW94/0cYBf44FdmfzD2+nUs99bp8m8/2EblzRdIMKC5VPqEkbR5zKGrtXBE13o+CiRAqHYSa8TytcGl9yp4JVN6OJE2o6bOKCOowwbSARR7p7WdC6COsSY/bImx6lo3BIrKB/ub/NYbphWD/Upe9n+DThZBod0oEOD4VQPS94rrzGNXRahZ6R5b45zesAeS88K5qdbQvrt8iWlH7G0UYcTGBk+1ih/beV2v/n3OcGWdkETvjCuAvXhCs0XXXCQk3HJ9PeaZTjF+W3O5F6MhO4KhR07K4lsoM5I2pc6/SDhyiftwqcvnvc78hvs9JN6Jd3pPmG8fLBHVw1vnRZCemCsk0oVKTB7v7v+YnsUFgOZVR3EtlzqR3jyykLLnUImmK40oXTrn7+p3C6+oF+vKrDyB5F/NxOyIl0s8s55WLr6ZcpO+7gTJfT/Rwfz1Ugeo4omg5F7RXptyC5Pm9dfwn+BWwVgBd9ZWaVAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Enabling WSL integration in Docker Desktop" title="" src="/static/a2008c9803a34cfc3f3665c7f0630bc6/302a4/wsl-docker.png" srcset="/static/a2008c9803a34cfc3f3665c7f0630bc6/01bf6/wsl-docker.png 270w, /static/a2008c9803a34cfc3f3665c7f0630bc6/07484/wsl-docker.png 540w, /static/a2008c9803a34cfc3f3665c7f0630bc6/302a4/wsl-docker.png 1080w, /static/a2008c9803a34cfc3f3665c7f0630bc6/99375/wsl-docker.png 1525w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Once you have that done, simply run the docker command:</p> <div class="gatsby-code-button-container" data-toaster-id="6781245797722457000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`docker run -d -p 3005:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main`, `6781245797722457000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">-p</span> <span class="token number">3005</span>:8080 --add-host<span class="token operator">=</span>host.docker.internal:host-gateway <span class="token parameter variable">-v</span> open-webui:/app/backend/data <span class="token parameter variable">--name</span> open-webui <span class="token parameter variable">--restart</span> always ghcr.io/open-webui/open-webui:main</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Note I changed the default port to 3005 since I have a few other apps running on port 3000 in development. Once the container is up and running all you need to do is to open a browser and navigate to <code class="language-text">http://localhost:3005</code>:</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/368ee4ee03bfeba427f8f1cea9a080e0/32ac3/openwebuilogin.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 78.51851851851852%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAACB0lEQVR42oVU2W7iQBBE4r7MbQMLRmAMxg4iCogshwDBAwjxwv9/TGWqlSHGm00eStMz7qme6sOxYrEIDcMwkMlkEI/HkUwmxU6lUmJrpNNp+Z5IJGSfz+cR5oiFybLZLGazGa7XK7bbLabTKVarFTabDQ6Hg6zL5RL3+x3n8xmXywWDwQC5XE7ufxEWCnLI6I7j4Ha7YbfbYTweC8FiscB+vxcwyOl0wvF4lCC2bT8TFhRZpVJBz+6h2+3KKymHUmlzDcvWKdGSSVb8JHsQlstlBEEAb+LBKJVkT5SUzWBEtVoVhG2irPYlRVgKSyZprVbDaDSGp2ROJhOR66u12Wz+CMs0MZwv0O71UFAFiumC1Ot1cTCVQ7vVQotQe57/Bkv51tT6lMO3tzn+vr9j9voqcrMqV8xPtC2+Q175Fj79Hm1jWib6/YFUrdPtSIFsu4tOpwPLstBoNL4FX/hHdUZDqWG3PAh5iXlj24xGI7iuK7mk3W63v3Km/MJgivrBC5oq8BMh8xiFPmdatHRWPgpDfTeik8KnMxplcNVg9R1niMAPpFfDfhrip4uiCfkhLIOgTcIXGcG1GjNHEdZghoLqO7z/zyxrsOokksYtV6B7ld/0q3TjR1MUi7YALzKi53lwh65M0JAF8n34/kSKtVqv1XzPVa82//+3iZLSUSO654zr8+jdD0cPkQWTUrV7AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Open WebUI login page" title="" src="/static/368ee4ee03bfeba427f8f1cea9a080e0/302a4/openwebuilogin.png" srcset="/static/368ee4ee03bfeba427f8f1cea9a080e0/01bf6/openwebuilogin.png 270w, /static/368ee4ee03bfeba427f8f1cea9a080e0/07484/openwebuilogin.png 540w, /static/368ee4ee03bfeba427f8f1cea9a080e0/302a4/openwebuilogin.png 1080w, /static/368ee4ee03bfeba427f8f1cea9a080e0/32ac3/openwebuilogin.png 1249w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Click on sign up and add your user, don’t worry the password is only stored locally inside the docker container volume. Once you signed up, you will need to add the Ollama address in the settings:</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/26b12b6d378269593fe0ceae46f386af/e1190/openwebuiollama.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 70%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAABR0lEQVR42q2TyW6DQBBE5wsidrOJzSwGjEEWueYUyYdw5P9/pUK1ReQslrCcQ8FAd9e8bgZlmiZ834dt2+CaMgxDtD5vla7rUEEQoO97pGkqpq7rwvM82YTrraLPbreDYuHxeES23yMMQwnkeY6iKCThKvdm/V2EiOMYwzBA0zSopmkwzzM+pgmXywXjOKKqKvB9UZayu+M4UnyPjh0RxLIsKG8h7E8naZkBisQ0Pp/PEuu6DofDQXKyLPsldsaupGVeSJQkieCThoVMoBjrTt11LEvxOt9brYSs/zIsl/Y4i7W9W63ka/s/xRzexZCJNCQ2C+4Nf4toqmhS1w2iKPqT7mFDzqBtWyH8N8O6rp8m5OhkhnKwl2PxDKFjOzBfNJi6AUWTZz6Is1CFWYzX+R1Rm0Pxh+YJp4j8qCzTgheHGKY3BGWCT95vbgT39NUgAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Adding Ollama URL in the Open WebUI settings" title="" src="/static/26b12b6d378269593fe0ceae46f386af/302a4/openwebuiollama.png" srcset="/static/26b12b6d378269593fe0ceae46f386af/01bf6/openwebuiollama.png 270w, /static/26b12b6d378269593fe0ceae46f386af/07484/openwebuiollama.png 540w, /static/26b12b6d378269593fe0ceae46f386af/302a4/openwebuiollama.png 1080w, /static/26b12b6d378269593fe0ceae46f386af/0d292/openwebuiollama.png 1620w, /static/26b12b6d378269593fe0ceae46f386af/b3608/openwebuiollama.png 2160w, /static/26b12b6d378269593fe0ceae46f386af/e1190/openwebuiollama.png 2203w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Click <strong>Save</strong> and you’re ready to select a model and start chatting.</p> <h2 id="-custom-model" style="position:relative;"><a href="#-custom-model" aria-label=" custom model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>🤖 Custom model</h2> <p>That got me through the initial setup and everything was great, but I still had the problem of how to prevent the model to give direct answers to my kid. Fortunately Open WebUI has the ability to create custom model files which basically allows you to set a system message for an existing model. This is exactly what I needed.</p> <p>Navigate to <strong>Workspace</strong> and select create a new model file, I named it Debra, and added the following custom prompt:</p> <div class="gatsby-code-button-container" data-toaster-id="354177881345041340" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`FROM llama3 PARAMETER temperature 0 SYSTEM &quot;&quot;&quot; You are an AI assistant designed to help my daughter which is in high school learn and solve problems. You will guide her through the process of finding solutions, but you won’t provide direct answers. This is to ensure that she is actively learning and understanding the concepts. Remember, the goal is not just to get the right answer, but to understand how to arrive at that answer. I want her on this journey of learning together in a safe and supportive environment. &quot;&quot;&quot;`, `354177881345041340`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="txt"><pre style="counter-reset: linenumber NaN" class="language-txt line-numbers"><code class="language-txt">FROM llama3 PARAMETER temperature 0 SYSTEM """ You are an AI assistant designed to help my daughter which is in high school learn and solve problems. You will guide her through the process of finding solutions, but you won’t provide direct answers. This is to ensure that she is actively learning and understanding the concepts. Remember, the goal is not just to get the right answer, but to understand how to arrive at that answer. I want her on this journey of learning together in a safe and supportive environment. """</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I also checked the assistant and education boxes and saved my model.</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/66f56828465d28441d6c66df1c46b7f1/87629/debra.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 73.33333333333334%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAABjElEQVR42n2TWZKCYAyEOYTivoMbKAzulve/VsYvVlMMAz50hYT8WTvBarWyoihsMBhYv9//h16vZ6PRyPI8t9Pp5L6TycTtTb4BgeI4tuFw6EHbMJ1ObblcenAeN/lgD+bzuWVZZtvt1sIw9Cx1VO1NXfypkIxpmtrxeLT9fm+73c6SJPFvkoDD4WBRFLVWBujQK1wsFna/3w2JgR9NUAVtKCsk0Pl8ttls5g+puArZxuNxKetgSfiVLTPDy+XigZG3280lW0XSAf/w06blj45MktRbD0QJPVLQ6/XqEjweD9dlw0ffyDzP3vh5zz2xgHKpiEdAGUnwfD7LClkUnGU50AeJDuUYVxTF78VmHx6CKj3aKMH/brfrUkDvdDoG/UgQEB3K0LauoM7Hb9wTPksJPzNcr9e22WycgwAd0A6t4fPtinRJvhQqYnvQh/IxqhWgdmlLOqj7lDzkEl6vlw+f4DhwOSyIa+EhY0EnsWZJJ6IV7WpMHpBt8lPzY4tqV2eFztAVEF9tujrvX6yonnZe2dFXAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Adding a custom model file in Open WebUI" title="" src="/static/66f56828465d28441d6c66df1c46b7f1/302a4/debra.png" srcset="/static/66f56828465d28441d6c66df1c46b7f1/01bf6/debra.png 270w, /static/66f56828465d28441d6c66df1c46b7f1/07484/debra.png 540w, /static/66f56828465d28441d6c66df1c46b7f1/302a4/debra.png 1080w, /static/66f56828465d28441d6c66df1c46b7f1/0d292/debra.png 1620w, /static/66f56828465d28441d6c66df1c46b7f1/87629/debra.png 2076w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>And last we need to make sure her user can only use this model and can’t delete their chat history which can be done in the admin settings:</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/c6063cefe87ddb1f2b5ddef872c725b3/b5c8e/lockuserdown.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 52.222222222222214%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABIklEQVR42pVSSW6EQBDjCUmAZh32HYFGMHMhpwiJYyR+kP9/wqkqCZREMNEcTNFN22UXrfmXC5IkQZGnUk3ThK7rO3j9HwzDgGVZUjXP91AUBYmlCKNIPlyoSRiGCIIAjuPAtu1T8HmlFBx656oxeRgGlGWBiEQiEm3bVvb6vt9JR2AB3/eR57nw2K1W1zXWdcWyLJjnGeM4ijOOz5WJj9yxIKfhKoIcqSzLvQOvb7c7pmlC13Xi4szh5nLjKUWCPEje/EmsqkoiV9QojmNxe4Ysy5CmqcxdHPLjb1fP8yhGINV13VNwzKZp0dDMKxqd/JQjwS3G5vwRZJ7EMV/omr2+HQs+A2XSlQnI6ccdXh79nuHTsCiJbsBNArx/fSK6VvgG5KMIFIS+eBgAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Locking user down to a custom model in Open WebUI" title="" src="/static/c6063cefe87ddb1f2b5ddef872c725b3/302a4/lockuserdown.png" srcset="/static/c6063cefe87ddb1f2b5ddef872c725b3/01bf6/lockuserdown.png 270w, /static/c6063cefe87ddb1f2b5ddef872c725b3/07484/lockuserdown.png 540w, /static/c6063cefe87ddb1f2b5ddef872c725b3/302a4/lockuserdown.png 1080w, /static/c6063cefe87ddb1f2b5ddef872c725b3/0d292/lockuserdown.png 1620w, /static/c6063cefe87ddb1f2b5ddef872c725b3/b3608/lockuserdown.png 2160w, /static/c6063cefe87ddb1f2b5ddef872c725b3/b5c8e/lockuserdown.png 2194w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>And we’re done. This gave my daughter a perfect tool which she can use with her homework without me worrying about how she uses AI for education purposes.</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>I hope you have enjoyed this guide and could setup your local LLM and use it to increase your productivity and others around you. Remember there are many more models you can leverage including CodeGemma and Phi3 from Microsoft. And last, you can use this with Semantic Kernel which is even cooler since I just finished my series on it.</p><![CDATA[Semantic kernel series - Last part - Planners]]>https://yashints.dev/blog/2024/05/27/semantic-kernel-plannershttps://yashints.dev/blog/2024/05/27/semantic-kernel-plannersMon, 27 May 2024 00:00:00 GMT<p>In my previous posts, I introduced you to foundational concepts of <a href="https://learn.microsoft.com/en-us/semantic-kernel/overview/" target="_blank" rel="nofollow noopener noreferrer">Semantic Kernel</a>, offering a glimpse into its potential. Then I showed you how to leverage plugins to communicate to LLMs, and as promised in this part we would review planners and native function plugins to show <em>Semantic Kernel’s</em> full potential.</p> <!--more--> <p>Semantic Kernel Series:</p> <p>✔️ Part one: <a href="/blog/2024/04/30/semantic-kernel">Intro</a> <br/> ✔️ Part two: <a href="/blog/2024/05/13/semantic-kernel-plugins">Plugins</a> <br/> ✔️ Part three: <a href="/blog/2024/05/27/semantic-kernel-planners/">Planners and Native Function plugins</a></p> <p><a href="https://github.com/yashints/semantic-kernel-devops" target="_blank" rel="nofollow noopener noreferrer">You can find the code on my GitHub repository here</a>.</p> <p>In out last two posts we successfully created some prompts for Azure DevOps and GitHub Action workflows and called Azure OpenAI to generate the YAML files and return the result. However, the result had multiple files separated by a special separator and that gives us a great opportunity to get into planners and native function plugins.</p> <h2 id="native-function-plugins" style="position:relative;"><a href="#native-function-plugins" aria-label="native function plugins permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Native function plugins</h2> <p>Previously we learnt how to create a plugin from prompt directory which allowed us to invoke one based on user input to get the desired results. But you don’t always have to use the text based approach, any function can become a plugin if you use a special decorator from the Semantic Kernel library.</p> <p>The result we got from our Azure OpenAI model had multiple YAML files separated by a series of characters. Let’s create a plugin which gets that output and creates one file per workflow in a given directory. All we need is to use the <code class="language-text">KernelFunction</code> attribute like following:</p> <div class="gatsby-code-button-container" data-toaster-id="26004689446923334000" data-toaster-class="gatsby-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 Microsoft.SemanticKernel; using System.ComponentModel; class ExtrcatPipelineFromOutput { [KernelFunction, Description(@&quot;Saves a pipeline to a file. The pipeline is a YAML file.&quot;)] public static bool Extract(string modelOutPut, string separator, string path) { Console.WriteLine(modelOutPut); try { var chunks = modelOutPut.Split(separator); for (int i = 0; i < chunks.Length; i++) { if (chunks[i].IndexOf(&quot;FILE: &quot;) >= 0) { var fileName = chunks[i].Split(&quot;FILE: &quot;)[1].TrimEnd('\r', '\n'); SaveFile.SaveContentToFile(chunks[i + 1], Path.Combine(path, fileName)); i++; } } return true; } catch (Exception e) { Console.WriteLine(\$&quot;Error saving the pipeline: {e.Message}&quot;); return false; } } }`, `26004689446923334000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>SemanticKernel</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>ComponentModel</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">ExtrcatPipelineFromOutput</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">KernelFunction</span><span class="token punctuation">,</span> <span class="token class-name">Description</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">@"Saves a pipeline to a file. The pipeline is a YAML file."</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">bool</span></span> <span class="token function">Extract</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span></span> modelOutPut<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> separator<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> path<span class="token punctuation">)</span> <span class="token punctuation">{</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>modelOutPut<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword">var</span></span> chunks <span class="token operator">=</span> modelOutPut<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span>separator<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></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> chunks<span class="token punctuation">.</span>Length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>chunks<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">IndexOf</span><span class="token punctuation">(</span><span class="token string">"FILE: "</span><span class="token punctuation">)</span> <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword">var</span></span> fileName <span class="token operator">=</span> chunks<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token string">"FILE: "</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 punctuation">.</span><span class="token function">TrimEnd</span><span class="token punctuation">(</span><span class="token char">'\r'</span><span class="token punctuation">,</span> <span class="token char">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> SaveFile<span class="token punctuation">.</span><span class="token function">SaveContentToFile</span><span class="token punctuation">(</span>chunks<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> Path<span class="token punctuation">.</span><span class="token function">Combine</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> fileName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token 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">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"Error saving the pipeline: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">e<span class="token punctuation">.</span>Message</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 keyword">return</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It’s that easy to create a kernel function which then can be included in a plan by the kernel. Don’t worry about the <code class="language-text">SaveFile</code> class for now, that just writes the content into a file in given path. You can look up the source for that in the GitHub repository.</p> <h2 id="planner" style="position:relative;"><a href="#planner" aria-label="planner permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Planner</h2> <p>Now that we have our function ready, let’s go ahead and create our planner. You might be asking what is a planner anyway, which I will answer nothing special. It’s a function which takes user’s ask and returns a plan created using AI and any plugins or kernel functions which are registered to accomplish the ask.</p> <p>There are two types of planners you can use at the time of writing this post (this is in preview so anything can happen):</p> <ul> <li><strong>HandlebarsPlanner</strong>: It’s a sequential planner which is using the <a href="https://handlebarsjs.com/guide/" target="_blank" rel="nofollow noopener noreferrer">Handlebars’ syntax</a> to generate a plan using a single call to LLMs. This has multiple benefits such as the ability to inspect a plan before execution or the ability to save it and load it later to save costs. In addition to those, since it’s using Handlebars it can have <strong>loops</strong> and <strong>conditions</strong> in the plan as well.</li> <li><strong>FunctionCallingStepwisePlanner</strong>: This one has the ability to use the ReAct model which allows the AI to make a function call, reason over it and make another call if necessary.</li> </ul> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> In addition to this, the feature is also baked into the model and is called automatic function calling which does not require a planner at all, more on this at the end.</div></div> <h3 id="creating-the-planner" style="position:relative;"><a href="#creating-the-planner" aria-label="creating the planner permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 planner</h3> <p>Let’s start by creating our planner and see how it will create a plan. We need a few things before we start:</p> <ul> <li>The directory which we need to save the pipelines into.</li> <li>The directory which we intend to save our plan into.</li> <li>The function which is going to be called (Azure DevOps or GitHub Actions).</li> <li>Adding the native function to our kernel as plugin.</li> <li>And finally the separator since our native function requires that to extract the pipelines from the output.</li> </ul> <p>First we can ready our directories from the <code class="language-text">appsettings.json</code> file:</p> <div class="gatsby-code-button-container" data-toaster-id="26869464626790363000" data-toaster-class="gatsby-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 planTemplatePath = Configuration!.GetValue<string>(&quot;PlanPath&quot;)!; var pipelineDir = Configuration!.GetValue<string>(&quot;PipelineDir&quot;)!;`, `26869464626790363000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> planTemplatePath <span class="token operator">=</span> Configuration<span class="token operator">!</span><span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetValue</span><span class="token generic class-name"><span class="token punctuation">&lt;</span><span class="token keyword">string</span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token string">"PlanPath"</span><span class="token punctuation">)</span><span class="token operator">!</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> pipelineDir <span class="token operator">=</span> Configuration<span class="token operator">!</span><span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetValue</span><span class="token generic class-name"><span class="token punctuation">&lt;</span><span class="token keyword">string</span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token string">"PipelineDir"</span><span class="token punctuation">)</span><span class="token operator">!</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Next let’s add our function to our kernel:</p> <div class="gatsby-code-button-container" data-toaster-id="43305878738409185000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`kernel.ImportPluginFromType<ExtrcatPipelineFromOutput>();`, `43305878738409185000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp">kernel<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">ImportPluginFromType</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ExtrcatPipelineFromOutput<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Since our planner will have to pass parameters to prompts and plugins, we need to create a <code class="language-text">KernelArguments</code> object:</p> <div class="gatsby-code-button-container" data-toaster-id="55053790234845630000" data-toaster-class="gatsby-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 initialArguments = new KernelArguments() { { &quot;input&quot;, description }, { &quot;path&quot;, pipelineDir }, { &quot;function&quot;, function }, { &quot;separator&quot;, kernelSettings.Separator } };`, `55053790234845630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> initialArguments <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">KernelArguments</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> <span class="token string">"input"</span><span class="token punctuation">,</span> description <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"path"</span><span class="token punctuation">,</span> pipelineDir <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"function"</span><span class="token punctuation">,</span> function <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"separator"</span><span class="token punctuation">,</span> kernelSettings<span class="token punctuation">.</span>Separator <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Next we will create our planner and ask:</p> <div class="gatsby-code-button-container" data-toaster-id="56409185485402900000" data-toaster-class="gatsby-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 planner = new HandlebarsPlanner(new HandlebarsPlannerOptions() { AllowLoops = true }); string ask = @\$&quot;Given the provided function use the proper prompt to generate the output with provided input, then save them in the provided directory \${pipelineDir}&quot;;`, `56409185485402900000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> planner <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">HandlebarsPlanner</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">HandlebarsPlannerOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> AllowLoops <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 class-name"><span class="token keyword">string</span></span> ask <span class="token operator">=</span> <span class="token interpolation-string"><span class="token string">@$"Given the provided function use the proper prompt to generate the output with provided input, then save them in the provided directory $</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">pipelineDir</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>As for our plan, and to save some cost, we can check if our plan is previously created or not, if it is, we will load it from a file, if not we will create it and then save it to the file:</p> <div class="gatsby-code-button-container" data-toaster-id="57438570986165050000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`string planTemplate = &quot;&quot;; HandlebarsPlan plan; if (File.Exists(planTemplatePath)) { planTemplate = await File.ReadAllTextAsync(planTemplatePath); plan = new HandlebarsPlan(planTemplate); } else { plan = await planner.CreatePlanAsync(kernel, ask, initialArguments); Console.WriteLine(plan.ToString()); SaveFile.SaveContentToFile(plan.ToString(), planTemplatePath); }`, `57438570986165050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">string</span></span> planTemplate <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span> <span class="token class-name">HandlebarsPlan</span> plan<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>File<span class="token punctuation">.</span><span class="token function">Exists</span><span class="token punctuation">(</span>planTemplatePath<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> planTemplate <span class="token operator">=</span> <span class="token keyword">await</span> File<span class="token punctuation">.</span><span class="token function">ReadAllTextAsync</span><span class="token punctuation">(</span>planTemplatePath<span class="token punctuation">)</span><span class="token punctuation">;</span> plan <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">HandlebarsPlan</span><span class="token punctuation">(</span>planTemplate<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> plan <span class="token operator">=</span> <span class="token keyword">await</span> planner<span class="token punctuation">.</span><span class="token function">CreatePlanAsync</span><span class="token punctuation">(</span>kernel<span class="token punctuation">,</span> ask<span class="token punctuation">,</span> initialArguments<span class="token punctuation">)</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>plan<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> SaveFile<span class="token punctuation">.</span><span class="token function">SaveContentToFile</span><span class="token punctuation">(</span>plan<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> planTemplatePath<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If we print our plan, it might look like this:</p> <div class="gatsby-code-button-container" data-toaster-id="67115553128402340000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{{!-- Step 1: Call the chosen function with input and assign the result to a new variable &quot;result&quot; --}} {{set 'result' (DevOps-GitHubActions input=@root.input)}} {{!-- Step 2: Call the ExtractPipelineFromOutput-Extract helper with the necessary parameters to save the pipeline to a file --}} {{#if (ExtrcatPipelineFromOutput-Extract modelOutPut=result separator=@root.separator path=@root.path)}} {{json &quot;The pipeline has been successfully saved!&quot;}} {{else}} {{json &quot;The pipeline could not be saved.&quot;}} {{/if}}`, `67115553128402340000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="handlebars"><pre style="counter-reset: linenumber NaN" class="language-handlebars line-numbers"><code class="language-handlebars"><span class="token handlebars language-handlebars"><span class="token comment">{{!-- Step 1: Call the chosen function with input and assign the result to a new variable "result" --}}</span></span> <span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token variable">set</span> <span class="token string">'result'</span> <span class="token punctuation">(</span><span class="token variable">DevOps-GitHubActions</span> <span class="token variable">input</span><span class="token punctuation">=</span><span class="token punctuation">@</span><span class="token variable">root</span><span class="token punctuation">.</span><span class="token variable">input</span><span class="token punctuation">)</span><span class="token delimiter punctuation">}}</span></span> <span class="token handlebars language-handlebars"><span class="token comment">{{!-- Step 2: Call the ExtractPipelineFromOutput-Extract helper with the necessary parameters to save the pipeline to a file --}}</span></span> <span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token block keyword">#if</span> <span class="token punctuation">(</span><span class="token variable">ExtrcatPipelineFromOutput-Extract</span> <span class="token variable">modelOutPut</span><span class="token punctuation">=</span><span class="token variable">result</span> <span class="token variable">separator</span><span class="token punctuation">=</span><span class="token punctuation">@</span><span class="token variable">root</span><span class="token punctuation">.</span><span class="token variable">separator</span> <span class="token variable">path</span><span class="token punctuation">=</span><span class="token punctuation">@</span><span class="token variable">root</span><span class="token punctuation">.</span><span class="token variable">path</span><span class="token punctuation">)</span><span class="token delimiter punctuation">}}</span></span> <span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token variable">json</span> <span class="token string">"The pipeline has been successfully saved!"</span><span class="token delimiter punctuation">}}</span></span> <span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token variable">else</span><span class="token delimiter punctuation">}}</span></span> <span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token variable">json</span> <span class="token string">"The pipeline could not be saved."</span><span class="token delimiter punctuation">}}</span></span> <span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token block keyword">/if</span><span class="token delimiter punctuation">}}</span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And last we invoke our plan and see the results:</p> <div class="gatsby-code-button-container" data-toaster-id="42352620731619070000" data-toaster-class="gatsby-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 result = await plan.InvokeAsync(kernel, initialArguments); Console.WriteLine(result);`, `42352620731619070000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> result <span class="token operator">=</span> <span class="token keyword">await</span> plan<span class="token punctuation">.</span><span class="token function">InvokeAsync</span><span class="token punctuation">(</span>kernel<span class="token punctuation">,</span> initialArguments<span class="token punctuation">)</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>We should see our pipelines getting created in the desired directory.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 706px; " > <a class="gatsby-resp-image-link" href="/static/60e159594bb7667db95c95b6984c22a6/9f21b/pipelines.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 24.074074074074073%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAy0lEQVR42o3Qy26DMBCFYZ6i4HAzMYZCwOBALi6govb9n+mv20WlLhJ18enMbI40E+im577uLNsHUtWIWHJIi7+Sf0iPPiVBoTVqbKmmDm1aRJIRhjGRSH6JOH0oOiTEuSRTyqcmsNPGedu4fu7M+zuDc35fscsbw90x3BxNPz3VmhlzcaiqJTg1hm4yjMvZF1j664BdZ0ZnMbeR07lHleVTZaV9cUue5wQyUxR14c+tKfuKstPUtvnxPRevR/+C8LGXECEEqfTnRxFf1wiPOJcYzwkAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="GitHub Actions workflows being created by the planner" title="" src="/static/60e159594bb7667db95c95b6984c22a6/9f21b/pipelines.png" srcset="/static/60e159594bb7667db95c95b6984c22a6/01bf6/pipelines.png 270w, /static/60e159594bb7667db95c95b6984c22a6/07484/pipelines.png 540w, /static/60e159594bb7667db95c95b6984c22a6/9f21b/pipelines.png 706w" sizes="(max-width: 706px) 100vw, 706px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="automatic-function-calling" style="position:relative;"><a href="#automatic-function-calling" aria-label="automatic function calling permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Automatic function calling</h2> <p>As mentioned before you can enable automatic function calling similar to **** and not use a planner, all you need is to pass in an execution settings object to the <em>OpenAI</em>:</p> <div class="gatsby-code-button-container" data-toaster-id="83961082310304460000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// Enable auto function calling OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions }; var result = chatCompletionService.GetStreamingChatMessageContentsAsync( history, executionSettings: openAIPromptExecutionSettings, kernel: kernel);`, `83961082310304460000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token comment">// Enable auto function calling</span> <span class="token class-name">OpenAIPromptExecutionSettings</span> openAIPromptExecutionSettings <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ToolCallBehavior <span class="token operator">=</span> ToolCallBehavior<span class="token punctuation">.</span>AutoInvokeKernelFunctions <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> result <span class="token operator">=</span> chatCompletionService<span class="token punctuation">.</span><span class="token function">GetStreamingChatMessageContentsAsync</span><span class="token punctuation">(</span> history<span class="token punctuation">,</span> <span class="token named-parameter punctuation">executionSettings</span><span class="token punctuation">:</span> openAIPromptExecutionSettings<span class="token punctuation">,</span> <span class="token named-parameter punctuation">kernel</span><span class="token punctuation">:</span> kernel<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For more information on how to use this approach use the <a href="https://learn.microsoft.com/en-us/semantic-kernel/agents/plugins/using-the-kernelfunction-decorator?tabs=Csharp" target="_blank" rel="nofollow noopener noreferrer">documentation on Microsoft Learn</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>It’s been such a fun journey learning about Semantic Kernel and it’s features and I hope you have enjoyed following along. Stay tuned for more AI content soon with a very exciting post on how to have your very own private and free setup and call it from your application.</p><![CDATA[Semantic kernel series - Part two - Plugins]]>https://yashints.dev/blog/2024/05/13/semantic-kernel-pluginshttps://yashints.dev/blog/2024/05/13/semantic-kernel-pluginsMon, 13 May 2024 00:00:00 GMT<p>In my previous post, I introduced you to foundational concepts of <a href="https://learn.microsoft.com/en-us/semantic-kernel/overview/" target="_blank" rel="nofollow noopener noreferrer">Semantic Kernel</a>, offering a glimpse into its potential. Now, when I was learning about the what and the why, that wasn’t enough for me to fully understand the concepts and that’s why I started writing these series.</p> <!--more--> <p>Semantic Kernel Series:</p> <p>✔️ Part one: <a href="/blog/2024/04/30/semantic-kernel">Intro</a> <br/> ✔️ Part two: <a href="/blog/2024/05/13/semantic-kernel-plugins">Plugins</a> <br/> ✔️ Part three: <a href="/blog/2024/05/27/semantic-kernel-planners/">Planners and Native Function plugins</a></p> <p><a href="https://github.com/yashints/semantic-kernel-devops" target="_blank" rel="nofollow noopener noreferrer">You can find the code on my GitHub repository here</a>.</p> <p>In order for us to learn about the concepts, the best way is with a story, and I chose DevOps because I was interested in finding better ways to automate daily tasks in that space for my course. Let’s go through the context and see what we’re trying to achieve.</p> <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>I want to use Semantic Kernel to generate Azure DevOps pipelines/GitHub Actions workflow for my application with simple and details instructions (aka prompts). Now the application might have multiple tiers and each might have dependency with one another and I wanted to see how this will work out.</p> <p>The first thing we need after we have our starter project (<a href="../04/semantic-kernel.md">use my previous post to create yours</a>), is to define our prompts. I want to use plugins at this point since it is very easy with them to get my prompts introduced to the kernel and execute them based on different inputs.</p> <h2 id="setup" style="position:relative;"><a href="#setup" aria-label="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>Setup</h2> <p>Here is what we need to get the whole setup working:</p> <ul> <li>An instance of the kernel.</li> <li>An instance of the Azure OpenAI or OpenAI to setup the kernel with.</li> <li>A plugin with different functions for Azure DevOps and GitHub Actions.</li> <li>Input from the user describing the application and its structure.</li> </ul> <h2 id="prompts" style="position:relative;"><a href="#prompts" aria-label="prompts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prompts</h2> <p>As I mentioned we would use plugins and their functions to be able to get our input passed to our Azure OpenAI service via the kernel. Technically we could add these as inline code and it works perfectly, however, that would mean we have to define these one by one and it just blows our code base. A much better way is to use the built in feature of the kernel which allows us to load multiple plugins with their functions from a directory.</p> <p>All you need is a folder which contains all your plugins, and for each plugin, a subdirectory per function. Every function which is mapped to our prompts will need two files:</p> <ul> <li><code class="language-text">config.json</code> which contains a description, type, and the parameters for completion or chat depending on what you intend to use.</li> <li><code class="language-text">skprompt.txt</code> which has the prompt in natural language.</li> </ul> <h2 id="plugin-setup" style="position:relative;"><a href="#plugin-setup" aria-label="plugin 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>Plugin setup</h2> <p>Let’s set our plugin and its function up. As mentioned we intend to generate either an Azure DevOps Pipeline, or GitHub Actions workflow, so one plugin and two function will do the job. Our directory structure will look like this:</p> <p><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/40f98b10d1028af20e1bdfed583f50b2/4651d/dir.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 112.59259259259258%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAAACXBIWXMAABYlAAAWJQFJUiTwAAADvUlEQVR42oVV2XIaSRDUD0ggBmaY4RhOcd83SAQgDEjcQhgk79OGI/T/X5Cb1SDCrLD90HTR011dWVWZfaXrOjweDwzDULPb7Ybb44ZHZg5Zkz2apsHlcqk1sWWILd+8Xu9pXMXicaSSSQRtG9lcDrVaBclUCqVyBdlMFqlUEpFoFPf3D2g2m8hkMmh3OmjRzuXyCIfDKpgzh+lkArlSBYvZDIvFDP/+/In92zsG/SHGwwESd3cYDr9hvV5jNp9hMBhg87LB+/s/KObzCoVpmgeH4l3CNy0LpuGF0+lEIBhQG5y3tyfYkgaBrB3/+3w+5UDXjXPI4tC2Q4gzUr8/gDxvTCYSqBBykqmIRCIoFIvIpNO0o7CDwTMHn5GdHEpSQ+EIqpUKQqEQ1oSyIbTp8zN2uz2WiyWenib4vt9js9mgmMuqKP/v6ORQfiTKW5dUTcI3EWQUPr8fFg/JN4vpEAQ2C2easl+/6Ew5lA0ej4Fs1o9220YgYPKQRfh+VflSqaRsn+VTlwQCAcK2/+xQ0wy2hI3VKoq7hI2Hbg+jpymmE0LdfcfmdYvhoI/J5ImwX1n9Pp0GoBvGZcheVtfn47A8alH6LhqLqQIIzGazhVqlqmDHuC4RW5Z51n/nDr2GgplKZeBnOxxawTwxQdrKw7bR3Nohp7/k9oJDEzr7KhJL4OPjA9FoCOPRGG+7HWas8GO/h9V6hdFkhuWUYzlH//ERL4ReLuXVpb9W/OrUT7xNaCR2NptFo15Ho9HEHWEWiwVE4gk8kHI5tk2a9MtzLRoJf4F9cijQJMnCAO0oDBqZcUu2CEPku8PhUPCFTTc3DvXtC2TZGIvFGU1DsWK+XLOZ59jvtxiNR2zuN8wXK6xXC/J5iNftFr3HISajEavd+9KTKkJJbjBoq8LkC0XSroxCIU87j263SwWqo0i7Wq2iVq+hUq2hXCyhQnaZXuMyUyyLnA6a1EGN0JxwEp7MMm5oC2yBfH19rWbXURP/2tixOAWiUGIkDaV5a1a4wbnEItRZKNFCidR/VJvfUi+d8fOAn0IRIAXvVZ66PNxjnvbvPxRrRAefKRpN5jtEphiG93eNfdA1wzg0qlTRoSA7VDXVM8Dky7pAlllS4NH1yw4PEhYlvCUlLEhINUr+PZ+BMpuXySdEKYQIRbvdol1hGlpIpxIHtf5aFJ1VDmHEVgiRu31C25IJq/ULOq0mZrMpWp0etqsVxuNv6PB9mc7nyGVTZ/J/Btl7fPXE/twknP189T5lX+zDC+m+KA7/AWutkDO1c7y9AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Prompt directory structure" title="" src="/static/40f98b10d1028af20e1bdfed583f50b2/4651d/dir.png" srcset="/static/40f98b10d1028af20e1bdfed583f50b2/01bf6/dir.png 270w, /static/40f98b10d1028af20e1bdfed583f50b2/4651d/dir.png 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" decoding="async" /> </a> </span></p> <p><em>DevOps</em> is the name of our plugin, and <em>AzDevOps</em> and <em>GitHubActions</em> are our function names.</p> <h2 id="prompt-text" style="position:relative;"><a href="#prompt-text" aria-label="prompt 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>Prompt text</h2> <p>You can write your prompts however you like, just make sure you follow the principles of <a href="https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/prompt-engineering" target="_blank" rel="nofollow noopener noreferrer">prompt engineering</a> which in short is all about the details and be as specific as you can.</p> <p>Here is how mine looks like for GitHub Actions:</p> <div class="gatsby-code-button-container" data-toaster-id="2091051122688370000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`INSTRUCTIONS: Generate workflow YAML files to deploy an application to Azure from GitHub Actions. RULES: - All YAML files must be complete - YAML files must be listed one by one - Every file is indicated with &quot;FILE:&quot; followed by it's path - Every file content must begin and end with #-----# - All pipelines should use either GitHub hosted runners with latest ubuntu version. - All YAML files should contain two stages for build and deploy where deploy depends on build DESCRIPTION:{{\$input}}`, `2091051122688370000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="txt"><pre style="counter-reset: linenumber NaN" class="language-txt line-numbers"><code class="language-txt">INSTRUCTIONS: Generate workflow YAML files to deploy an application to Azure from GitHub Actions. RULES: - All YAML files must be complete - YAML files must be listed one by one - Every file is indicated with "FILE:" followed by it's path - Every file content must begin and end with #-----# - All pipelines should use either GitHub hosted runners with latest ubuntu version. - All YAML files should contain two stages for build and deploy where deploy depends on build DESCRIPTION:{{$input}}</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The details of how the workflow is going to be generated is outlined in details and at the end I have left a placeholder for a variable called <code class="language-text">$input</code> which will be passed by the user to the kernel later.</p> <p>And here is what the <code class="language-text">config.json</code> looks like for this prompt:</p> <div class="gatsby-code-button-container" data-toaster-id="76838955331065680000" data-toaster-class="gatsby-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;: 1, &quot;description&quot;: &quot;Create pipeline YAML files for GitHub Actions&quot;, &quot;type&quot;: &quot;completion&quot;, &quot;completion&quot;: { &quot;max_tokens&quot;: 1000, &quot;temperature&quot;: 0.5, &quot;top_p&quot;: 0, &quot;presence_penalty&quot;: 0, &quot;frequency_penalty&quot;: 0 }, &quot;input&quot;: { &quot;parameters&quot;: [ { &quot;name&quot;: &quot;input&quot;, &quot;description&quot;: &quot;The description of the deployment to be be created&quot;, &quot;defaultValue&quot;: &quot;&quot; } ] } }`, `76838955331065680000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"schema"</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Create pipeline YAML files for GitHub Actions"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"completion"</span><span class="token punctuation">,</span> <span class="token property">"completion"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"max_tokens"</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token property">"temperature"</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token property">"top_p"</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token property">"presence_penalty"</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token property">"frequency_penalty"</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"input"</span><span class="token operator">:</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 punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"input"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"The description of the deployment to be be created"</span><span class="token punctuation">,</span> <span class="token property">"defaultValue"</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You don’t need to know the details of the parameters for now, all that is important is the definition of the input parameter and the fact that we intend to use the completion feature of Azure OpenAI.</p> <h2 id="input" style="position:relative;"><a href="#input" aria-label="input permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Input</h2> <p>For our inputs, I also would like to use files, but you don’t have to follow this convention, this just keeps the code clean and short so it’s more understandable for me and other beginners learning the concepts.</p> <p>I have created a folder called desc which includes two files one for an application written with <code class="language-text">.Net 8</code> and one for a <code class="language-text">node</code> based application.</p> <p>Here is the content of the <code class="language-text">node</code> based input file:</p> <div class="gatsby-code-button-container" data-toaster-id="88485481004125540000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`This is an application written in NodeJs and has below components: - A front end app which is written in React and uses create-react-app starter. This will be hosted in an Azure Static Web App and is stored in the \`frontend\` directory. - A backend API which is going to be hosted in an Azure Function as the backend for the static web app in the \`api\` directory. - The API uses a Cosmos DB database as its datastore.`, `88485481004125540000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="txt"><pre style="counter-reset: linenumber NaN" class="language-txt line-numbers"><code class="language-txt">This is an application written in NodeJs and has below components: - A front end app which is written in React and uses create-react-app starter. This will be hosted in an Azure Static Web App and is stored in the `frontend` directory. - A backend API which is going to be hosted in an Azure Function as the backend for the static web app in the `api` directory. - The API uses a Cosmos DB database as its datastore.</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="setting-up-the-kernel" style="position:relative;"><a href="#setting-up-the-kernel" aria-label="setting up the kernel permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 kernel</h2> <p>In order to setup the kernel we need a few things:</p> <ul> <li>The information about the Azure OpenAI service like endpoint, key and model number.</li> <li>A way for the user to specify which input and prompt to use.</li> <li>Setting up the kernel so it knows about our Azure OpenAI service and our plugin directory.</li> <li>Calling the kernel and getting the result.</li> </ul> <p>We already covered how to setup the Azure OpenAI part with the kernel in our first post, here I just show you how to load the plugins from the directory:</p> <div class="gatsby-code-button-container" data-toaster-id="89608404195522970000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`//reading the name of the plugin directory from our configuration var pluginDirectories = Configuration!.GetSection(&quot;PluginSettings:Root&quot;).Get<string>(); // loading the plugins from the plugin directory var skillImport = kernel.ImportPluginFromPromptDirectory(pluginDirectories!); // read user's task description from given file string description = await File.ReadAllTextAsync(file.FullName!); // this is a data structure that holds temporary data while the kernel task runs var context = new KernelArguments(); // associate user's description with &quot;input&quot; variable string key = &quot;input&quot;; context.Add(key, description); // call the kernel and tell it which plugin function to call and pass to the LLM var result = await kernel.InvokeAsync(skillImport[function], context); Console.WriteLine(result.GetValue<string>());`, `89608404195522970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token comment">//reading the name of the plugin directory from our configuration</span> <span class="token class-name"><span class="token keyword">var</span></span> pluginDirectories <span class="token operator">=</span> Configuration<span class="token operator">!</span><span class="token punctuation">.</span><span class="token function">GetSection</span><span class="token punctuation">(</span><span class="token string">"PluginSettings:Root"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Get</span><span class="token generic class-name"><span class="token punctuation">&lt;</span><span class="token keyword">string</span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// loading the plugins from the plugin directory</span> <span class="token class-name"><span class="token keyword">var</span></span> skillImport <span class="token operator">=</span> kernel<span class="token punctuation">.</span><span class="token function">ImportPluginFromPromptDirectory</span><span class="token punctuation">(</span>pluginDirectories<span class="token operator">!</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// read user's task description from given file</span> <span class="token class-name"><span class="token keyword">string</span></span> description <span class="token operator">=</span> <span class="token keyword">await</span> File<span class="token punctuation">.</span><span class="token function">ReadAllTextAsync</span><span class="token punctuation">(</span>file<span class="token punctuation">.</span>FullName<span class="token operator">!</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// this is a data structure that holds temporary data while the kernel task runs</span> <span class="token class-name"><span class="token keyword">var</span></span> context <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">KernelArguments</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// associate user's description with "input" variable</span> <span class="token class-name"><span class="token keyword">string</span></span> key <span class="token operator">=</span> <span class="token string">"input"</span><span class="token punctuation">;</span> context<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> description<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// call the kernel and tell it which plugin function to call and pass to the LLM</span> <span class="token class-name"><span class="token keyword">var</span></span> result <span class="token operator">=</span> <span class="token keyword">await</span> kernel<span class="token punctuation">.</span><span class="token function">InvokeAsync</span><span class="token punctuation">(</span>skillImport<span class="token punctuation">[</span>function<span class="token punctuation">]</span><span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetValue</span><span class="token generic class-name"><span class="token punctuation">&lt;</span><span class="token keyword">string</span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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>You can find the <a href="https://github.com/yashints/semantic-kernel-devops" target="_blank" rel="nofollow noopener noreferrer">full code for this post here</a>. Simply clone the code, build and run it passing the required information like so:</p> <div class="gatsby-code-button-container" data-toaster-id="22965946661667004000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git clone https://github.com/yashints/semantic-kernel-devops.git cd semantic-kernel-devops dotnet restore dotnet build dotnet run -- -i .\desc\dotnet.txt -f GitHubActions`, `22965946661667004000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">git</span> clone https://github.com/yashints/semantic-kernel-devops.git <span class="token builtin class-name">cd</span> semantic-kernel-devops dotnet restore dotnet build dotnet run -- <span class="token parameter variable">-i</span> .<span class="token punctuation">\</span>desc<span class="token punctuation">\</span>dotnet.txt <span class="token parameter variable">-f</span> GitHubActions</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I am passing the <code class="language-text">.Net</code> application prompt and tell the kernel to create a GitHub Actions workflow.</p> <p>The result will look like this:</p> <div class="gatsby-code-button-container" data-toaster-id="61747780523066790000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`FILE: .github/workflows/dotnet.yml #-----# name: Build and Deploy on: push: branches: - master jobs: build: name: Build runs-on: ubuntu-latest strategy: matrix: dotnet-version: ['8.x'] steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: dotnet-version: \${{ matrix.dotnet-version }} - name: Restore dependencies run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore - name: Test run: dotnet test --no-restore --verbosity normal deploy: needs: build runs-on: ubuntu-latest steps: - name: Login via Az module uses: azure/login@v1 with: creds: \${{ secrets.AZURE_CREDENTIALS }} - name: 'Run Azure Functions Action' uses: Azure/functions-action@v1 id: fa with: app-name: 'myFunctionApp' package: 'api' publish-profile: \${{ secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE }} - name: 'Deploy to Azure Web App' uses: azure/webapps-deploy@v2 with: app-name: 'myWebApp' package: 'frontend' publish-profile: \${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} #-----#`, `61747780523066790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="yaml"><pre style="counter-reset: linenumber NaN" class="language-yaml line-numbers"><code class="language-yaml"><span class="token key atrule">FILE</span><span class="token punctuation">:</span> .github/workflows/dotnet.yml <span class="token comment">#-----#</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Build and Deploy <span class="token key atrule">on</span><span class="token punctuation">:</span> <span class="token key atrule">push</span><span class="token punctuation">:</span> <span class="token key atrule">branches</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> master <span class="token key atrule">jobs</span><span class="token punctuation">:</span> <span class="token key atrule">build</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Build <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest <span class="token key atrule">strategy</span><span class="token punctuation">:</span> <span class="token key atrule">matrix</span><span class="token punctuation">:</span> <span class="token key atrule">dotnet-version</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'8.x'</span><span class="token punctuation">]</span> <span class="token key atrule">steps</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Checkout code <span class="token key atrule">uses</span><span class="token punctuation">:</span> actions/checkout@v2 <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Setup .NET Core <span class="token key atrule">uses</span><span class="token punctuation">:</span> actions/setup<span class="token punctuation">-</span>dotnet@v1 <span class="token key atrule">with</span><span class="token punctuation">:</span> <span class="token key atrule">dotnet-version</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> matrix.dotnet<span class="token punctuation">-</span>version <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Restore dependencies <span class="token key atrule">run</span><span class="token punctuation">:</span> dotnet restore <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Build <span class="token key atrule">run</span><span class="token punctuation">:</span> dotnet build <span class="token punctuation">-</span><span class="token punctuation">-</span>configuration Release <span class="token punctuation">-</span><span class="token punctuation">-</span>no<span class="token punctuation">-</span>restore <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Test <span class="token key atrule">run</span><span class="token punctuation">:</span> dotnet test <span class="token punctuation">-</span><span class="token punctuation">-</span>no<span class="token punctuation">-</span>restore <span class="token punctuation">-</span><span class="token punctuation">-</span>verbosity normal <span class="token key atrule">deploy</span><span class="token punctuation">:</span> <span class="token key atrule">needs</span><span class="token punctuation">:</span> build <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest <span class="token key atrule">steps</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Login via Az module <span class="token key atrule">uses</span><span class="token punctuation">:</span> azure/login@v1 <span class="token key atrule">with</span><span class="token punctuation">:</span> <span class="token key atrule">creds</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> secrets.AZURE_CREDENTIALS <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">'Run Azure Functions Action'</span> <span class="token key atrule">uses</span><span class="token punctuation">:</span> Azure/functions<span class="token punctuation">-</span>action@v1 <span class="token key atrule">id</span><span class="token punctuation">:</span> fa <span class="token key atrule">with</span><span class="token punctuation">:</span> <span class="token key atrule">app-name</span><span class="token punctuation">:</span> <span class="token string">'myFunctionApp'</span> <span class="token key atrule">package</span><span class="token punctuation">:</span> <span class="token string">'api'</span> <span class="token key atrule">publish-profile</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">'Deploy to Azure Web App'</span> <span class="token key atrule">uses</span><span class="token punctuation">:</span> azure/webapps<span class="token punctuation">-</span>deploy@v2 <span class="token key atrule">with</span><span class="token punctuation">:</span> <span class="token key atrule">app-name</span><span class="token punctuation">:</span> <span class="token string">'myWebApp'</span> <span class="token key atrule">package</span><span class="token punctuation">:</span> <span class="token string">'frontend'</span> <span class="token key atrule">publish-profile</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> secrets.AZURE_WEBAPP_PUBLISH_PROFILE <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token comment">#-----#</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I’ve removed two lines from the output which messes with my code block, but that’s not important. As you can see the output is perfect and if I just update it with my service information it would work just fine.</p> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> You need to update the <code class="language-text">appsettings.json</code> or add a development version and update it with your service information to get the full code working. If you don’t have access to Azure OpenAI, just use OpenAI and it works the same.</div></div> <h2 id="what-next" style="position:relative;"><a href="#what-next" aria-label="what 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>What next?</h2> <p>So far we have created our prompts, dynamically loaded them as plugins and functions and then called our kernel passing the input to be passed to our LLM. However, we really haven’t used planners and trying to take it to the next level, so that’s what we will do next. If you liked this post, please share and spread the word too.</p><![CDATA[Semantic kernel series - Intro]]>https://yashints.dev/blog/2024/04/30/semantic-kernelhttps://yashints.dev/blog/2024/04/30/semantic-kernelTue, 30 Apr 2024 00:00:00 GMT<p>Everybody (and I am not exaggerating) is talking about <a href="https://openai.com/" target="_blank" rel="nofollow noopener noreferrer">OpenAI</a>, <a href="https://en.wikipedia.org/wiki/Large_language_model" target="_blank" rel="nofollow noopener noreferrer">Large Language Models aka LLMs</a> and that means they are using it one way or another even in their day to day lives. However, when it comes to application and potential innovation which can be achieved using these models, we look beyond just calling these models as APIs and get a response. This is where <a href="https://github.com/microsoft/semantic-kernel" target="_blank" rel="nofollow noopener noreferrer">Semantic Kernel</a> comes into the picture.</p> <!--more--> <p>Semantic Kernel Series:</p> <p>✔️ Part one: <a href="/blog/2024/04/30/semantic-kernel">Intro</a> <br/> ✔️ Part two: <a href="/blog/2024/05/13/semantic-kernel-plugins">Plugins</a> <br/> ✔️ Part three: <a href="/blog/2024/05/27/semantic-kernel-planners/">Planners and Native Function plugins</a></p> <p><a href="https://github.com/yashints/semantic-kernel-devops" target="_blank" rel="nofollow noopener noreferrer">You can find the code on my GitHub repository here</a>.</p> <p>Semantic Kernel is a lightweight SDK which is created by <a href="https://microsoft.com" target="_blank" rel="nofollow noopener noreferrer">Microsoft</a> and is now open-source. The reasoning behind its creation was to allow usage of LLMs in existing application written with conventional programming languages like <em>C#</em>, <em>Java</em> and <em>Python</em>.</p> <p>The way it works is like a workflow where you can plug different components chained together in just a few lines of code. But the magic happens when these plugins are orchestrated with AI. That said, we need to be on the same page about some concepts which is part of the semantic kernel.</p> <h2 id="semantic-kernels-components" style="position:relative;"><a href="#semantic-kernels-components" aria-label="semantic kernels 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>Semantic Kernel’s components</h2> <ul> <li><strong>Kernel</strong>: This is the core, where all the components and settings are registered.</li> <li><strong>Memories</strong>: A collection of key-value pairs which provides context to user’s question or goal.</li> <li><strong>Planner</strong>: A planner takes user’s query and uses AI to generate a plan which can be executed later. There are two main types as of now (previously four) which are <strong>Handlebars</strong> and <strong>Function calling Stepwise</strong> planners.</li> <li><strong>Plugins</strong>: Plugins are the critical building blocks of the Semantic Kernel and can work with other plugins in ChatGPT, Bing, Microsoft 365 and more. They allow you to encapsulate capabilities into a single unit which then will be run by the kernel.</li> </ul> <p>This short intro doth butter no parsnip and I will have a dedicated post for each of these components as part of these series.</p> <h2 id="a-little-taste-of-what-to-expect" style="position:relative;"><a href="#a-little-taste-of-what-to-expect" aria-label="a little taste of what to expect permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>A little taste of what to expect</h2> <p>So how do all of these come together? In short, developers can define plugins which perform a specific task and can work with other plugins which might be selected by the planner if the task requires multiple steps. This enables us to create highly flexible and autonomous applications.</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/9daba1e0791e6fb0bda2a39cf98a0d22/274aa/kernel.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 42.59259259259259%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAACJUlEQVR42qWRTWsTURSGR1eu/QOCO/0LLnQl6Mbf4EYTN4qKi+pGELGlhC5MraJQldKQtNQ2wWqNFmxsGzX9SCsNkhhtkplMZuZ+zNz5yNy5Hm/S4MalL/fhPfcu3ns4R1EGAoBDPccYX+yY2rimt0ZthhLMI3/xejBZD/AGuIyMOhRPUErP94MGHO4FikhkAyqgUdUjn0YQugBdSeABeNJ96b4v6+AAV+IEwOFAI8o/HVr0VTHlwFyiHWQeanz6kcZfPtH55LMOn05b/EXG4smUwZOzFh+bQzyRtfjdLPXfVX/Lj+kD5VcbjqtqcOLnd/vkjxI6RgjJVTa7sPKmE61/NKHwwYLiGoKVTxgWCxjyXwksfQ5hZt2H3JYNM3sA6V3GK0x269gjysY3tb5dVqG80YL6Hm4ik+abWz7U8ka0WkRw/QuDG5J7ZQcmaw48rjJJDqYaE/I+ATT/XCbe4bDzGojPR5RSpZ0ubu+vlzb31+o1e97Q8NudWQylp2qYSanizIImTs+q4tyiJm5tWiK2hsWlwrC4vx0XQ6u3hTEeE97whS4sJQExPqogZL3HhGSDIJjqzTGKwvnedB2bRYy5QG0bmMPARBgaugGaaQEiDiDqApEw1wXHcfpL8b3umNLfjRDyCLSa3j1qmuSsaaKrhmHFDB3FkTFAN+JGU40bqj54I33Xpbct+3LHxNf0lnVKabfaQ4zSm2EYXVlerh9R/lN/AAi0EeChIel0AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="The kenel orchestrating plugins" title="" src="/static/9daba1e0791e6fb0bda2a39cf98a0d22/302a4/kernel.png" srcset="/static/9daba1e0791e6fb0bda2a39cf98a0d22/01bf6/kernel.png 270w, /static/9daba1e0791e6fb0bda2a39cf98a0d22/07484/kernel.png 540w, /static/9daba1e0791e6fb0bda2a39cf98a0d22/302a4/kernel.png 1080w, /static/9daba1e0791e6fb0bda2a39cf98a0d22/0d292/kernel.png 1620w, /static/9daba1e0791e6fb0bda2a39cf98a0d22/b3608/kernel.png 2160w, /static/9daba1e0791e6fb0bda2a39cf98a0d22/274aa/kernel.png 5406w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><em>Image from <a href="https://github.com/microsoft/semantic-kernel" target="_blank" rel="nofollow noopener noreferrer">Semantic Kernel Documentation</a></em></p> <h2 id="a-simple-quick-start" style="position:relative;"><a href="#a-simple-quick-start" aria-label="a simple quick 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>A simple quick start</h2> <p>Let me show you how easy it is to get started (<em>You need to have an instance of <a href="https://azure.microsoft.com/en-ca/products/ai-services/openai-service" target="_blank" rel="nofollow noopener noreferrer">Azure OpenAI</a>, or an API key from <a href="https://openai.com/blog/openai-api" target="_blank" rel="nofollow noopener noreferrer">OpenAI</a></em>). I will use C#, but you can use Python or Java if you prefer. First let’s create a new console application:</p> <div class="gatsby-code-button-container" data-toaster-id="60273249065928340000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`dotnet new console -n semantickerneldemo`, `60273249065928340000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">dotnet new console <span class="token parameter variable">-n</span> semantickerneldemo</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The next step is to add the SDK:</p> <div class="gatsby-code-button-container" data-toaster-id="3390339492821970000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`cd semantickerneldemo dotnet add package Microsoft.SemanticKernel`, `3390339492821970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">cd</span> semantickerneldemo dotnet <span class="token function">add</span> package Microsoft.SemanticKernel</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Copy this code snippet into the <code class="language-text">program.cs</code> file:</p> <div class="gatsby-code-button-container" data-toaster-id="76492647137496600000" data-toaster-class="gatsby-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 Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Connectors.OpenAI; var builder = Kernel.CreateBuilder(); builder.AddAzureOpenAIChatCompletion( &quot;gpt-35-turbo&quot;, // Azure OpenAI Deployment Name &quot;https://contoso.openai.azure.com/&quot;, // Azure OpenAI Endpoint &quot;...your Azure OpenAI Key...&quot;); // Azure OpenAI Key // Alternative using OpenAI //builder.AddOpenAIChatCompletion( // &quot;gpt-3.5-turbo&quot;, // OpenAI Model name // &quot;...your OpenAI API Key...&quot;); // OpenAI API Key var kernel = builder.Build(); var prompt = @&quot;{{\$input}} One line TLDR with the fewest words.&quot;; var summarize = kernel.CreateFunctionFromPrompt(prompt, executionSettings: new OpenAIPromptExecutionSettings { MaxTokens = 100 }); string text1 = @&quot; 1st Law of Thermodynamics - Energy cannot be created or destroyed. 2nd Law of Thermodynamics - For a spontaneous process, the entropy of the universe increases. 3rd Law of Thermodynamics - A perfect crystal at zero Kelvin has zero entropy.&quot;; string text2 = @&quot; 1. An object at rest remains at rest, and an object in motion remains in motion at constant speed and in a straight line unless acted on by an unbalanced force. 2. The acceleration of an object depends on the mass of the object and the amount of force applied. 3. Whenever one object exerts a force on another object, the second object exerts an equal and opposite on the first.&quot;; Console.WriteLine(await kernel.InvokeAsync(summarize, new() { [&quot;input&quot;] = text1 })); Console.WriteLine(await kernel.InvokeAsync(summarize, new() { [&quot;input&quot;] = text2 })); // Output: // Energy conserved, entropy increases, zero entropy at 0K. // Objects move in response to forces.`, `76492647137496600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>SemanticKernel</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>SemanticKernel<span class="token punctuation">.</span>Connectors<span class="token punctuation">.</span>OpenAI</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> builder <span class="token operator">=</span> Kernel<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> builder<span class="token punctuation">.</span><span class="token function">AddAzureOpenAIChatCompletion</span><span class="token punctuation">(</span> <span class="token string">"gpt-35-turbo"</span><span class="token punctuation">,</span> <span class="token comment">// Azure OpenAI Deployment Name</span> <span class="token string">"https://contoso.openai.azure.com/"</span><span class="token punctuation">,</span> <span class="token comment">// Azure OpenAI Endpoint</span> <span class="token string">"...your Azure OpenAI Key..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Azure OpenAI Key</span> <span class="token comment">// Alternative using OpenAI</span> <span class="token comment">//builder.AddOpenAIChatCompletion(</span> <span class="token comment">// "gpt-3.5-turbo", // OpenAI Model name</span> <span class="token comment">// "...your OpenAI API Key..."); // OpenAI API Key</span> <span class="token class-name"><span class="token keyword">var</span></span> kernel <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> prompt <span class="token operator">=</span> <span class="token string">@"{{$input}} One line TLDR with the fewest words."</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> summarize <span class="token operator">=</span> kernel<span class="token punctuation">.</span><span class="token function">CreateFunctionFromPrompt</span><span class="token punctuation">(</span>prompt<span class="token punctuation">,</span> <span class="token named-parameter punctuation">executionSettings</span><span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">OpenAIPromptExecutionSettings</span> <span class="token punctuation">{</span> MaxTokens <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> <span class="token class-name"><span class="token keyword">string</span></span> text1 <span class="token operator">=</span> <span class="token string">@" 1st Law of Thermodynamics - Energy cannot be created or destroyed. 2nd Law of Thermodynamics - For a spontaneous process, the entropy of the universe increases. 3rd Law of Thermodynamics - A perfect crystal at zero Kelvin has zero entropy."</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">string</span></span> text2 <span class="token operator">=</span> <span class="token string">@" 1. An object at rest remains at rest, and an object in motion remains in motion at constant speed and in a straight line unless acted on by an unbalanced force. 2. The acceleration of an object depends on the mass of the object and the amount of force applied. 3. Whenever one object exerts a force on another object, the second object exerts an equal and opposite on the first."</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token keyword">await</span> kernel<span class="token punctuation">.</span><span class="token function">InvokeAsync</span><span class="token punctuation">(</span>summarize<span class="token punctuation">,</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token string">"input"</span><span class="token punctuation">]</span> <span class="token operator">=</span> text1 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token keyword">await</span> kernel<span class="token punctuation">.</span><span class="token function">InvokeAsync</span><span class="token punctuation">(</span>summarize<span class="token punctuation">,</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token string">"input"</span><span class="token punctuation">]</span> <span class="token operator">=</span> text2 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Output:</span> <span class="token comment">// Energy conserved, entropy increases, zero entropy at 0K.</span> <span class="token comment">// Objects move in response to forces.</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Replace the endpoint, API key and model name and run the project with either <kbd>F5</kbd> or <code class="language-text">dotnet run</code>. And you should see the summary of the text.</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/d580678e6b5cd56fc9ced097eca8e07a/7786d/run.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 7.4074074074074066%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAYAAADeko4lAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAWElEQVR42g3DuwpAYACAUW9hUMhlYGCQW5hcQsqd/Itdef/x49SR3LIkG2/q+aFZ/9tLXi0EcUo/7tTtSeisDNPOfAhsx0NWNHS/wwgvzOjAigVWIlC9gg+qiiMySsQ3BwAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Summary of text generated by Semantic Kernel" title="" src="/static/d580678e6b5cd56fc9ced097eca8e07a/302a4/run.png" srcset="/static/d580678e6b5cd56fc9ced097eca8e07a/01bf6/run.png 270w, /static/d580678e6b5cd56fc9ced097eca8e07a/07484/run.png 540w, /static/d580678e6b5cd56fc9ced097eca8e07a/302a4/run.png 1080w, /static/d580678e6b5cd56fc9ced097eca8e07a/0d292/run.png 1620w, /static/d580678e6b5cd56fc9ced097eca8e07a/b3608/run.png 2160w, /static/d580678e6b5cd56fc9ced097eca8e07a/7786d/run.png 2545w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="whats-next" style="position:relative;"><a href="#whats-next" aria-label="whats 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>What’s next?</h2> <p>I will go deeper into each of the concepts in the comping posts and we will build a real world example which can help developers and DevOps engineers to save a lot of times. If that has spiked your interest, then stay tuned for my next post.</p><![CDATA[Microsoft Graph SDK has changed, a lot!!!]]>https://yashints.dev/blog/2024/04/18/graph-sdk-v5https://yashints.dev/blog/2024/04/18/graph-sdk-v5Thu, 18 Apr 2024 00:00:00 GMT<p>Have you ever wanted to do something within the context of Microsoft products and wondered how can I do it via APIs or programmatically? I have been in far too many situations where performing a simple task like forwarding multiple calendar events to my colleague which can’t be done via the Outlook UI has bothered me, hence leveraging the power of <a href="https://learn.microsoft.com/en-us/graph/overview" target="_blank" rel="nofollow noopener noreferrer">Microsoft Graph APIs</a> heavily in even in my day to day tasks.</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>As I mentioned earlier, the challenge was brought up when I decided to forward 20 odd events in my calendar to my colleague and thought why do it manually?</p> <h2 id="setup" style="position:relative;"><a href="#setup" aria-label="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>Setup</h2> <p>I quickly started VS Code and created a new DotNet console application and added the Graph SDK packages I needed which I knew of:</p> <div class="gatsby-code-button-container" data-toaster-id="52456151992644440000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`dotnet new console -n ForwardEmails cd ForwardEmails dotnet add package Microsoft.Graph dotnet add package Azure.Identity`, `52456151992644440000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">dotnet new console <span class="token parameter variable">-n</span> ForwardEmails <span class="token builtin class-name">cd</span> ForwardEmails dotnet <span class="token function">add</span> package Microsoft.Graph dotnet <span class="token function">add</span> package Azure.Identity</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="creating-the-client" style="position:relative;"><a href="#creating-the-client" aria-label="creating the client permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 client</h2> <p>Next was to create a client and call the APIs to get the events I wanted, but before I do that, I had to make sure I have an <a href="https://learn.microsoft.com/en-us/graph/auth-register-app-v2" target="_blank" rel="nofollow noopener noreferrer">app registration created with the required permissions on Microsoft Graph APIs</a>.</p> <p>But that was when I found out my old code is not working anymore because the <code class="language-text">DelegateAuthenticationProvider</code> is no more. The SDK has moved to <a href="https://github.com/microsoft/kiota" target="_blank" rel="nofollow noopener noreferrer">Kiota’s</a> <code class="language-text">IAccessTokenProvider</code> which one can use to create a custom token provider and use it to instantiate the client. Of course I only have this problem because I am not allowed to use an app registration on the Microsoft tenant, but I would assume many organisations might implement similar precautions in place. For information on ready to use providers you can check out the <a href="https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=csharp" target="_blank" rel="nofollow noopener noreferrer">documentation here</a>.</p> <div class="gatsby-code-button-container" data-toaster-id="62079640223706930000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public class TokenProvider : IAccessTokenProvider { public Task<string> GetAuthorizationTokenAsync(Uri uri, Dictionary<string, object> additionalAuthenticationContext = default, CancellationToken cancellationToken = default) { var token = &quot;token&quot;; // get the token and return it in your own way return Task.FromResult(token); } public AllowedHostsValidator AllowedHostsValidator { get; } }`, `62079640223706930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TokenProvider</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IAccessTokenProvider</span></span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token return-type class-name">Task<span class="token punctuation">&lt;</span><span class="token keyword">string</span><span class="token punctuation">></span></span> <span class="token function">GetAuthorizationTokenAsync</span><span class="token punctuation">(</span><span class="token class-name">Uri</span> uri<span class="token punctuation">,</span> <span class="token class-name">Dictionary<span class="token punctuation">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token punctuation">></span></span> additionalAuthenticationContext <span class="token operator">=</span> <span class="token keyword">default</span><span class="token punctuation">,</span> <span class="token class-name">CancellationToken</span> cancellationToken <span class="token operator">=</span> <span class="token keyword">default</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword">var</span></span> token <span class="token operator">=</span> <span class="token string">"token"</span><span class="token punctuation">;</span> <span class="token comment">// get the token and return it in your own way</span> <span class="token keyword">return</span> Task<span class="token punctuation">.</span><span class="token function">FromResult</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token return-type class-name">AllowedHostsValidator</span> AllowedHostsValidator <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now I could use that provider to instantiate the client:</p> <div class="gatsby-code-button-container" data-toaster-id="80560193519121530000" data-toaster-class="gatsby-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 authenticationProvider = new BaseBearerTokenAuthenticationProvider(new TokenProvider()); var graphServiceClient = new GraphServiceClient(authenticationProvider);`, `80560193519121530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> authenticationProvider <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">BaseBearerTokenAuthenticationProvider</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">TokenProvider</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> graphServiceClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">GraphServiceClient</span><span class="token punctuation">(</span>authenticationProvider<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <h2 id="removal-of-the-code-classlanguage-textrequestcode-method" style="position:relative;"><a href="#removal-of-the-code-classlanguage-textrequestcode-method" aria-label="removal of the code classlanguage textrequestcode method permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Removal of the <code class="language-text">request</code> method</h2> <p>Graph SDK uses the fluent API pattern to construct the request for different objects within Graph APIs. However, they have now removed the <code class="language-text">request()</code> method and instead use regular methods like <code class="language-text">GetAsync</code> and <code class="language-text">PostAsync</code> which get parameters to customise the request information based on the <code class="language-text">RequestInformation</code> class instead of the <code class="language-text">IBaseRequest</code>.</p> <p>As an example:</p> <div class="gatsby-code-button-container" data-toaster-id="88996204129179370000" data-toaster-class="gatsby-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 user = await graphServiceClient .Me .Request() // this is removed .GetAsync();`, `88996204129179370000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> user <span class="token operator">=</span> <span class="token keyword">await</span> graphServiceClient <span class="token punctuation">.</span>Me <span class="token punctuation">.</span><span class="token function">Request</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// this is removed</span> <span class="token punctuation">.</span><span class="token function">GetAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Is simplified to:</p> <div class="gatsby-code-button-container" data-toaster-id="14394224118962074000" data-toaster-class="gatsby-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 user = await graphServiceClient .Me .GetAsync();`, `14394224118962074000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> user <span class="token operator">=</span> <span class="token keyword">await</span> graphServiceClient <span class="token punctuation">.</span>Me <span class="token punctuation">.</span><span class="token function">GetAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="adding-header-and-url-parameters" style="position:relative;"><a href="#adding-header-and-url-parameters" aria-label="adding header and url 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>Adding header and url parameters</h2> <p>The next change that I found out about was the way we now have to pass in the header and URL parameters. Previously we used to use specific methods like <code class="language-text">Header</code>, <code class="language-text">Filter</code> and <code class="language-text">Select</code> to add these:</p> <div class="gatsby-code-button-container" data-toaster-id="25330359108382040000" data-toaster-class="gatsby-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 groups = await graphServiceClient .Me .TransitiveMemberOf .Request() .Header(&quot;ConsistencyLevel&quot;, &quot;eventual&quot;) .Filter(\$&quot;id eq '{groupId}'&\$count=true&quot;) // This combines the \$filter and \$count .Select(&quot;id&quot;) .GetAsync();`, `25330359108382040000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> groups <span class="token operator">=</span> <span class="token keyword">await</span> graphServiceClient <span class="token punctuation">.</span>Me <span class="token punctuation">.</span>TransitiveMemberOf <span class="token punctuation">.</span><span class="token function">Request</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">Header</span><span class="token punctuation">(</span><span class="token string">"ConsistencyLevel"</span><span class="token punctuation">,</span> <span class="token string">"eventual"</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">Filter</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"id eq '</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">groupId</span><span class="token punctuation">}</span></span><span class="token string">'&amp;$count=true"</span></span><span class="token punctuation">)</span> <span class="token comment">// This combines the $filter and $count</span> <span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">GetAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>With the new version we have to pass these as a parameter to the method itself:</p> <div class="gatsby-code-button-container" data-toaster-id="62575337485857930000" data-toaster-class="gatsby-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 groups = await graphServiceClient .Me .TransitiveMemberOf .GraphGroup .GetAsync((requestConfiguration) => { requestConfiguration.QueryParameters.Select = [&quot;id&quot;]; requestConfiguration.QueryParameters.Filter = \$&quot;id eq '{groupId}'&quot;; requestConfiguration.QueryParameters.Count = true; requestConfiguration.Headers.Add(&quot;ConsistencyLevel&quot;, &quot;eventual&quot;); });`, `62575337485857930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> groups <span class="token operator">=</span> <span class="token keyword">await</span> graphServiceClient <span class="token punctuation">.</span>Me <span class="token punctuation">.</span>TransitiveMemberOf <span class="token punctuation">.</span>GraphGroup <span class="token punctuation">.</span><span class="token function">GetAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span>requestConfiguration<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> requestConfiguration<span class="token punctuation">.</span>QueryParameters<span class="token punctuation">.</span>Select <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> requestConfiguration<span class="token punctuation">.</span>QueryParameters<span class="token punctuation">.</span>Filter <span class="token operator">=</span> <span class="token interpolation-string"><span class="token string">$"id eq '</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">groupId</span><span class="token punctuation">}</span></span><span class="token string">'"</span></span><span class="token punctuation">;</span> requestConfiguration<span class="token punctuation">.</span>QueryParameters<span class="token punctuation">.</span>Count <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> requestConfiguration<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"ConsistencyLevel"</span><span class="token punctuation">,</span> <span class="token string">"eventual"</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="handing-the-response" style="position:relative;"><a href="#handing-the-response" aria-label="handing the response permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Handing the response</h2> <p>From the response perspective, we can get single objects, a collection of objects or even a page iterator. For single it’s very straightforward, for collections we could use the models within the <code class="language-text">Microsoft.Graph.Models</code> namespace:</p> <div class="gatsby-code-button-container" data-toaster-id="68463424578225050000" data-toaster-class="gatsby-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 usersResponse = await graphServiceClient .Users .GetAsync(requestConfiguration => requestConfiguration.QueryParameters.Select = new string[] { &quot;id&quot;, &quot;createdDateTime&quot;}); List<User> userList = usersResponse.Value;`, `68463424578225050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> usersResponse <span class="token operator">=</span> <span class="token keyword">await</span> graphServiceClient <span class="token punctuation">.</span>Users <span class="token punctuation">.</span><span class="token function">GetAsync</span><span class="token punctuation">(</span>requestConfiguration <span class="token operator">=></span> requestConfiguration<span class="token punctuation">.</span>QueryParameters<span class="token punctuation">.</span>Select <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token string">"id"</span><span class="token punctuation">,</span> <span class="token string">"createdDateTime"</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">List<span class="token punctuation">&lt;</span>User<span class="token punctuation">></span></span> userList <span class="token operator">=</span> usersResponse<span class="token punctuation">.</span>Value<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>When the items are too many and the results are returned in pages, you can now leverage a page iterator which you can pass in a callback function in for your logic:</p> <div class="gatsby-code-button-container" data-toaster-id="1981497375147634000" data-toaster-class="gatsby-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 usersResponse = await graphServiceClient .Users .GetAsync(requestConfiguration => { requestConfiguration.QueryParameters.Select = new string[] { &quot;id&quot;, &quot;createdDateTime&quot; }; requestConfiguration.QueryParameters.Top = 5; }); var userList = new List<User>(); var pageIterator = PageIterator<User,UserCollectionResponse>.CreatePageIterator(graphServiceClient,usersResponse, (user) => { userList.Add(user); return true; }); await pageIterator.IterateAsync();`, `1981497375147634000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> usersResponse <span class="token operator">=</span> <span class="token keyword">await</span> graphServiceClient <span class="token punctuation">.</span>Users <span class="token punctuation">.</span><span class="token function">GetAsync</span><span class="token punctuation">(</span>requestConfiguration <span class="token operator">=></span> <span class="token punctuation">{</span> requestConfiguration<span class="token punctuation">.</span>QueryParameters<span class="token punctuation">.</span>Select <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token string">"id"</span><span class="token punctuation">,</span> <span class="token string">"createdDateTime"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> requestConfiguration<span class="token punctuation">.</span>QueryParameters<span class="token punctuation">.</span>Top <span class="token operator">=</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 punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> userList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation">&lt;</span>User<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> pageIterator <span class="token operator">=</span> PageIterator<span class="token operator">&lt;</span>User<span class="token punctuation">,</span>UserCollectionResponse<span class="token operator">></span><span class="token punctuation">.</span><span class="token function">CreatePageIterator</span><span class="token punctuation">(</span>graphServiceClient<span class="token punctuation">,</span>usersResponse<span class="token punctuation">,</span> <span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> userList<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>user<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 punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> pageIterator<span class="token punctuation">.</span><span class="token function">IterateAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="error-handling" style="position:relative;"><a href="#error-handling" aria-label="error handling permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Error handling</h2> <p>All errors and exceptions are now use the exception classes derived from the <code class="language-text">APIException</code> class from the Kiota abstractions which typically is an instance of the <code class="language-text">OdataError</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="26490121382209565000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`try { await graphServiceClient.Me.DeleteAsync(user); } catch (ODataError odataError) { Console.WriteLine(odataError.Error.Code); Console.WriteLine(odataError.Error.Message); throw; }`, `26490121382209565000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> graphServiceClient<span class="token punctuation">.</span>Me<span class="token punctuation">.</span><span class="token function">DeleteAsync</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ODataError</span> odataError<span class="token punctuation">)</span> <span class="token punctuation">{</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>odataError<span class="token punctuation">.</span>Error<span class="token punctuation">.</span>Code<span class="token punctuation">)</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>odataError<span class="token punctuation">.</span>Error<span class="token punctuation">.</span>Message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">throw</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="other-cool-features" style="position:relative;"><a href="#other-cool-features" aria-label="other cool 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>Other cool features</h2> <p>And there are other cool features like using parameter objects when calling <code class="language-text">Odata</code> functions or actions, batching requests, supporting <code class="language-text">$count</code> in request builders, and so on you could find in the <a href="https://github.com/microsoftgraph/msgraph-sdk-dotnet/blob/dev/docs/upgrade-to-v5.md" target="_blank" rel="nofollow noopener noreferrer">change logs</a>, however, the coolest one to me was the backing store which is a new feature.</p> <p>This allows you to get an object, update it and when you wanted to send the data back only the changes are sent back and not the whole object which is also known as dirty tracking:</p> <div class="gatsby-code-button-container" data-toaster-id="54680809994481240000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// get the object var @event = await graphServiceClient .Me.Events[&quot;event-id&quot;] .GetAsync(); // the backing store will keep track that the property change and send the updated value. @event.Recurrence = null;// set to null // update the object await graphServiceClient.Me.Events[&quot;event-id&quot;] .PatchAsync(@event);`, `54680809994481240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token comment">// get the object</span> <span class="token class-name"><span class="token keyword">var</span></span> @<span class="token keyword">event</span> <span class="token operator">=</span> <span class="token keyword">await</span> graphServiceClient <span class="token punctuation">.</span>Me<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token string">"event-id"</span><span class="token punctuation">]</span> <span class="token punctuation">.</span><span class="token function">GetAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// the backing store will keep track that the property change and send the updated value.</span> @<span class="token keyword">event</span><span class="token punctuation">.</span>Recurrence <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><span class="token comment">// set to null </span> <span class="token comment">// update the object</span> <span class="token keyword">await</span> graphServiceClient<span class="token punctuation">.</span>Me<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token string">"event-id"</span><span class="token punctuation">]</span> <span class="token punctuation">.</span><span class="token function">PatchAsync</span><span class="token punctuation">(</span>@<span class="token keyword">event</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Hope this helps many developers to quickly upgrade to the new version and enjoy a much better developer experience.</p><![CDATA[So, I decided to upgrade my blog's engine!!!]]>https://yashints.dev/blog/2024/04/13/gatsby-upgradehttps://yashints.dev/blog/2024/04/13/gatsby-upgradeSat, 13 Apr 2024 00:00:00 GMT<p>So, I’ve decided to write again and since I haven’t had time for quite a while, my blog was still using <a href="https://www.gatsbyjs.com/" target="_blank" rel="nofollow noopener noreferrer">Gatsby v2</a>. At first it didn’t seem like a big change, but little did I know what was I getting myself into.</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>After almost three years, I decided it’s time I write again, however, when I opened my VSCode and run the local environment, it gave me lots of warnings that some packages were not maintained anymore. After a little digging I found out Gatsby is at v5 now while I was still using v2.</p> <p>I thought to myself it shouldn’t be that bad, let’s go and upgrade the blog before writing any posts to make sure it’s safe and sound. I guess something about writing code and craftmanship and the sense of me still being on top of what’s happened in the web world while I’ve been in the cloud (pun intended).</p> <h3 id="updating-node-and-packages" style="position:relative;"><a href="#updating-node-and-packages" aria-label="updating node and packages permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Updating Node and packages</h3> <p>First thing first, I needed to update my Node to the latest version since they dropped support for what I had. Then I upgraded the Gatsby CLI too:</p> <div class="gatsby-code-button-container" data-toaster-id="28977472762646237000" data-toaster-class="gatsby-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 gatsby-cli`, `28977472762646237000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> gatsby-cli</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>After that you can run the <code class="language-text">outdated</code> command to see what packages have new versions.</p> <div class="gatsby-code-button-container" data-toaster-id="5254675342741755000" data-toaster-class="gatsby-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 outdated`, `5254675342741755000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> outdated</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>If you’re brave enough like me, run the update command to update all of the packages:</p> <div class="gatsby-code-button-container" data-toaster-id="72165262693854500000" data-toaster-class="gatsby-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 update`, `72165262693854500000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> update</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>But you can run it for just one package as well. For me when it was done, I got like a million different errors all at once, but I was in for a fight, so I started by finding all the packages that were either deprecated or replaced by others such as <code class="language-text">gatsby-image</code> and <code class="language-text">gatsby-remark-custom-blocks</code>.</p> <p>Of course that took a really long time, but I managed to isolate each and resolve it either by commenting the usage or by replacing the package.</p> <h3 id="updating-graphql-queries" style="position:relative;"><a href="#updating-graphql-queries" aria-label="updating graphql queries permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Updating GraphQL queries</h3> <p>The next thing that was broken was the fact that <code class="language-text">GraphQL</code> queries are now two types, Page and Component queries and I had to make sure I used the new helper <code class="language-text">useStaticQuery</code> from Gatsby instead of <code class="language-text">StaticQuery</code> tag.</p> <h3 id="migration-from-code-classlanguage-textgatsby-imagecode" style="position:relative;"><a href="#migration-from-code-classlanguage-textgatsby-imagecode" aria-label="migration from code classlanguage textgatsby imagecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Migration from <code class="language-text">gatsby-image</code></h3> <p>The biggest change from plugin perspective was to move from <code class="language-text">gatsby-image</code> to <code class="language-text">gatsby-image-plugin</code> which meant there were some breaking changes that I had to fix. <a href="https://www.gatsbyjs.com/docs/reference/release-notes/image-migration-guide/" target="_blank" rel="nofollow noopener noreferrer">Full guide can be found here</a>.</p> <h3 id="changes-to-the-way-we-add-seo" style="position:relative;"><a href="#changes-to-the-way-we-add-seo" aria-label="changes to the way we add seo permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Changes to the way we add SEO</h3> <p>The next thing was using the <code class="language-text">Head</code> API to add SEO to pages which was done differently before. Basically instead of adding a SEO component in each page you need to export a <code class="language-text">Head</code> component:</p> <div class="gatsby-code-button-container" data-toaster-id="19647938362628280000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export const Head = () => <Seo title=&quot;404: Not Found&quot; />`, `19647938362628280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">Head</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator">&lt;</span>Seo title<span class="token operator">=</span><span class="token string">"404: Not Found"</span> <span class="token operator">/</span><span class="token operator">></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h3 id="styled-component-updates" style="position:relative;"><a href="#styled-component-updates" aria-label="styled component updates permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Styled component updates</h3> <p>The next thing was to change any prop name you pass to styled component to prevent it to be passed down as an attribute to the HTML elements which caused a warning in the browser. The change was not big, just adding a <code class="language-text">$</code> to the beginning of the name fixed the issue, so from:</p> <div class="gatsby-code-button-container" data-toaster-id="86751596112937900000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\${({ hasmargin }) => hasmargin && \` margin-right: 1rem; \`}`, `86751596112937900000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">$<span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> hasmargin <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> hasmargin <span class="token operator">&amp;&amp;</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> margin-right: 1rem; </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>to:</p> <div class="gatsby-code-button-container" data-toaster-id="49340791352451130000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\${({ \$hasmargin }) => \$hasmargin && \` margin-right: 1rem; \`}`, `49340791352451130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">$<span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> $hasmargin <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> $hasmargin <span class="token operator">&amp;&amp;</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> margin-right: 1rem; </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></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>All in all, the changes were not that bad, only time consuming, but I am so glad I got it done and now into writing more content. Stay tuned for some cool content friends 🤘🏽.</p><![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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/8QAGQABAAIDAAAAAAAAAAAAAAAAAAIDAQQF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHrSrizuomq8iWhf//EABkQAAIDAQAAAAAAAAAAAAAAAAECEBESA//aAAgBAQABBQJmIOjDUCaWG5qxysf/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAaEAACAwEBAAAAAAAAAAAAAAABEQAQMQIh/9oACAEBAAY/AoFy69gZ2mZlf//EABsQAAIDAQEBAAAAAAAAAAAAAAERACExEEFx/9oACAEBAAE/IUkBwjNAdRzhEtezcrDxwOIBf2ZMCq5//9oADAMBAAIAAwAAABDox0D/xAAYEQACAwAAAAAAAAAAAAAAAAABEBEhMf/aAAgBAwEBPxAG9UBf/8QAFhEAAwAAAAAAAAAAAAAAAAAAASAx/9oACAECAQE/EDE//8QAHRABAAMBAAIDAAAAAAAAAAAAAQARITEQUWFxgf/aAAgBAQABPxC/M/DxhKnYC/w98DxIUX0uIGh0mW59EAuvcerV1ERbSAC60chP/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Crowbits kit" title="" 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" decoding="async" /> </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,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB6ElEQVR42pWRz2/SYBjH+aM8mIwxlUxiogeNiUdvXjQxMWzGzOES4+LExIOXZcvE6eZl/HArTWG2/FrIaCgyWDekhREtqMwFKevbUtq+ry2KotGDT76H53v4PN/nyWNDfy84JMMUtPRn2YbN/LNXN+/MTngeu6e9tz1et8d7667VTM08mZycDmOYNXVoiO1nigykFTzrz7RwpvVmV0zsH5NFkciLi3TrKSMvpivR2OY/kxUZZLLsFq9rpvmwCisL/fVVpqtjCsIlLcGWkKF/T/oFH0rqy532cqqBJbK+dBeoepquZXKceaqsqLnD7XA94K/6NrPhPvf72nRdGn8tXFwora5vL21p3FH3XUx4GxE0qHUVtdFmhE5k73MomYuY4BGA9Q5StAGcew8u4MeXlxrB6M76HvoIkMaTMhe3UqDxqQM7AALQo/PsbtOIVhFVQ1/AAC7UlKs++fpcc24+tkxWCmyZKxe5MlvmD0zRxSrNHsQZ/jnBrLDoRQGt7SOpN4DzJXDN05xwf7105YZz3Olyuc6eO+84dWbEPmofdYw4xsZOO0+ctN+7/8D8uKLBnvHjbgsW6tLDWf7RDB+jUokkSVJUPJ7EwhvB4Fog4A+FggSBRwg8laREsd2/BQ6/yjQ6Qhr6z/oGn7gwhz+FkvEAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Crowbits letscode software" title="" 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" decoding="async" /> </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" target="_blank" rel="nofollow noopener noreferrer">Application registration, service principal</a>, <a href="https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">Authentication</a></li> <li><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-vs-authorization" target="_blank" rel="nofollow noopener noreferrer">Authorization</a></li> <li><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-mfa-howitworks" target="_blank" rel="nofollow noopener noreferrer">Multi-Factor authentication</a></li> <li><a href="https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/what-is-single-sign-on" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABJ0AAASdAHeZh94AAACC0lEQVR42qWTS2/TQBRG83/5B6yQUBdly4IFogghUqnLIsRTiFJoqQJUaUrTRkmTOE7sJI7jd/zM4Y7bsOlDCK5kj+3xnPvd785UuIyCJXZHY7Z/xKQ3ICty/iUq6rZcKiBoOzW69zfQ9w5J/geoIglDAt/DNca4c4e+YRBEEXEQEMq4VFn/BugKqDEe82U45MxxKNIUQ8b1owYPz8+pTqZ8ME2yOOaimtvBlZ8CWmueclcAm90esSTwPI/v8zkv9CFVXadpWXjOnCRNLqDFzdCKLQs116UvoxcGxIsFM9siiQIW8q4MXsg305hw2mij9w1cz7lRaaUoinJRmsR4doDWNmk3dHrHU/TOVFTFROGCk4MBX18d8+NjC8cKiKLweuAqk+v4tGtTWt8mdGoWxmmAKwlCpVr867VGnNS6NA7adJoaY/E9Fb+vdvlS+SKKsQy3hPieAomXvluW6/s+eZ6hqimWRfms5jVNE2tiqS69um2U0ixPybK0XLBSPrNm2HKV1khkMqe21ZuzPZ79es3nUR1bGrb6v3KdD2mc0Bp2eVrb5tHuFpv1t/SH2sWJEnAgNjypb3Pn5ToP9p8zsE1WlV4LLLKcznRAtfmetd0N7n16zPG4TZ5k5bzaVpptsHX4js6oTygWFbcpVBGWPkZ0TY3hzMSVU7RqgmpSFEiX8yW5JM+y7I+HvwGcZeEyxjtYUQAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Azure Active Directory Security Principal types" title="" 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" decoding="async" /> </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/" target="_blank" rel="nofollow noopener noreferrer">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,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABJ0AAASdAHeZh94AAACBUlEQVR42o1SXavUMBDtv1Yf7oe7y15WEH3a+wU+CfsbBF2vD1fh+iAiKCirqNvWbZsmbfqRNk2Ok+xFFxSvA4dJhsmZMzMJThdP8PbjGu8+hfiwivBwvsD+ZI7D6QlGszOMZ+ce7jy5d47J9BQH4zn2xse4NTrB/uwR9ih2e3SMOxQPDp5z3H2a4nDJ8PiNwLOvGsvvFstvBhdrixchPC4IlzGweN/j6LLG9GWNMfmjVw3uX7V48Frh7IojWGUtwjhBynKIQkJ1Gnowf0Jv0TsMu36AbAeIpqezRhDzGlGaI+USvKx9UKnOE3fk9TCg6zpCT4QafU/oFHbNWuthjEGQ8xyMMbRti7qSSEWLXGoiV2AFnZ0vtz6nOyt7UmNQE6dUFnUHDxIITh0GhZSerO97KPJJkiHLsl/Vja++o8Yr2p6lrHw3xlgPIQoEWdVCE5kzpRREWVKiRF1XVKjB4FtWpL6iWO1zXGvOtO5pLMq/NzQOIYRTWIClKSoiGmhWiSgRRhGiKKZFMa98s9nQPUJKeaXLoyJ/s4qKBuvVF/z4vEJMEGGIhoKSHrkNmutEWVVe2U3mCgVJkoOTAkUkmlpyCpIkoXnWYLJD3gwYqLW2/d3qPwnLpkFRFv5LuNW7BfE8386Lvog2Fv9rnpDRIHnO0RBx68lLT+bvRG6vV2rtzcRO1E+OA4gdHm2BBwAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Enterprise Applications in Azure Active Directory" title="" 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" decoding="async" /> </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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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="19581576941696864000" data-toaster-class="gatsby-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; } ] }`, `19581576941696864000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Using Bicep it will be simplified to:</p> <div class="gatsby-code-button-container" data-toaster-id="83378654092479790000" data-toaster-class="gatsby-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' }`, `83378654092479790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> diagStorageAccountName <span class="token literal-property property">location</span><span class="token operator">:</span> location <span class="token literal-property property">sku</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> storageAccountType <span class="token punctuation">}</span> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'Storage'</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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="53294306213039145000" data-toaster-class="gatsby-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 } }`, `53294306213039145000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'bicepstorage2063'</span> <span class="token literal-property property">location</span><span class="token operator">:</span> <span class="token string">'northcentralus'</span> <span class="token literal-property property">properties</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="73658214581785805000" data-toaster-class="gatsby-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>`, `73658214581785805000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="62944884126366940000" data-toaster-class="gatsby-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`, `62944884126366940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="33567622693547983000" data-toaster-class="gatsby-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'`, `33567622693547983000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="43787735925740450000" data-toaster-class="gatsby-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; } } }`, `43787735925740450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="78296541307306200000" data-toaster-class="gatsby-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>`, `78296541307306200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="75869708988730700000" data-toaster-class="gatsby-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 //... }`, `75869708988730700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> storageAccountName <span class="token comment">//...</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">ARM template function</a> is also a valid Bicep function.</p> <div class="gatsby-code-button-container" data-toaster-id="65331181020683985000" data-toaster-class="gatsby-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')`, `65331181020683985000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></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="78816266952296380000" data-toaster-class="gatsby-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 } }`, `78816266952296380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> storageAccountName <span class="token literal-property property">location</span><span class="token operator">:</span> location <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'Storage'</span> <span class="token literal-property property">sku</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="64153537655130920000" data-toaster-class="gatsby-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`, `64153537655130920000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></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="95015330555116240000" data-toaster-class="gatsby-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> = {...}]`, `95015330555116240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="13482385385837836000" data-toaster-class="gatsby-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}' //... }]`, `13482385385837836000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">containerNames</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="12417934017992560000" data-toaster-class="gatsby-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 }`, `12417934017992560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> storageAccountName <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="51474139027401590000" data-toaster-class="gatsby-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`, `51474139027401590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">.</span> ├── main.bicep └── stg.bicep</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="45489524699301180000" data-toaster-class="gatsby-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 } }`, `45489524699301180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> storageAccountName <span class="token literal-property property">location</span><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 literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'Storage'</span> <span class="token literal-property property">sku</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> storageSku <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="60132925876469080000" data-toaster-class="gatsby-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`, `60132925876469080000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'storageDeploy'</span> <span class="token literal-property property">params</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">storageAccountName</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="15696117545730015000" data-toaster-class="gatsby-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') } } } } ] } }`, `15696117545730015000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'wordpress-containerinstance'</span> <span class="token literal-property property">location</span><span class="token operator">:</span> location <span class="token literal-property property">properties</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">containers</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'wordpress'</span> <span class="token literal-property property">properties</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token literal-property property">resources</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">requests</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">cpu</span><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> <span class="token literal-property property">memoryInGB</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">GitHub Actions</a> for your CI/CD pipeline, there is already a <a href="https://github.com/marketplace/actions/bicep-build" target="_blank" rel="nofollow noopener noreferrer">Bicep action</a> created by our developer advocate <a href="https://github.com/justinyoo" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">Visual Studio Code</a>, you need to install the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">Azure Functions Core Tools</a> and either <a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" target="_blank" rel="nofollow noopener noreferrer">Azure CLI</a> or <a href="https://docs.microsoft.com/en-us/powershell/azure/install-az-ps" target="_blank" rel="nofollow noopener noreferrer">Azure PowerShell</a> to create Azure resources. You can also use the <a href="https://azure.microsoft.com/downloads/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">Windows Terminal</a>) and initialize a new function using the init command:</p> <div class="gatsby-code-button-container" data-toaster-id="25155588810706320000" data-toaster-class="gatsby-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`, `25155588810706320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">func init myLocalFunctionProj <span class="token parameter variable">--dotnet</span> <span class="token builtin class-name">cd</span> myLocalFunctionProj</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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="72635970050452060000" data-toaster-class="gatsby-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;`, `72635970050452060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">func new <span class="token parameter variable">--name</span> HttpExample <span class="token parameter variable">--template</span> <span class="token string">"HTTP trigger"</span> <span class="token parameter variable">--authlevel</span> <span class="token string">"function"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="68477181705774326000" data-toaster-class="gatsby-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`, `68477181705774326000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">func start</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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="96038566687706990000" data-toaster-class="gatsby-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;); }`, `96038566687706990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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="25619186228691260000" data-toaster-class="gatsby-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;); }`, `25619186228691260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></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="83070115787007380000" data-toaster-class="gatsby-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;); } }`, `83070115787007380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="91237729633003980000" data-toaster-class="gatsby-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; } }`, `91237729633003980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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="52529296057922120000" data-toaster-class="gatsby-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;); }`, `52529296057922120000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="22465912551594824000" data-toaster-class="gatsby-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); } }`, `22465912551594824000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="12529905136236906000" data-toaster-class="gatsby-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); } } } } } `, `12529905136236906000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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/" target="_blank" rel="nofollow noopener noreferrer">you can find out about them here</a>. All you need to do is to select the <code class="language-text">Reference > 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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">Vue.js</a> application which is using <a href="https://auth0.com/" target="_blank" rel="nofollow noopener noreferrer">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="2282009942550145000" data-toaster-class="gatsby-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; }, }; }`, `2282009942550145000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We also implement a route guard in the same file:</p> <div class="gatsby-code-button-container" data-toaster-id="26336409144695750000" data-toaster-class="gatsby-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(); } }); };`, `26336409144695750000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">isAuthenticated</span><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> <span class="token literal-property property">loading</span><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> <span class="token literal-property property">user</span><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> <span class="token literal-property property">popupOpen</span><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> <span class="token literal-property property">claims</span><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> from<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> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'/login'</span><span class="token punctuation">,</span> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">returnUrl</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="97340914586159280000" data-toaster-class="gatsby-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'); });`, `97340914586159280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">domain</span><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> <span class="token literal-property property">client_id</span><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> <span class="token literal-property property">redirect_uri</span><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> <span class="token literal-property property">audience</span><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> <span class="token literal-property property">advancedOptions</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">defaultScope</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="57369245985930210000" data-toaster-class="gatsby-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>`, `57369245985930210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And in our component:</p> <div class="gatsby-code-button-container" data-toaster-id="44854511006129470000" data-toaster-class="gatsby-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); //... } } } //... }`, `44854511006129470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">methods</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="1303742981738564900" data-toaster-class="gatsby-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;`, `1303742981738564900`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><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> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'/login'</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><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> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'/admin'</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> Admin<span class="token punctuation">,</span> <span class="token literal-property property">beforeEnter</span><span class="token operator">:</span> routeGuard<span class="token punctuation">,</span> <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">authorize</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">role</span><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> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'/unauthorized'</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><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> <span class="token literal-property property">history</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="20742324209318298000" data-toaster-class="gatsby-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`, `20742324209318298000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">vue <span class="token function">add</span> e2e-playwright <span class="token parameter variable">--dev</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="66158802764054310000" data-toaster-class="gatsby-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');`, `66158802764054310000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="53762544221167420000" data-toaster-class="gatsby-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';`, `53762544221167420000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></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="94055674234599640000" data-toaster-class="gatsby-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; })`, `94055674234599640000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="8419483010305729000" data-toaster-class="gatsby-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); });`, `8419483010305729000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></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="97138346634436260000" data-toaster-class="gatsby-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(); });`, `97138346634436260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="14058504200565248000" data-toaster-class="gatsby-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\`); });`, `14058504200565248000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="6586465777419593000" data-toaster-class="gatsby-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') ]);`, `6586465777419593000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="3275099176181517300" data-toaster-class="gatsby-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;]');`, `3275099176181517300`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="50367040573900490000" data-toaster-class="gatsby-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;]'); });`, `50367040573900490000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/8QAFgABAQEAAAAAAAAAAAAAAAAAAwAF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAdJERBnl/8QAGRAAAgMBAAAAAAAAAAAAAAAAABMBAgMQ/9oACAEBAAEFAk0E5iciO//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAICAwAAAAAAAAAAAAAAAACRAjIBIDP/2gAIAQEABj8CrhFIo5xWn//EABsQAAEEAwAAAAAAAAAAAAAAAAABEBEhceHx/9oACAEBAAE/IU08rqfE5diN/9oADAMBAAIAAwAAABBcz//EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxAMn//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EAB4QAAIBAwUAAAAAAAAAAAAAAAERACEx0UFRYeHw/9oACAEBAAE/EMnwxoCzM9E3PJxA1RcACrqoxP/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Cosmos DB Emulator" title="" 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" decoding="async" /> </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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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="89479352997386290000" data-toaster-class="gatsby-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>`, `89479352997386290000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="38928701102676165000" data-toaster-class="gatsby-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; }`, `38928701102676165000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Don’t worry too much about the code, you can view the result <a href="https://pwa-dual-screen.glitch.me/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAADM0lEQVR42mWTX0zbVRTHf6/GN190zkh0xvkyp9kSZ8iyB43RqNmf6BaXvanbg7olOiYpGzIrMgbI3MoKFtJ12v1RUGBQMuiftbQw0KkJ2jhwDgobUPpntPyglPb38d7bsAc9yTf33HPuOff81TweD6FQiIHBQYLiDAQC+P1+gsEgQ0NDhMNhTCYTFRUVjIyMKPnAwICyWYXP5yM4GKA/1I+2vLxMLp/HAPLiXFlZQclyOQVJDocDp9Op+IWFBaHPCM7AMArIGzn02RwrKQMtFosxNjpKZGJcYILZaJREIkF0Lsac0N2ZmaG6pobPzWYmp6aYmY0SSyQLzkQAup4RrvNEx3Ri4/No1zxXaakqpe7YJ9Qe/ZjwHyOcc7YLBydwdbuwNJ5l06bNbCkuxlx1gq62Szisp0jG4yKbLB3trZyzn8dma8Lb50Lz9nTwcvFzrH/6KSpLjxDwuCl6vIiitWuoKi+j9up11r72Di/sfo+aVi+/XvMw3NXOVxUmOi86KDv4LpdOfkDJvlc4VV2JFvJ0s2HdI2x59hkO7HuLC85vefKxh9n56jZMnx5mf/VZtDXrefCJjex4v4Q2u5XmL4/y0Z7XOW4q5cXnN7L10Qd4SNM4dPAQ2q3RMM2Wk7Q01GITqfx18yZ+n5froQCjY2P4+9zsfGM7u3e9TXvrj1z+rpm6L8qwnK7D5fbS3Gil8rNyzOXH6OvtRZOdTd5LsZTJqC7KYuuLS6LYS6rrkpq+sd3v8qLQpdK60BnqLu1S6QVlJ0mTY3J3epop0UFd15WT27fHGZ+IqKJLqq+v54zFovhEPEEkEmFadF+OVTKZZHJykmh0TtlqUhgXj9LpNJlMRs1jQoxFWvyaNwoRWq1W7HZ7YQ7Fu1RKZLRUyCAl7nLMpL30pclQZZQS8oG8L2ezZAWkTJKlwUpjk03x8eQ80cQ9kvNpUZqM+NRQWC2Xxn9ICuXmrG5JbUsv6zbvYMPWPZgburD3BDnd2c95zxChP//GyC6KhfiHoNvF7zd+/r/DVVLrmMtyuecGL+3az5t7P+RC9zA/tH3PFXcfgV9+49bUXYZ9nXQ6z/D18RKudPzEv3hkVs/3QJxYAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Initial state of the application across two folds" title="" 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" decoding="async" /> </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" target="_blank" rel="nofollow noopener noreferrer">CSS screen-spanning media feature</a></li> <li><a href="https://github.com/webscreens/window-segments/blob/master/EXPLAINER.md" target="_blank" rel="nofollow noopener noreferrer">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="39061032481216240000" data-toaster-class="gatsby-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>) { }`, `39061032481216240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEDAgX/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/2gAMAwEAAhADEAAAAe3ma0XEF//EABsQAAEEAwAAAAAAAAAAAAAAAAEAAhAREhMh/9oACAEBAAEFAgONEbKWdJpsf//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAAMBAAAAAAAAAAAAAAAAAAAQEYH/2gAIAQEABj8CNUip/8QAGxAAAgMAAwAAAAAAAAAAAAAAAAERIUExUWH/2gAIAQEAAT8hRChDTrQqmCXAoT5XZNej/9oADAMBAAIAAwAAABBDH//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxDGW//EABsQAQACAwEBAAAAAAAAAAAAAAEAESExcUFR/9oACAEBAAE/EGshUllhwZ7DY4F6OE9I0u4Ql1rt9bjMAXocJ//Z'); background-size: cover; display: block;"></span> <img class="gatsby-resp-image-image" alt="double portrait" title="" 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" decoding="async"> </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="23458042570962158000" data-toaster-class="gatsby-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 */ }`, `23458042570962158000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAcABQDASIAAhEBAxEB/8QAGQAAAwADAAAAAAAAAAAAAAAAAAECAwQF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgAB/9oADAMBAAIQAxAAAAHtOGssAyrFCtgA3//EABsQAAICAwEAAAAAAAAAAAAAAAACAREQEjEh/9oACAEBAAEFAqKgUujYTkYUbybkXn//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAYEQACAwAAAAAAAAAAAAAAAAAAARARIf/aAAgBAgEBPwHRlR//xAAbEAACAgMBAAAAAAAAAAAAAAABEAAhAjFxMv/aAAgBAQAGPwIs0Z5yR6j2UZtf/8QAHxABAAIBAwUAAAAAAAAAAAAAAQARMRAhQWFxobHh/9oACAEBAAE/IQKk5nSmL3l0Lt8kv8orTVb4Z7mos1mm8s//2gAMAwEAAgADAAAAEPM9A//EABcRAQEBAQAAAAAAAAAAAAAAAAABETH/2gAIAQMBAT8Q2JxqP//EABgRAAMBAQAAAAAAAAAAAAAAAAABMREh/9oACAECAQE/EGhRp9HT/8QAIBABAAIABQUAAAAAAAAAAAAAAQARITFhkdEQUXGx8f/aAAgBAQABPxC7E3LWafdgozIYQJMfwCvc+M5llKz7h1DL5IigC3VHE1uxxDQVVSqz/9k='); background-size: cover; display: block;"></span> <img class="gatsby-resp-image-image" alt="double portrait tall" title="" 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" decoding="async"> </a> </span> <br> <i>Image from Microsoft Surface Duo blog</i> </p> <div class="gatsby-code-button-container" data-toaster-id="21148936908590030000" data-toaster-class="gatsby-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 */ }`, `21148936908590030000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB3ElEQVR42q2UW2/TQBCF8/9/QN+hqLRSH5om6iXlJipBqQkukAoqlQcQimsnjr2O92Z79zBrp3WilAdQIh3Fm3Pm02y8sx1s9qM7f3PKQkPwHFJwaK2hhKTnHFopWGtXsvYxYFEBibRIF5pkGneJIEmkuUTCFYKZQMQUEmEecq6mqBqkcUCzwJ/eaHRHgr4lTr5LnJIGN4rWAv3+GN1zhhe3mtaq9usMZQ+vBY6/qZpRGQLed9/7IsGoE6UVpGokpKa95+gd/MbLs4nbEbhsfZfNOEE/i6bDZeDhtcR0LjGngkw0YlzTfynQPQkweBPDGo2Ut77LxlTjdrYOHEnEmUROoblolAmNLJ2iexTgjIAgIOOt77KzfwWGwS8cHI03B4wn4812yJKIgP/RYY9+jFJBBc25q88ehZXiNXDwekovqAHc+y47YeJxYJ/eMlcaVVWgLBsVZUljINE/DvDq7cwdf+ii9SuSpCnqrQMNdjyGJ+9j7Hkxdi9b7XlTbO38wPbuT+z7CZ5/WPZiPKWaZ5dpPYA10D0ZY2wYRtbzR/bio0+6etA778oOP5GGvj2/GK54Tp7/1d6FoV3Mt+osj7jbgrsUluUuB8YYKcU8Y2sZt7bWrFwO6YbESNEfIWe+R5no2JIAAAAASUVORK5CYII='); background-size: cover; display: block;"></span> <img class="gatsby-resp-image-image" alt="env variables" title="" 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" decoding="async"> </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="56358940640027200000" data-toaster-class="gatsby-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) ); } }`, `56358940640027200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></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,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAADZUlEQVR42jWTf0zUZRzHv1tbf2T/9l+mJisn5aJEslqb0A9NTGlDREFOLGuSjUlsmjLzlF/eQqh2XB3e8dPZBNoyaWvQwgx/wRXcsk4QbhcH3HHHwf3gfvA9Xj3PN/1snz3vPfs878/z7PN6FJfLhd/vJxgKEpif17TP5yMQCBAOh5FhNBppamrStNxfWFhgXtQ+TK/Xq52ZmZlBCYdDLC5GiMaiRKNRTUsjqWOxmGZiNptpbW3VdDAUIhaPs7S0pKWqqlqd1MlkEsXnD3B/bAL35BRu9zTT016RM/w7Ocnk1BQhYW4ymTAYDMzNzeFw3GN0dJR4PCaaLxISDSKRiLZKY2XYs0RFf5D6a37aBjxcsgUZcTiZmJhgfMIpnjHL10YTac8/R9lHOs6U5FC0awt11Xr27MnlmXUpbExPY9WalZwz1KJcv+chz2wjr8vJjtb77PxikLauq9hH7IyOjTNw4xYVp/Ssfmol+bu2c7xoK3lvbORE2RFey87h8bUbWJWRxWNr1nOyShj+5XBQpS8n9/xlHvlskCf3X6b2fCN37gwy9Ied6poaig9+wLNrV3NIt5sDeW+hy93KyfJPeK9gH2mvbCIr+x0yXn2J+i/rUMb+GaKtsYLO9gZSCit5QhgePa6nWLePko9LyMx8ndTUdbycsZnaSj3HSos5fGAvJz4tJX1TGoqisGLFo9paVlaK4p50cvPGdZxjw3R2f0dDRz9Xf/qZczVnBS5f0d7WQkHhXj4/XcXdv8e5PXAT+6ANu20Ic9O36M+epr6hjsrqM/T90ociRz0762MusCCmFCepJgQCqmAtKPCJaKi0tLRgsVhQBRqSQ4mOrJFTlTqeSJAQuby8jKKqS8LQi8fjxS+wkIzFRc4KUOWejObmZi5YLqCKAx4BsURJTaoaKl5xGQm1ZFfjULomH6TUMiSksrP8OdoNpaG1+X+w54MkEyrLAuhoNEbkwSd4CLmyGAnya4+VW/3d/Hm7F/+si2/MJjK3ZVF06CD5ugLWv5BKYXY+3aV67oqB2Roacff2sS1nO+lbNvCu7k1SXnyaSkMlSiQUoLfnIr3XRvjtd5v4yzNc6fkRo6kRi9WCtdnK2zt3UCPQcf3wPc7Oi7i7OogMD1B+7AjvH97N0VMfsl+XQ3uHhf8AA7EptbMAzswAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Half aligned with columns reducing from 5 to 4" title="" 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" decoding="async" /> </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="84795445177694290000" data-toaster-class="gatsby-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)) ); }`, `84795445177694290000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAADTElEQVR42n2TXWxTZRjHz50x4cYbryRcIUYdUSLLiCQmfmTG8bE5XFyjbpqAkZgwx8bYCAQTCSbMqVHrate1tVpxTFQ6yigbZQKyqUO2lanRQem6fq09/e45Xdv9PO+JF1z5T568/+e8z/95npP8XykQCJBIJMhkMyRTKZ3H43GSySS5XA4Bo9GI2WzWubhPaXV3RywW0zWRSARJiAqFAoqq6iF4NptDUVRULRcQzex2u87z+bz+/e4QPRRFoVwuI8myjN/vJxhcYjEYJBQKEY0tE47GiGihqEX6TSacTqfeUIj+D1JCTjLn+4N/Fm6zcDvAUihCsZAnKy9TyKT1IssX/fQPWhGtoukMy9ofpLWNookUi7EEwWWZQCRBMptH8oz9xPM7Wmnd3cX+/Ud5v3cA19BXeC3Hmf6mj8BFB++9ZaCpex/GyVFOXBim2+XEOnmJJwwHkGqaua/2TaTHd9Hx6ddIP5xxs2XL0xjq62nc1kBLy14cVjOnB07w+xk7U99+RGv9Mxw50Mz5sx/ymfEQp5xHuHblJI80tiE9uo01TzYjra/lnd5BpPMeLy9tf5HXGxuoq91OR3sPVtPH9PXs5qqzj6uOYxh2PEV7ax29h9/mDcPLHNprYMploqa5nTVrq1n34FakDc/S+YEFacTlpmrjZqqrt7Lp4Sp27Wzi6LHDvPpKLe17dtKxp46azevZ8FAVLQ11NL3wHJseq+ZgZ5dW+xqSdD/33rOWdQ9spOf4J0iLgUW+Gz7NyIgbj2eciUsTTP72C0M/DjN6wc3MzK90dnXQfbCb+emfmbg4hndsjLkbNzh3bhzbl0MMf+/m5CkX07PzSJVKRfNdVvfTysqKbgsRmUxW96OA8KDNZtN5Ll9ALRYpa7qiduZzeUqaTmhXV1eRSqWS5vAooXAY4UlRpKiK5sEoce1VCFitViwDZlaKqu5TtaANWq2Q0oZGYnFiCZlsXhi7om2odS39t5WYICDyVCqNz+fTc4fDgcliR9wmswWCKZVoRkFJyyQjS6SjQUo5mUpZRRKCmzdnmfB6GHLacLvPUqrA/J9/07avjYVbfswDg7zb+zm+sMro9TsMXvYzOhfmzl/Xmbk2zq1ZL3J4iqIS419hR0Qzjab1/wAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Header aligned with using margin calculated based on fold size" title="" 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" decoding="async" /> </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="79395705558282490000" data-toaster-class="gatsby-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; } }`, `79395705558282490000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAADF0lEQVR42n2TTUxUVxTH38q46Zak7hoauyDRjcFFAyHR1LQaacrChQlpm5J+LHQlKqEapQoRUgIxQxNghhmYSFEEhvAhhmDwYwA/OswosZHawjDO+IaZeW++38DMr/e+icRuepKbe+557/7vOff8ruL3+9nc3CSeSBCNaUSEL9exWIxkMok0i8VCd3e36UciETRN+89QVdXcEwqFUOSmdDpNJps1RyqVMoUymQxZsZbW3dNDX1+f6adSxW/vj4RIRmpsbW2haLqO3/+GYEgl9LY4ZHbyxHA4TC63hc1mw+l0moLb29v8n4kM4wQ2/iYUXBeiAVGSStrIkcgaZMQszdHfL0ruknLiMJVoVCWux1h9tcry8gt8vhW8nuciFkdJ6wFW/xjFe38AbW0Osq8ZujNHs+Mmw48e83xTo6nDQsvVs2z4H+PxzLC0NMqi+w4VByrYvetD9pR8zOH9nzAxOony0rPAb20NDNvbmL/VytqTEa5ct3P8pwYaLU6ssx6+b2jGbu2Egrj4gJfA2gK+5YfUffk5ZaVlHK6q5Ny3NYwPj6N43XN0tZzF0vYzltZzPLh7i3ZbM1/UVfJ141d811pL1YlDdHVeJhxc5Kl7ENfNFqYnnNTXnaTm6FEunz9N7bEjuEzBZwtcb7vA1Yv1NDWcYnrkBpd+/YHyYx9w/Ju9VP9YSvlnH9F+rZHQhpvlJ2PMTnZxd+p39u+roKRkL1UHK6j+tJyJsaliU9b/+Yuw+gYtGkaPRc3m+FY8vHr9J/GkRkdnB729PaLDOXRdwzAyApMUz556ePRQlO/xsbqygiY4ViQGmhYXYCfR4wlygiWJioxpMd3scr/ostVqFYJ5Aa+6A7zkNJ1Jm3NWEFEoFFAkjFHBXUwQL+HM5/MC0Jz5cuQrkGZ32OkVgtKkmPxHbo6LBCKRKJJlwzDMuCI/SCefL+zAWVznTfJNDh0OBgYGTP9dTO57f37nK8GgX4C9ji5Kdi8tMDM7Y5ZmGPK+iiXbbHZ+aTrDg3kXI8N2ZqaHBI+LDA4O0T/k4vbkPW64ZvEHw/wL8+Nxh5KXN5MAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Columns aligned on the two sides of the fold" title="" 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" decoding="async" /> </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="16650381349012777000" data-toaster-class="gatsby-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`, `16650381349012777000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="72655717662005600000" data-toaster-class="gatsby-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; }`, `72655717662005600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/8QAFgABAQEAAAAAAAAAAAAAAAAAAwAF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAdJERBnl/8QAGRAAAgMBAAAAAAAAAAAAAAAAABMBAgMQ/9oACAEBAAEFAk0E5iciO//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAICAwAAAAAAAAAAAAAAAACRAjIBIDP/2gAIAQEABj8CrhFIo5xWn//EABsQAAEEAwAAAAAAAAAAAAAAAAABEBEhceHx/9oACAEBAAE/IU08rqfE5diN/9oADAMBAAIAAwAAABBcz//EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxAMn//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EAB4QAAIBAwUAAAAAAAAAAAAAAAERACEx0UFRYeHw/9oACAEBAAE/EMnwxoCzM9E3PJxA1RcACrqoxP/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Starting Azure Cosmos DB Emulator" title="" 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" decoding="async" /> </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" target="_blank" rel="nofollow noopener noreferrer">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="68190665757595830000" data-toaster-class="gatsby-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`, `68190665757595830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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//aAAgBAQABBQJYVa8xmYRPjz//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAcEAABAwUAAAAAAAAAAAAAAAACADKRECIxUXH/2gAIAQEABj8CG0caTAhMGEHK/wD/xAAdEAABAgcAAAAAAAAAAAAAAAAAARARITFBobHx/9oACAEBAAE/IVziy1KXgcgYHT//2gAMAwEAAgADAAAAEOAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHRABAAEDBQAAAAAAAAAAAAAAAQARYfAQQVHB0f/aAAgBAQABPxA+uVUK1oWnUh8hv41pn+Gv/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Azure Cosmos DB Emulator connection string page" title="" 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" decoding="async" /> </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="53941591170971120000" data-toaster-class="gatsby-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`, `53941591170971120000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> init <span class="token parameter variable">-y</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The next thing to do is to install the dependencies:</p> <div class="gatsby-code-button-container" data-toaster-id="47788469438264380000" data-toaster-class="gatsby-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`, `47788469438264380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="5506122035429128000" data-toaster-class="gatsby-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, () => {});`, `5506122035429128000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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> <span class="token literal-property property">extended</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="81589217696579060000" data-toaster-class="gatsby-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;); }); });`, `81589217696579060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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> <span class="token literal-property property">extended</span><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> <span class="token literal-property property">useNewUrlParser</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="50961737180493100000" data-toaster-class="gatsby-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; }`, `50961737180493100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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 'cosmos_emulator_mongo'</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="72546755292583010000" data-toaster-class="gatsby-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; }]`, `72546755292583010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="44694522472383504000" data-toaster-class="gatsby-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\`); } }); } ); });`, `44694522472383504000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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> <span class="token literal-property property">useNewUrlParser</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">sslValidate</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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('fs')</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="13515757457019628000" data-toaster-class="gatsby-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); }); });`, `13515757457019628000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="59893236012640210000" data-toaster-class="gatsby-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`, `59893236012640210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">-X</span> GET http://localhost:5000/api/celebrities</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAde86oC//8QAFxABAAMAAAAAAAAAAAAAAAAAAQAgQf/aAAgBAQABBQIJlP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABoQAQADAAMAAAAAAAAAAAAAAAEAEBExYZH/2gAIAQEAAT8hDv2ZoKAIcV//2gAMAwEAAgADAAAAEK/P/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/EIF//8QAFhEAAwAAAAAAAAAAAAAAAAAAARAR/9oACAECAQE/EKV//8QAGxAAAgIDAQAAAAAAAAAAAAAAABEBIRAxcUH/2gAIAQEAAT8QeWnZQJSWPAslTgz/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Opening clipboard settings on windows" title="" 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" decoding="async" /> </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><img src="/1c3782258e317f014eda43682c3642ad/clipboard-settings-windows.jpg" alt="Clipboard settings on windows"></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/8QAGAABAQEBAQAAAAAAAAAAAAAAAgADAQX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB9dLqYyhaBrlUf//EABsQAAICAwEAAAAAAAAAAAAAAAACATEQEiER/9oACAEBAAEFAtTUnk8k8GtKGvDX/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAFBABAAAAAAAAAAAAAAAAAAAAMP/aAAgBAQAGPwJP/8QAGxAAAgMBAQEAAAAAAAAAAAAAAAERIVEQYfD/2gAIAQEAAT8hXyRWFoViSZUkcZ5GNWXvaFnL/9oADAMBAAIAAwAAABAP3QD/xAAVEQEBAAAAAAAAAAAAAAAAAAARIP/aAAgBAwEBPxAj/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHhAAAwEAAgIDAAAAAAAAAAAAAAERITFRQWGBkfH/2gAIAQEAAT8Q8idoppxd1CKETkgRlxgltOk7hwyMN+4z5J+Bc13BiksfQqSxTD//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Windows clipboard history" title="" 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" decoding="async" /> </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/2gAMAwEAAhADEAAAAdfi0oSkYLWV1rAP/8QAHBAAAwABBQAAAAAAAAAAAAAAAAECAxARITFB/9oACAEBAAEFAtkTWWqfAumho8GLRn//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAaEAABBQEAAAAAAAAAAAAAAAAxAAECETAy/9oACAEBAAY/Aipc0wz/AP/EABsQAAIDAQEBAAAAAAAAAAAAAAABESExQVGh/9oACAEBAAE/IVS39i1SSSyd+GC7Ak4JuFmCmFovrN6LRBs//9oADAMBAAIAAwAAABCv6wz/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREQ/9oACAEDAQE/EIR7/8QAFhEAAwAAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/ECv/xAAcEAEBAAMAAwEAAAAAAAAAAAABEQAhMUFRYXH/2gAIAQEAAT8QngL0jWQFmVCqV81VPZktHgv7gBs6LueMRCO/W4wIuec5kISuGmm/M59awo0cyPRhJ0cz/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Pin items in clipboard history on windows" title="" 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" decoding="async" /> </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." target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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." target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">C++</a>, <a href="https://en.wikipedia.org/wiki/Turbo_Pascal" target="_blank" rel="nofollow noopener noreferrer">Turbo Pascal</a>, <a href="https://en.wikipedia.org/wiki/FoxPro" target="_blank" rel="nofollow noopener noreferrer">FoxPro</a>, <a href="https://en.wikipedia.org/wiki/Delphi_(software)" target="_blank" rel="nofollow noopener noreferrer">Delphi</a>, <a href="https://en.wikipedia.org/wiki/Active_Server_Pages" target="_blank" rel="nofollow noopener noreferrer">ASP Classic</a>, <a href="https://en.wikipedia.org/wiki/PHP" target="_blank" rel="nofollow noopener noreferrer">PHP</a>, and many other languages and ended up with, and finally <a href="https://en.wikipedia.org/wiki/ASP.NET_MVC" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">ASP.Net web forms</a> and <a href="https://en.wikipedia.org/wiki/Spring_Framework" target="_blank" rel="nofollow noopener noreferrer">Java Spring</a>, <a href="https://en.wikipedia.org/wiki/Java_Card" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">Vue.js v3</a> app with <a href="https://tailwindcss.com/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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="99794607296837730000" data-toaster-class="gatsby-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`, `99794607296837730000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> @vue/cli <span class="token comment"># OR</span> <span class="token function">yarn</span> global <span class="token function">add</span> @vue/cli</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="1733699455177473000" data-toaster-class="gatsby-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`, `1733699455177473000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">vue create vue-tailwindcss</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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/2gAMAwEAAhADEAAAAcSYxaA//8QAFhAAAwAAAAAAAAAAAAAAAAAAARAx/9oACAEBAAEFAkJ//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BZ//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPwGMf//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABkQAQACAwAAAAAAAAAAAAAAAAEAEBEhUf/aAAgBAQABPyEc8gbq/9oADAMBAAIAAwAAABCH3//EABURAQEAAAAAAAAAAAAAAAAAAAEA/9oACAEDAQE/EEjDf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxACSNv/xAAbEAEAAgIDAAAAAAAAAAAAAAABACERQVGRwf/aAAgBAQABPxB9OkED5GFjN8z/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Vue CLI wizard" title="" 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" decoding="async" /> </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/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHGkVNYH//EABUQAQEAAAAAAAAAAAAAAAAAAABB/9oACAEBAAEFAkf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAYEAACAwAAAAAAAAAAAAAAAAABEQAQYf/aAAgBAQABPyHYS0r/2gAMAwEAAgADAAAAEIAP/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAh/9oACAEDAQE/EB2f/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGhAAAgIDAAAAAAAAAAAAAAAAAAERMSFRkf/aAAgBAQABPxB1JYI9lRC0+n//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Vue CLI wizard" title="" 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" decoding="async" /> </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//2gAMAwEAAgADAAAAEIgv/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/EIXX/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAx/9oACAECAQE/EDS//8QAGhAAAQUBAAAAAAAAAAAAAAAAAQAQESExQf/aAAgBAQABPxDK0ROVzxt//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Vue CLI wizard" title="" 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" decoding="async" /> </span></p> <p>I would normally choose <a href="https://www.typescriptlang.org/" target="_blank" rel="nofollow noopener noreferrer">TypeScript</a>, <a href="https://babeljs.io/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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="52672046323650900000" data-toaster-class="gatsby-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`, `52672046323650900000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> tailwindcss</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="74624732028545840000" data-toaster-class="gatsby-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;; // ...`, `74624732028545840000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="3017714544803751400" data-toaster-class="gatsby-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;;`, `3017714544803751400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="77856081723483770000" data-toaster-class="gatsby-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;: {} } }`, `77856081723483770000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">their free gallery</a> in:</p> <div class="gatsby-code-button-container" data-toaster-id="96884515552698300000" data-toaster-class="gatsby-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>`, `96884515552698300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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/aAAwDAQACEAMQAAABtYZVJJNM3//EABsQAAICAwEAAAAAAAAAAAAAAAECAAMSITEz/9oACAEBAAEFAtku+Mco5l3LvT//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFX/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/Aax//8QAGxAAAgEFAAAAAAAAAAAAAAAAAAEREBIhgaH/2gAIAQEABj8Cw+Gi5ypoxn//xAAaEAEBAAIDAAAAAAAAAAAAAAABEQAhIFFh/9oACAEBAAE/IawDTjZEej7hi0LLJwQ//9oADAMBAAIAAwAAABBE7//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxANtF//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQIBAT8Qph//xAAbEAEBAAIDAQAAAAAAAAAAAAABEQAQITGBof/aAAgBAQABPxA6CZFcYqcIUS1XiZBwavTqTzXwGt//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Tailwindcss components" title="" 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" decoding="async" /> </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="88769458069522970000" data-toaster-class="gatsby-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`, `88769458069522970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">npx tailwind init</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="72057123636222660000" data-toaster-class="gatsby-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: [], }`, `72057123636222660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">future</span><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> <span class="token literal-property property">purge</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">theme</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">inset</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'0'</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">auto</span><span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span> <span class="token string-property property">'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> <span class="token literal-property property">extend</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">variants</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">plugins</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="7477525268949048000" data-toaster-class="gatsby-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>`, `7477525268949048000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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/aAAwDAQACEAMQAAABuzwdYT//xAAaEAEAAQUAAAAAAAAAAAAAAAADAAECERIh/9oACAEBAAEFAu5ZKwbti//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAERAiH/2gAIAQEABj8CI1yGWf/EABgQAQEBAQEAAAAAAAAAAAAAAAERACFB/9oACAEBAAE/IQqqzILbVR93LZTf/9oADAMBAAIAAwAAABALz//EABYRAAMAAAAAAAAAAAAAAAAAAAEQQf/aAAgBAwEBPxAKv//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/EFP/xAAbEAEAAgIDAAAAAAAAAAAAAAABESEAMUFhwf/aAAgBAQABPxDYAUVGVIEJIFkc9YJ6EMLOq8z/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Customise Tailwindcss" title="" 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" decoding="async" /> </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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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="66304936248032820000" data-toaster-class="gatsby-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`, `66304936248032820000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></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="75213685633552400000" data-toaster-class="gatsby-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);`, `75213685633552400000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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> </ol> <ul> <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> </ul> <ol start="6"> <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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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="1131058203578616600" data-toaster-class="gatsby-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. })`, `1131058203578616600`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">video</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="72195198049138920000" data-toaster-class="gatsby-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];`, `72195198049138920000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="58438649013737030000" data-toaster-class="gatsby-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 }] });`, `58438649013737030000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">advanced</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">zoom</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="98025868447745600000" data-toaster-class="gatsby-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);`, `98025868447745600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="73348997006117010000" data-toaster-class="gatsby-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));`, `73348997006117010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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="94371983663242280000" data-toaster-class="gatsby-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'));`, `94371983663242280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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/" target="_blank" rel="nofollow noopener noreferrer">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="71402031829646350000" data-toaster-class="gatsby-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'));`, `71402031829646350000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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> <span class="token literal-property property">threshold</span><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> <span class="token literal-property property">trackVisibility</span><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> <span class="token literal-property property">delay</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAB603ioq3FYJvQH//EABoQAAICAwAAAAAAAAAAAAAAAAITAAEQEiD/2gAIAQEAAQUCSEUEUONr5//EABgRAAMBAQAAAAAAAAAAAAAAAAISUQAQ/9oACAEDAQE/AVGZRnf/xAAYEQACAwAAAAAAAAAAAAAAAAABEQAQUf/aAAgBAgEBPwFmM7f/xAAXEAADAQAAAAAAAAAAAAAAAAAAATEg/9oACAEBAAY/AoiIiLr/xAAZEAEAAwEBAAAAAAAAAAAAAAABABExEEH/2gAIAQEAAT8h9O1eXBZSMBreGwyf/9oADAMBAAIAAwAAABCEGAD/xAAYEQADAQEAAAAAAAAAAAAAAAAAAWGREP/aAAgBAwEBPxCDCTELn//EABURAQEAAAAAAAAAAAAAAAAAACBh/9oACAECAQE/ELif/8QAHRABAAMAAgMBAAAAAAAAAAAAAQARMSHRUXGh8P/aAAgBAQABPxASrC7d9xDfv3P3PcRWlw1hHtJvjIkNyzwROdZpMPU//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Kill Chrome task in windows task manager" title="" 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" decoding="async" /> </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="" 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" decoding="async" /> </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/xAAYEAACAwAAAAAAAAAAAAAAAAABAgAgQv/aAAgBAQABBQLVi4DT/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/AYuT/8QAFxEAAwEAAAAAAAAAAAAAAAAAAQIQEf/aAAgBAgEBPwGKNn//xAAYEAACAwAAAAAAAAAAAAAAAAAQESAhkf/aAAgBAQAGPwJTV4P/xAAbEAABBAMAAAAAAAAAAAAAAAABEBEhMSBBYf/aAAgBAQABPyF4sNXrMAOR6T//2gAMAwEAAgADAAAAEODIfP/EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxCMNJ//xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8QgrGf/8QAHBAAAwEAAgMAAAAAAAAAAAAAAAERIRAxQWGR/9oACAEBAAE/ELWBbPHxb2Rmi4Yn4EZYpGLfch2f/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Chrome bookmark all open tabs" title="" 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" decoding="async" /> </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//EABYQAQEBAAAAAAAAAAAAAAAAACABMf/aAAgBAQAGPwIXT//EAB4QAAICAAcAAAAAAAAAAAAAAAABESEQMUFRYYHw/9oACAEBAAE/IaOmTwz2yYJ23c4LPQbgI//aAAwDAQACAAMAAAAQo888/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAIBABAAICAQQDAAAAAAAAAAAAAQARITFRYXGBkaHR8P/aAAgBAQABPxC1bnENuY/dYIKPi+5e2l9oDHvaODsOvEL5fUzVmnEoA4mk/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Chrome open all pages in bookmark folder" title="" 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" decoding="async" /> </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" target="_blank" rel="nofollow noopener noreferrer">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/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHtzRKpf//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEAAQUCX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABUQAQEAAAAAAAAAAAAAAAAAACAx/9oACAEBAAY/Aov/xAAbEAADAAIDAAAAAAAAAAAAAAAAAREQITFBUf/aAAgBAQABPyF26ovqElB8kT6x/9oADAMBAAIAAwAAABD0D//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EIf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFhcf/aAAgBAQABPxCplKrxCJGlvzqdJzuwXcUyc5s/YT//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Chrome Tab Session Manager extension" title="" 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" decoding="async" /> </a> </span></p> <p>It also has <a href="https://microsoftedge.microsoft.com/addons/detail/jkjjclfiflhpjangefhgfjhgfbhajadk" target="_blank" rel="nofollow noopener noreferrer">Microsoft</a> Edge and <a href="https://addons.mozilla.org/ja/firefox/addon/tab-session-manager/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer"><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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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 style="counter-reset: linenumber NaN" class="language-text line-numbers"><code class="language-text">#:~:text=[prefix-,]textStart[,textEnd][,-suffix] context |-------match-----| context</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="98112228408205020000" data-toaster-class="gatsby-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>`, `98112228408205020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>And you can test it live by <a href="https://yashints.dev#:~:text=Meet&#x26;text=Yas" target="_blank" rel="nofollow noopener noreferrer">clicking here</a>.</p> <p>If you want to target an exact text:</p> <div class="gatsby-code-button-container" data-toaster-id="41635310244543860000" data-toaster-class="gatsby-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>`, `41635310244543860000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p><a href="https://yashints.dev/#:~:text=almond%20croissant%20addict" target="_blank" rel="nofollow noopener noreferrer">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="22870775088101425000" data-toaster-class="gatsby-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>`, `22870775088101425000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p><a href="https://yashints.dev/#:~:text=Although,web%20developer" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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></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="61634438745636900000" data-toaster-class="gatsby-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>`, `61634438745636900000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="49639291383592020000" data-toaster-class="gatsby-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>`, `49639291383592020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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 special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">goTo</span><span class="token punctuation">(</span><span class="token string">'elsewhere'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="17769167555962274000" data-toaster-class="gatsby-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>`, `17769167555962274000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">goTo</span><span class="token punctuation">(</span><span class="token string">'elsewhere'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="10158887898293090000" data-toaster-class="gatsby-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>`, `10158887898293090000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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('elsewhere')<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="20464825775575470000" data-toaster-class="gatsby-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>`, `20464825775575470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">goTo</span><span class="token punctuation">(</span><span class="token string">'elsewhere'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="20310331769892940000" data-toaster-class="gatsby-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>`, `20310331769892940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">goTo</span><span class="token punctuation">(</span><span class="token string">'elsewhere'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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="75365862597122970000" data-toaster-class="gatsby-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`, `75365862597122970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-text line-numbers"><code class="language-text">http://example.com/old-school-url example.com/page#section</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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/Ca1DAAAACXBIWXMAABnWAAAZ1gEY0crtAAACf0lEQVR42oWSy0tUYRTAvyiynVgoGdW/UIuWURSuWrZyUas2rqJltAl7mFQUhJhFr8EcNbOHaWGJJkYJpUL2UEdtUGfmzp3nnevMfc2dX2es3BT0we9+F845P8459yoVtFFBC9UuBAqoe3nUbRPVkkZdS6AuaajGCOpMGHUqhGr4hjo2iTo6jjryDlU3ijo8gjo4xIb9r1GqS4TdNpU9eaq6TSo7slQ9zFETzFMdMKm5k6O6JcnWyzFqG+fYdXqCuitfqb/xjfrrwtUv7Dk5xu4Tw+w6Xhb2OGzutRkJaWi6ztT3eSa+zjIbjjC/FCUUXmJ6ZpZP0zNMzS2xHIkQjUWIaSskdQ3DSKMl4qSNFJOzURH2ulQ8dxhfiGFJ0C36pNNp3n8YZzUVJ7UyR1b7QSq+Qsxw0LWyMIqRMzEFx3Hx/RLyYG7JEOEzjy0vPCZXUuQlwdAXMJMiyBjYVgHbcUQYJhmPoJkeuh4hm01j2w6u64rQwbIsKPmElnMi7POoGHCZ1k18CSaiITJ6WEQuBRFaUpjPJshkUkQNG8918LyiNOSvU5SpymcxsirCfhG+8vgcz4FrEVpcJiy7K59yMiUZhxKOFGmGxb/OWsq6cKBExaDP94QJBdmJbVEqemsjrIMvu/WI5ez/CM1fHW4ccNg3mufAmPCuILfwVt6HhcEch15m2dudpPVjQso8HBm5WPyDLyv4NXJoufxRhkANC0O/eSMMCv3CE6HTZ1NA/tXrqzSN59cKf9f/1eFCeeTtzS+ovdhLbVMvNY3d1Jx7xLYLT6lq6mNncx87zkv87ACbGgLUNwdp7+ii9X4nbQ+6uHmvc41bgce03Q1yuSXITwrK0wP0OV5KAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Linux GUI in Windows Subsystem for Linux" title="" 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" decoding="async" /> </a> </span> <em>Image from <a href="https://devblogs.microsoft.com/commandline/the-windows-subsystem-for-linux-build-2020-summary/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer"><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" target="_blank" rel="nofollow noopener noreferrer">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="34265453275249103000" data-toaster-class="gatsby-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`, `34265453275249103000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">WinGet <span class="token function">install</span> powertoys</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></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/2gAMAwEAAhADEAAAAZa8ZDEH/8QAGBABAQADAAAAAAAAAAAAAAAAAwIBBCD/2gAIAQEAAQUC1owlOBwPH//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAICAwAAAAAAAAAAAAAAAAECABEgUXH/2gAIAQEABj8CIbUZhV9x/8QAGhAAAgIDAAAAAAAAAAAAAAAAAREAICFBUf/aAAgBAQABPyFFiGxmEG4Vf//aAAwDAQACAAMAAAAQ9M//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAwEBPxCn/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHRABAAIBBQEAAAAAAAAAAAAAAQARMRAhQVFhof/aAAgBAQABPxBaVYLDnxJZEESw5DFxpcfYqm6yjo0//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Powertoys run launcher" title="" 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" decoding="async" /> </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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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/" target="_blank" rel="nofollow noopener noreferrer">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" target="_blank" rel="nofollow noopener noreferrer">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,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABJ0lEQVR42pVSW26EMAzk/hfpDVZUosfoflWqBAgtDc8AIeGR2Uy6Qajbj9aSFTu2x2MnkbUW+76DMgwDvsoSbdt63bYNjIecfV0gBg0xahhjoLSBdifzKFVVIaLBAkqapnhLErzGMeLLBW3TIMR35tgNyafEy7XDR6PxLmb0yjDB59V1/Q0YJLA5mjzs4K/rimVZPLPZqXE2/TDhAWh/FD4BnwC11qgrgfJ2Q991/u4J8C9CWO6Ke8rzHFmWoQuA55GllD6JAS6aD6OU8j6VcfpkQXbTOEL2vVfehxqCCyEQ9S7QuOUzmUqfujz2w9dmAdmpafLALKZt2WSe/eOV7nd4QPxDwr5Gx5JNaPPOnkeeXCcm8Az2bz6VzMnuUMeeJ8E5XVEUuAO5LLsLEx1vPQAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Azure Static Web Apps" title="" 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" decoding="async" /> </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="73038509417858744000" data-toaster-class="gatsby-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`, `73038509417858744000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="34638043261860040000" data-toaster-class="gatsby-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`, `34638043261860040000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="76469530238958550000" data-toaster-class="gatsby-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`, `76469530238958550000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="46739410459144380000" data-toaster-class="gatsby-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`, `46739410459144380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="43788108438561020000" data-toaster-class="gatsby-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`, `43788108438561020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="96406556916140430000" data-toaster-class="gatsby-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`, `96406556916140430000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="45131779928353150000" data-toaster-class="gatsby-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;); ?>`, `45131779928353150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-php line-numbers"><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 string double-quoted-string">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token delimiter important">?></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="12645979463463797000" data-toaster-class="gatsby-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`, `12645979463463797000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="93314716089783100000" data-toaster-class="gatsby-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`, `93314716089783100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="30665427457565150000" data-toaster-class="gatsby-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`, `30665427457565150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="7671352650766905000" data-toaster-class="gatsby-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`, `7671352650766905000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="24356107575602115000" data-toaster-class="gatsby-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`, `24356107575602115000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="2753021333288785400" data-toaster-class="gatsby-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`, `2753021333288785400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="182035245492984100" data-toaster-class="gatsby-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`, `182035245492984100`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="91620265597741660000" data-toaster-class="gatsby-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`, `91620265597741660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">jam</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="32547101083293905000" data-toaster-class="gatsby-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`, `32547101083293905000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[^\w\s]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 24</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="1804765931007890200" data-toaster-class="gatsby-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`, `1804765931007890200`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="48545815587934070000" data-toaster-class="gatsby-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`, `48545815587934070000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="53910493238574530000" data-toaster-class="gatsby-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`, `53910493238574530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="6404052960116835000" data-toaster-class="gatsby-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`, `6404052960116835000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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> <span class="token literal-property property">sensitivity</span><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="44228087895168340000" data-toaster-class="gatsby-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`, `44228087895168340000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="98625273869876350000" data-toaster-class="gatsby-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`, `98625273869876350000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="71302893561920650000" data-toaster-class="gatsby-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!`, `71302893561920650000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="64874731604953510000" data-toaster-class="gatsby-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`, `64874731604953510000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="89827835066674400000" data-toaster-class="gatsby-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`, `89827835066674400000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="89534728026115800000" data-toaster-class="gatsby-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!`, `89534728026115800000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="90343063427783380000" data-toaster-class="gatsby-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!`, `90343063427783380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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("\t")</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">"</code> as the separator, it splits the string into single UTF-16 characters.</li> </ul> <div class="gatsby-code-button-container" data-toaster-id="29016593481732223000" data-toaster-class="gatsby-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;]`, `29016593481732223000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></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="54487778546559200000" data-toaster-class="gatsby-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!`, `54487778546559200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="10787819077230987000" data-toaster-class="gatsby-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 🐶!`, `10787819077230987000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="45070694550159570000" data-toaster-class="gatsby-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 🐩!`, `45070694550159570000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">THIS</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></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"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">🐶</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="76633640230792310000" data-toaster-class="gatsby-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!`, `76633640230792310000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="28098952054585102000" data-toaster-class="gatsby-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;`, `28098952054585102000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="3872067209461494000" data-toaster-class="gatsby-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!`, `3872067209461494000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="90377195615072470000" data-toaster-class="gatsby-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;`, `90377195615072470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="21015058246867513000" data-toaster-class="gatsby-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`, `21015058246867513000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="98745586646047880000" data-toaster-class="gatsby-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;`, `98745586646047880000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="62535708075034436000" data-toaster-class="gatsby-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;`, `62535708075034436000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="31787181540616995000" data-toaster-class="gatsby-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;`, `31787181540616995000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></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="47323042541884375000" data-toaster-class="gatsby-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,`, `47323042541884375000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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="59802433166923880000" data-toaster-class="gatsby-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;`, `59802433166923880000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="95809234188394320000" data-toaster-class="gatsby-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`, `95809234188394320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="260775395012657900" data-toaster-class="gatsby-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`, `260775395012657900`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></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="98797667446180580000" data-toaster-class="gatsby-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`, `98797667446180580000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></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? 👉🏽</p> </blockquote> <p>A Kaiser roll</p><![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="70926061998842060000" data-toaster-class="gatsby-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]`, `70926061998842060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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="88769828218690930000" data-toaster-class="gatsby-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]`, `88769828218690930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">selectionSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> minIndex<span class="token punctuation">,</span> temp<span class="token punctuation">,</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> minIndex <span class="token operator">=</span> i<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> j <span class="token operator">=</span> i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">&lt;</span> list<span class="token punctuation">[</span>minIndex<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> minIndex <span class="token operator">=</span> j<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> temp <span class="token operator">=</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>minIndex<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>minIndex<span class="token punctuation">]</span> <span class="token operator">=</span> temp<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">selectionSort</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">11</span><span class="token punctuation">,</span> <span class="token number">25</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">,</span> <span class="token number">22</span><span class="token punctuation">,</span> <span class="token number">64</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//[11, 12, 22, 25, 64]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Let’s see how the list is sorted in each iteration in the above example:</p> <table> <thead> <tr> <th>Sorted list</th> <th>Unsorted sublist</th> <th>Lowest elements</th> </tr> </thead> <tbody> <tr> <td>[]</td> <td>[11, 25, 12, 22, 64]</td> <td>11</td> </tr> <tr> <td>[11]</td> <td>[25, 12, 22, 64]</td> <td>12</td> </tr> <tr> <td>[11, 12]</td> <td>[25, 22, 64]</td> <td>22</td> </tr> <tr> <td>[11, 12, 22]</td> <td>[25, 64]</td> <td>25</td> </tr> <tr> <td>[11, 12, 22, 25]</td> <td>[64]</td> <td>64</td> </tr> <tr> <td>[11, 12, 22, 25, 64]</td> <td>[]</td> <td></td> </tr> </tbody> </table> <p>In terms of complexity, this algorithm remains the same regardless of which scenario we’re facing. Which is <strong>O(n<sup>2</sup>)</strong> for comparisons, and <strong>O(n)</strong> swaps. But if you look at the code, it’s self explanatory and simple and sometimes we just want exactly that. In terms or swaps, it’s less than bubble sort.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n) swaps</td> </tr> <tr> <td>Best-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n) swaps</td> </tr> <tr> <td>Average-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n) swaps</td> </tr> </tbody> </table> <h2 id="insertion-sort" style="position:relative;"><a href="#insertion-sort" aria-label="insertion sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Insertion sort</h2> <p>This is like when I play cards and someone is handing me the them one by one. I usually put them in my hand in order as I receive them. Insertion sort builds the final list one item at a time. This means it’s less efficient for large lists relative to it’s competitors such as quick sort, or merge sort.</p> <p>However, it provides several advantages:</p> <ul> <li>Simple implementation (we’ll get there shortly).</li> <li>Efficient for small data sets.</li> <li>More efficient than bubble or selection sorts.</li> <li>Adaptive, i.e. efficient for already sorted collections.</li> <li>In place.</li> <li>Online, can sort a list as it receives it.</li> </ul> <p>Let’s see how it works in action:</p> <p><img src="/6e67d1c722106442b422ee53e98575b3/insertionsort.gif" alt="selection sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="18390780397491046000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function insertionSort(list){ let i, len = list.length, item, j; for(i = 1; i < len; i++){ item = list[i]; j = i; while(j > 0 && list[j-1] > item) { list[j] = list[j-1]; j--; } list[j] = item; } return list; }`, `18390780397491046000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">insertionSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> i<span class="token punctuation">,</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">,</span> item<span class="token punctuation">,</span> j<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> item <span class="token operator">=</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> j <span class="token operator">=</span> i<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>j <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> list<span class="token punctuation">[</span>j<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">></span> item<span class="token punctuation">)</span> <span class="token punctuation">{</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>j<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> j<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> item<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In terms of complexity, it’s similar to bubble sort in worst and average cases with <strong>O(n<sup>2</sup>)</strong> for both comparisons and swaps. But in best case, it’s really efficient with <strong>O(n)</strong> comparisons and <strong>O(1)</strong> swaps.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n<sup>2</sup>) swaps</td> </tr> <tr> <td>Best-case performance</td> <td>O(n) comparisons</td> </tr> <tr> <td></td> <td>O(1) swaps</td> </tr> <tr> <td>Average-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n<sup>2</sup>) swaps</td> </tr> </tbody> </table> <h2 id="merge-sort" style="position:relative;"><a href="#merge-sort" aria-label="merge sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Merge sort</h2> <p>Merge sort is in the divide and conquer algorithms and is implemented with a recursive pattern. We break down the list into small pieces until you have one item in each piece. Then we merge them back together but will compare them and put the items in order.</p> <p>It’s really easy to understand, but let’s see it in action:</p> <p><img src="/a29c0dd0186d1f8cef3c5ebdedf3e5a3/mergesort.gif" alt="merge sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="5779084685424963000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function mergeSort(list) { let len = list.length; if(len < 2) return list; let mid = Math.floor(len/2), left = list.slice(0,mid), right =list.slice(mid); return merge(mergeSort(left),mergeSort(right)); } function merge(left, right) { let result = [], lLen = left.length, rLen = right.length, l = 0, r = 0; while(l < lLen && r < rLen) { if(left[l] < right[r]) { result.push(left[l++]); } else{ result.push(right[r++]); } } return result.concat(left.slice(l)).concat(right.slice(r)); }`, `5779084685424963000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>len <span class="token operator">&lt;</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token keyword">let</span> mid <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>len<span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> left <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span>mid<span class="token punctuation">)</span><span class="token punctuation">,</span> right <span class="token operator">=</span>list<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>mid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">merge</span><span class="token punctuation">(</span><span class="token function">mergeSort</span><span class="token punctuation">(</span>left<span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token function">mergeSort</span><span class="token punctuation">(</span>right<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">merge</span><span class="token punctuation">(</span><span class="token parameter">left<span class="token punctuation">,</span> right</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lLen <span class="token operator">=</span> left<span class="token punctuation">.</span>length<span class="token punctuation">,</span> rLen <span class="token operator">=</span> right<span class="token punctuation">.</span>length<span class="token punctuation">,</span> l <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> r <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>l <span class="token operator">&lt;</span> lLen <span class="token operator">&amp;&amp;</span> r <span class="token operator">&lt;</span> rLen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>left<span class="token punctuation">[</span>l<span class="token punctuation">]</span> <span class="token operator">&lt;</span> right<span class="token punctuation">[</span>r<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> result<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>left<span class="token punctuation">[</span>l<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span><span class="token punctuation">{</span> result<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>right<span class="token punctuation">[</span>r<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>left<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>l<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>right<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Merge sort is much better in terms of complexity from previous algorithms. It takes <strong>O(n log n)</strong> operations to sort an array. In terms of memory needed, it’s <strong>O(n)</strong> total with <strong>O(n)</strong> auxiliary if we use array and <strong>O(1)</strong> if we use a linked list.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Best-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Average-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Worst-case space</td> <td>O(n) total, O(n) auxiliary with list, O(1) with linked list</td> </tr> </tbody> </table> <h2 id="quick-sort" style="position:relative;"><a href="#quick-sort" aria-label="quick sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Quick sort</h2> <p>Quick sort is similar to merge sort, with the difference that the we don’t split the collection in half. We choose a pivot point and split from there. Once we have chosen the pivot point, we put all smaller items to the left and all the larger items to the right of that.</p> <p>That means that the pivot point itself is sorted now. We continue this for left and right side recursively until we have the full list sorted.</p> <p>Choosing the pivot could be random, middle point, first, or last item of the list. There are many ways to do this each with their own pros and cons.</p> <p>Let’s see this in action to better understand the difference:</p> <p><img src="/42561febe484d44ab4fd5faf2a6d6fb6/quicksort.gif" alt="quick sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="62316283506604630000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function quickSort(list, left, right) { let len = list.length, pivot, partitionIndex; if(left < right) { pivot = right; partitionIndex = partition(list, pivot, left, right); //sort left and right quickSort(list, left, partitionIndex - 1); quickSort(list, partitionIndex + 1, right); } return list; } function partition(list, pivot, left, right) { let pivotValue = list[pivot], partitionIndex = left; for(let i = left; i < right; i++) { if(list[i] < pivotValue) { swap(list, i, partitionIndex); partitionIndex++; } } swap(list, right, partitionIndex); return partitionIndex; } function swap(list, i, j) { let temp = list[i]; list[i] = list[j]; list[j] = temp; } quickSort([11,8,14,3,6,2,7],0,6); //[2, 3, 6, 7, 8, 11, 14]`, `62316283506604630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">quickSort</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> left<span class="token punctuation">,</span> right</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">,</span> pivot<span class="token punctuation">,</span> partitionIndex<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>left <span class="token operator">&lt;</span> right<span class="token punctuation">)</span> <span class="token punctuation">{</span> pivot <span class="token operator">=</span> right<span class="token punctuation">;</span> partitionIndex <span class="token operator">=</span> <span class="token function">partition</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> pivot<span class="token punctuation">,</span> left<span class="token punctuation">,</span> right<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//sort left and right</span> <span class="token function">quickSort</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> left<span class="token punctuation">,</span> partitionIndex <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">quickSort</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> partitionIndex <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> right<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">partition</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> pivot<span class="token punctuation">,</span> left<span class="token punctuation">,</span> right</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> pivotValue <span class="token operator">=</span> list<span class="token punctuation">[</span>pivot<span class="token punctuation">]</span><span class="token punctuation">,</span> partitionIndex <span class="token operator">=</span> left<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> left<span class="token punctuation">;</span> i <span class="token operator">&lt;</span> right<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">&lt;</span> pivotValue<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">swap</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> i<span class="token punctuation">,</span> partitionIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> partitionIndex<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">swap</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> right<span class="token punctuation">,</span> partitionIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> partitionIndex<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">swap</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> i<span class="token punctuation">,</span> j</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> temp <span class="token operator">=</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> temp<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">quickSort</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">11</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">,</span><span class="token number">14</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//[2, 3, 6, 7, 8, 11, 14]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see, the more efficient the algorithm gets, the more complex the implementation will be. In terms of complexity, it’s worst than merge sort in worst-case, and equal in average and best.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n<sup>2</sup>)</td> </tr> <tr> <td>Best-case performance</td> <td>O(n log n) with simple partition, O(n) with <a href="https://en.wikipedia.org/wiki/Quicksort" target="_blank" rel="nofollow noopener noreferrer">three-way partition</a></td> </tr> <tr> <td>Average-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Worst-case space</td> <td>O(n) auxiliary</td> </tr> </tbody> </table> <h2 id="heap-sort" style="position:relative;"><a href="#heap-sort" aria-label="heap sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Heap sort</h2> <p>Heap sort is a comparison based sort, you can think of it as an improved version of selection sort. It divides it’s input into a sorted and an unsorted region, then iteratively shrinks the unsorted region by extracting the largest item and inserting it into the sorted region.</p> <p>The unsorted region is kept in <a href="https://en.wikipedia.org/wiki/Heap_(data_structure)" target="_blank" rel="nofollow noopener noreferrer">heap data structure</a> to more quickly find the largest item in each step.</p> <blockquote> <p>💡 Since there is no heap data structure in JavaScript, we can use an array to represent it.</p> </blockquote> <p>That was a mouthful, so let’s see it in action:</p> <p><img src="/2d571b4de2faccf2df0c7890db0dc9b7/heapsort.gif" alt="heap sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="5323429262434765000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function heapSort(list) { let len = list.length; let i = Math.floor(len / 2 - 1); let j = len - 1; while(i >= 0) { heapify(list, len, i); i--; } while(k >= 0) { [list[0], list[k]] = [list[k], list[0]]; heapify(list, k, 0); k--; } return list; } function heapify(list, len, i){ let largest = i; let left = i * 2 + 1; let right = left + 1; if(left < len && > list[left] > list[largest]) { largest = left; } if(right < len && list[right] > list[largest]) { largest = right; } if(largest != i) { [list[i], list[largest]] = [list[largest], list[i]]; heapify(list, len, largest); } return list; }`, `5323429262434765000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">heapSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">let</span> i <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>len <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> j <span class="token operator">=</span> len <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>i <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">heapify</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> len<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">while</span><span class="token punctuation">(</span>k <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">heapify</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> k<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">heapify</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> len<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> largest <span class="token operator">=</span> i<span class="token punctuation">;</span> <span class="token keyword">let</span> left <span class="token operator">=</span> i <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">let</span> right <span class="token operator">=</span> left <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>left <span class="token operator">&lt;</span> len <span class="token operator">&amp;&amp;</span> <span class="token operator">></span> list<span class="token punctuation">[</span>left<span class="token punctuation">]</span> <span class="token operator">></span> list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> largest <span class="token operator">=</span> left<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span><span class="token punctuation">(</span>right <span class="token operator">&lt;</span> len <span class="token operator">&amp;&amp;</span> list<span class="token punctuation">[</span>right<span class="token punctuation">]</span> <span class="token operator">></span> list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> largest <span class="token operator">=</span> right<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span><span class="token punctuation">(</span>largest <span class="token operator">!=</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">heapify</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> len<span class="token punctuation">,</span> largest<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In the above code snippet, <code class="language-text">heapify</code> function compares three elements, the parent, and two children. It then makes sure that they are in the correct order for a <strong>max heap</strong> since we’re building the heap from bottom up.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Best-case performance</td> <td>O(n log n) distinct keys, O(n) with equal keys</td> </tr> <tr> <td>Average-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Worst-case space</td> <td>O(n) total, O(1) auxiliary</td> </tr> </tbody> </table> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>You should have a good understanding of these sort algorithms by now. If not, I recommend going through them again and try to write a few examples with a pen and paper. Don’t worry if you have trouble understanding the more complex ones like heap sort. It’s completely OK as I had the same trouble initially. But with practice and trying to implement them I learnt them at the end.</p> <p>There are many other sort algorithms out there, so feel free to explore them and compare the way they work with what you’ve learnt so far.</p> <p>Thanks for reading and enjoy sorting your collections.</p> <blockquote> <p>⚡ All the images in this post are pulled from the algorithm’s Wikipedia pages.</p> </blockquote><![CDATA[Have you ever thought about for loops? ➰]]>https://yashints.dev/blog/2020/04/24/iteratorshttps://yashints.dev/blog/2020/04/24/iteratorsFri, 24 Apr 2020 00:00:00 GMT<p>Using a loop is almost a must in our day to day life. But have you ever thought what kind of loop should you use? Do you know the difference between enumerables and iterables? This article sheds some light in this space, so read on if you’re interested.</p> <!--more--> <h2 id="background" style="position:relative;"><a href="#background" aria-label="background permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background</h2> <p>Looping has seen quite a few changes from when I started programming. I remember using while loops and thinking wow, this is cool (I was printing starts on console using MS-DOS).</p> <p>For loop is another way to iterate through a data structure which contains many items. But non of these methods iterate over the actual structure. They use a sequence, usually named <code class="language-text">i</code> which mirrors the identifier for you.</p> <div class="gatsby-code-button-container" data-toaster-id="44303425814436650000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const fruits = ['🍉', '🍎', '🍌']; for (let i = 0; i < fruits.length; i++) { console.log(fruits[i]); } // 🍉, 🍎, 🍌`, `44303425814436650000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> fruits <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'🍉'</span><span class="token punctuation">,</span> <span class="token string">'🍎'</span><span class="token punctuation">,</span> <span class="token string">'🍌'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> fruits<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>fruits<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 🍉, 🍎, 🍌</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Here <code class="language-text">i</code> is an index which allows you to access the elements of fruits array and is not part of the array itself. But with progress on <strong>JavaScript</strong> towards more modern ways of programming, things have changes now. We have <code class="language-text">for...in</code>, and <code class="language-text">for...of</code> loops which use a different mechanism for going through items in a collection.</p> <h2 id="concepts" style="position:relative;"><a href="#concepts" aria-label="concepts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Concepts</h2> <p>Before we delve into these newer ways of iteration, we need to be on the same page around some concepts. So let’s go through them now:</p> <ul> <li><strong>Iterables</strong>: This is a kind of loop where we are performing a repetition. Meaning the same set of actions are performed on each item.</li> <li><strong>Enumerables</strong>: This is a kind of loop where we making mention of, or counting items one at a time. This means the collection’s elements can be distinctly identified and referenced.</li> </ul> <p>That didn’t click for me at first, but after going through some examples, it finally made sense. If you consider a <em>full pencil case</em>, that’s an enumerable. When you <em>line up at Aldi</em> to pay, that line is an iterable. A <em>wad of cash</em> is an enumerable, whereas a <em>row of keys on your keyboard</em> is an iterable.</p> <blockquote> <p>💡 In order for an object to be <code class="language-text">iterable</code>, it MUST implement an <code class="language-text">@@iterator</code> property which returns an iterator. An iterator object is one which has a <code class="language-text">next</code> method which returns the next item in the collection. That’s why an object is not an iterable.</p> </blockquote> <p>By now you should have started to see the pattern here. The best analogy I came across is:</p> <blockquote> <p>😍 <strong>Enumerables</strong> are like rectangles whereas <strong>iterables</strong> are squares. This means all <code class="language-text">iterables</code> are <code class="language-text">enumerables</code>, however, not all <code class="language-text">enumerables</code> are <code class="language-text">iterables</code>.</p> </blockquote> <h2 id="code-classlanguage-textforincode" style="position:relative;"><a href="#code-classlanguage-textforincode" aria-label="code classlanguage textforincode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">for...in</code></h2> <p>So let’s start from <code class="language-text">enumerables</code>. You can go through enumerables using <code class="language-text">for...in</code>. The use case is mainly to go through key-value pairs in an object:</p> <div class="gatsby-code-button-container" data-toaster-id="8861724597053256000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const superCar = { make: 'Lamborghini', model: 'Veneno', year: '2020' }; for (let key in superCar) { console.log(\`\${key} --> \${superCar[key]}\`); } // make --> Lamborghini // model --> Veneno // year --> 2020`, `8861724597053256000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> superCar <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">make</span><span class="token operator">:</span> <span class="token string">'Lamborghini'</span><span class="token punctuation">,</span> <span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token string">'Veneno'</span><span class="token punctuation">,</span> <span class="token literal-property property">year</span><span class="token operator">:</span> <span class="token string">'2020'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> key <span class="token keyword">in</span> superCar<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> --> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>superCar<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// make --> Lamborghini</span> <span class="token comment">// model --> Veneno</span> <span class="token comment">// year --> 2020</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can also use <code class="language-text">for...in</code> to go through index values of an iterable like an array or a string:</p> <div class="gatsby-code-button-container" data-toaster-id="45750463886743446000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let fact = 'Lamborghini is the best!'; for (let index in fact) { console.log(\`Index of \${fact[index]}: \${index}\`); } // Index of L: 0 // Index of a: 1 // Index of m: 2 // Index of b: 3 // ...`, `45750463886743446000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> fact <span class="token operator">=</span> <span class="token string">'Lamborghini is the best!'</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> index <span class="token keyword">in</span> fact<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Index of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>fact<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Index of L: 0</span> <span class="token comment">// Index of a: 1</span> <span class="token comment">// Index of m: 2</span> <span class="token comment">// Index of b: 3</span> <span class="token comment">// ...</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <blockquote> <p>💡 Beware that you can’t iterate on <code class="language-text">Symbol</code> properties with <code class="language-text">for...in</code> and that’s because <code class="language-text">Symbols</code> are primitive data types that are <em>always</em> unique. They are generally used as private properties to avoid name clashes when inheritance is used.</p> </blockquote> <h2 id="using-code-classlanguage-textforofcode" style="position:relative;"><a href="#using-code-classlanguage-textforofcode" aria-label="using code classlanguage textforofcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Using <code class="language-text">for...of</code></h2> <p>This kind of loop is applicable to “iterable objects” meaning the item after <code class="language-text">of</code> MUST be an <code class="language-text">iterable</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="61010050756001055000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const fruits = ['🍉', '🍎', '🍌']; for (let fruit of fruits) { console.log(\`\${fruit} is delicious.\`); } // 🍉 is delicious. // 🍎 is delicious. // 🍌 is delicious.`, `61010050756001055000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> fruits <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'🍉'</span><span class="token punctuation">,</span> <span class="token string">'🍎'</span><span class="token punctuation">,</span> <span class="token string">'🍌'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> fruit <span class="token keyword">of</span> fruits<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>fruit<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is delicious.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 🍉 is delicious.</span> <span class="token comment">// 🍎 is delicious.</span> <span class="token comment">// 🍌 is delicious.</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And again we can use it on strings, but with a slight difference:</p> <div class="gatsby-code-button-container" data-toaster-id="5376683406087079000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let fact = 'Yas'; for (let char of fact) { console.log(char); } // Y // a // s`, `5376683406087079000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> fact <span class="token operator">=</span> <span class="token string">'Yas'</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> char <span class="token keyword">of</span> fact<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>char<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Y</span> <span class="token comment">// a</span> <span class="token comment">// s</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw the difference between these two modern ways of looping through collections, let’s make more informed decisions as to use what where and write cleaner, more readable code 👊🏽.</p><![CDATA[Stay on top of performance with Lighthouse CI 🚦]]>https://yashints.dev/blog/2020/04/13/lighthouse-cihttps://yashints.dev/blog/2020/04/13/lighthouse-ciMon, 13 Apr 2020 00:00:00 GMT<p>You’ve spent many hours trying to improve your web performance and have got it to a good speed. What happens next? How do you ensure it remains in good shape especially if you’re working in a team with diverse backgrounds and level of coding.</p> <!--more--> <h2 id="web-performance-must-be-monitored" style="position:relative;"><a href="#web-performance-must-be-monitored" aria-label="web performance must be monitored permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Web performance must be monitored</h2> <p>I truly believe web performance shouldn’t be an item in your backlog, rather part of acceptance criteria on each story. That said, having discipline is hard when it comes to web performance. Each member of the team should be aware of dos and don’ts so that they can right code which doesn’t add a few seconds to current page load time, or user’s interactivity with the page.</p> <p>In order to do so, you need to constantly monitor the performance of your application and when is a better time to do it than your CI/CD pipeline or when creating a pull request to get the code merged in (it’s worth mentioning having a CI/CD pipeline is not necessary to have a high quality, well written and performing site).</p> <p>In addition to all of that, your site performs differently from your localhost, so you need to ensure you’re testing close to your actual environment.</p> <h2 id="lighthouse-ci" style="position:relative;"><a href="#lighthouse-ci" aria-label="lighthouse ci permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Lighthouse CI</h2> <p><a href="https://github.com/GoogleChrome/lighthouse-ci" target="_blank" rel="nofollow noopener noreferrer">Lighthouse CI</a> is a set of commands that make continuously running, asserting, saving, and retrieving Lighthouse results as easy as possible.</p> <p>This is a great tool which allows you to run audits on your code base using command line, and raise an alert when someone unintentionally downgrades the performance.</p> <h2 id="what-to-measure" style="position:relative;"><a href="#what-to-measure" aria-label="what to measure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What to measure?</h2> <p>There are countless metrics on which we could focus on. Some are user centric like time to interact, some are resource centric such as the size of your <em>JavaScript</em> or <em>CSS</em> files. Lighthouse CI allows us to easily focus on the size of the files. You can create two types of budgets:</p> <p>1- <strong>Number of given resource</strong>: This will help you to for example enforce having only <code class="language-text">3</code> <em>JavaScript</em> and <code class="language-text">1</code> <em>CSS</em> file. 2- <strong>Size of a given resource</strong>: This budget will enforce that a given resource is of certain size, e.g. only <code class="language-text">500kb</code>.</p> <h2 id="how-does-it-know" style="position:relative;"><a href="#how-does-it-know" aria-label="how does it know permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How does it know?</h2> <p>You’re probably wondering how does <strong>Lighthouse CI</strong> know what to measure and when to raise an alert. This **||is done via a <code class="language-text">JSON</code> file which is usually named <code class="language-text">budget.json</code>, but you can choose any name you prefer.</p> <h2 id="performance-budget" style="position:relative;"><a href="#performance-budget" aria-label="performance budget permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Performance budget</h2> <p>The content of this file is an array of objects representing the budgets for a path. The content will look like below if you only have one path to assert:</p> <div class="gatsby-code-button-container" data-toaster-id="75743295057654320000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[ { &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] } ]`, `75743295057654320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Within the <code class="language-text">resourceSizes</code> and <code class="language-text">resourceCounts</code> arrays, you can add individual objects that specify the <code class="language-text">resourceType</code> and its budget. The budget can be any positive integer and the <code class="language-text">resourceType</code> can be any of the following:</p> <table> <thead> <tr> <th><strong>Resource type</strong></th> <th><strong>Description</strong></th> </tr> </thead> <tbody> <tr> <td><strong>script</strong></td> <td>JavaScript files</td> </tr> <tr> <td><strong>document</strong></td> <td>HTML documents</td> </tr> <tr> <td><strong>image</strong></td> <td>Images</td> </tr> <tr> <td><strong>stylesheet</strong></td> <td>CSS files</td> </tr> <tr> <td><strong>font</strong></td> <td>Webfonts</td> </tr> <tr> <td><strong>media</strong></td> <td>Other media</td> </tr> <tr> <td><strong>other</strong></td> <td>Any other resource which doesn’t match the above, e.g. data transfers over Websocket connections</td> </tr> <tr> <td><strong>third-party</strong></td> <td>All resources from a third-party domain</td> </tr> <tr> <td><strong>total</strong></td> <td>All resources combined</td> </tr> </tbody> </table> <p>For example, the following file will set a 200Kb budget for all scripts, a 500Kb for all images, and a 500Kb for all other resources. Then it sets the total network requests to be 25.</p> <div class="gatsby-code-button-container" data-toaster-id="58840622161926940000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[ { &quot;resourceSizes&quot;: [ { &quot;resourceType&quot;: &quot;script&quot;, &quot;budget&quot;: 200 }, { &quot;resourceType&quot;: &quot;image&quot;, &quot;budget&quot;: 500 }, { &quot;resourceType&quot;: &quot;total&quot;, &quot;budget&quot;: 500 } ], &quot;resourceCounts&quot;: [ { &quot;resourceType&quot;: &quot;total&quot;, &quot;budget&quot;: 25 } ] } ]`, `58840622161926940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"script"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">200</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"image"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">500</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"total"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">500</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"total"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">25</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As of <strong>Lighthouse</strong> 5.3 you can add a <code class="language-text">path</code> property to select which pages the budget should apply to. This is very handy because it allows you to have a centralised budget file for all your pages.</p> <div class="gatsby-code-button-container" data-toaster-id="21277038811035130000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[ { &quot;path&quot;:&quot;/*&quot;, &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] }, { &quot;path&quot;:&quot;/blog&quot;, &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] }, { &quot;path&quot;:&quot;/contact&quot;, &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] } ]`, `21277038811035130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/*"</span><span class="token punctuation">,</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/blog"</span><span class="token punctuation">,</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/contact"</span><span class="token punctuation">,</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="how-should-you-choose-your-numbers" style="position:relative;"><a href="#how-should-you-choose-your-numbers" aria-label="how should you choose your numbers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How should you choose your numbers?</h2> <p>Finding the performance budget is not an easy task since it will depend on your application’s structure and bundling style. However, you can use this useful tool called <a href="https://perf-budget-calculator.firebaseapp.com/" target="_blank" rel="nofollow noopener noreferrer"><strong>Performance Budget Calculator</strong></a> to have a starting point. You might have to run the tool multiple time to each to a point where you’d be happy with the result. You don’t want to be too aggressive and also too complacent either.</p> <h2 id="using-the-ci-locally" style="position:relative;"><a href="#using-the-ci-locally" aria-label="using the ci locally permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Using the CI locally</h2> <p>You can install the CI locally with:</p> <div class="gatsby-code-button-container" data-toaster-id="18462283145883853000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npm install -g @lhci/cli`, `18462283145883853000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> @lhci/cli</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>It also has a dashboard which shows you the historical runs, compares reports and store their results.</p> <div class="gatsby-code-button-container" data-toaster-id="68738492893150840000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npm install @lhci/server`, `68738492893150840000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @lhci/server</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Before running the CI, you need to have a configuration file to tell the tool what to test and where to find the budget file (you could also pass those individually without a config file, but it’d be a pain):</p> <div class="gatsby-code-button-container" data-toaster-id="65621044080430326000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// lighthouserc.json { &quot;ci&quot;: { &quot;collect&quot;: { &quot;numberOfRuns&quot;: 2, &quot;startServerCommand&quot;: &quot;yarn serve&quot;, &quot;url&quot;: &quot;http://localhost:8080&quot; }, &quot;preset&quot;: &quot;lighthouse:recommended&quot; } }`, `65621044080430326000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token comment">// lighthouserc.json</span> <span class="token punctuation">{</span> <span class="token property">"ci"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"collect"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"numberOfRuns"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token property">"startServerCommand"</span><span class="token operator">:</span> <span class="token string">"yarn serve"</span><span class="token punctuation">,</span> <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"http://localhost:8080"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"preset"</span><span class="token operator">:</span> <span class="token string">"lighthouse:recommended"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Then you can run the tool on your local web server by first running:</p> <div class="gatsby-code-button-container" data-toaster-id="85413354435941190000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`lhci autorun --config=./lighthouserc.json`, `85413354435941190000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">lhci autorun <span class="token parameter variable">--config</span><span class="token operator">=</span>./lighthouserc.json</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>and then:</p> <div class="gatsby-code-button-container" data-toaster-id="81111182627168470000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`lhci assert --no-lighthouserc --budgetsFile=budget.json`, `81111182627168470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">lhci assert --no-lighthouserc <span class="token parameter variable">--budgetsFile</span><span class="token operator">=</span>budget.json</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And you will get a result similar to below based on your app’s performance:</p> <div class="gatsby-code-button-container" data-toaster-id="23874880749615346000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`2 result(s) for http://localhost:8080/ × resource-summary.script.size failure for maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <=102400 found: 2416174 all values: 2416174, 2416174 × resource-summary.total.size failure for maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <=512000 found: 2437694 all values: 2437694, 2437694 Assertion failed. Exiting with status code 1.`, `23874880749615346000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token number">2</span> result<span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">for</span> http://localhost:8080/ × resource-summary.script.size failure <span class="token keyword">for</span> maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <span class="token operator">&lt;=</span><span class="token number">102400</span> found: <span class="token number">2416174</span> all values: <span class="token number">2416174</span>, <span class="token number">2416174</span> × resource-summary.total.size failure <span class="token keyword">for</span> maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <span class="token operator">&lt;=</span><span class="token number">512000</span> found: <span class="token number">2437694</span> all values: <span class="token number">2437694</span>, <span class="token number">2437694</span> Assertion failed. Exiting with status code <span class="token number">1</span>.</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="using-the-tool-on-your-prs" style="position:relative;"><a href="#using-the-tool-on-your-prs" aria-label="using the tool on your prs permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Using the tool on your PRs</h2> <p>I am focusing on <a href="https://github.com/features/actions" target="_blank" rel="nofollow noopener noreferrer">GitHub</a> using actions here. But you can apply this technique to <a href="https://azure.microsoft.com/en-au/services/devops/" target="_blank" rel="nofollow noopener noreferrer">Azure DevOps</a>, <a href="https://circleci.com/" target="_blank" rel="nofollow noopener noreferrer">CircleCI</a>, <a href="https://www.jetbrains.com/teamcity/" target="_blank" rel="nofollow noopener noreferrer">TeamCity</a>, or any other tool you’re using. For this to work you will need to have a <a href="https://guides.github.com/introduction/flow/" target="_blank" rel="nofollow noopener noreferrer">GitHub flow</a> in your <code class="language-text">git</code> repository defined.</p> <p>This article’s focus is not to teach you how to create a workflow, but here is the bare minimum you will need to have. Create a <code class="language-text">.yaml</code>/<code class="language-text">.yml</code> file in the <code class="language-text">.github/workflows</code> folder, you can name it whatever you want. I usually name them after what’s their purpose, e.g. <code class="language-text">lighthouse.yml</code> or <code class="language-text">lhci-performance-bot.yml</code>.</p> <p>But before we get to the content of our <code class="language-text">yaml</code> file, let’s see what we need to do on each PR:</p> <ol> <li>Pull down the code</li> <li>Build the app</li> <li>Deploy to a temporary site (I am using Netlify Preview here, but you can use others like staging slots on Azure App Service, etc)</li> <li>Run Lighthouse CI on the site</li> <li>Fail if the conditions are not met</li> </ol> <p>For this to work, we need an application. So I just spun up a new <a href="https://vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue</a> application using <a href="https://cli.vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue CLI</a>, then added my workflow to it and pushed it to <a href="https://github.com/yashints/lighthouse-ci-pr-action" target="_blank" rel="nofollow noopener noreferrer">a new GitHub repo</a>.</p> <p>Here is how my workflow looks like:</p> <div class="gatsby-code-button-container" data-toaster-id="51054614038910740000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`name: Lighthouse CI on: pull_request: branches: [master] jobs: lighthouse: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Node 12 uses: actions/setup-node@v1 with: node-version: 12.x - name: Yarn Install and Build run: | yarn yarn build - name: Waiting for 200 from the Netlify Preview uses: jakepartusch/wait-for-netlify-action@v1 id: waitFor200 with: site_name: &quot;lighthouse-ci-pr&quot; - name: Audit URLs using Lighthouse uses: treosh/lighthouse-ci-action@v2 with: urls: | \$DEPLOY_URL/ \$DEPLOY_URL/about runs: 3 budgetPath: ./budget.json env: DEPLOY_URL: \${{ steps.waitFor200.outputs.url }}`, `51054614038910740000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="yml"><pre style="counter-reset: linenumber NaN" class="language-yml line-numbers"><code class="language-yml"><span class="token key atrule">name</span><span class="token punctuation">:</span> Lighthouse CI <span class="token key atrule">on</span><span class="token punctuation">:</span> <span class="token key atrule">pull_request</span><span class="token punctuation">:</span> <span class="token key atrule">branches</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>master<span class="token punctuation">]</span> <span class="token key atrule">jobs</span><span class="token punctuation">:</span> <span class="token key atrule">lighthouse</span><span class="token punctuation">:</span> <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest <span class="token key atrule">steps</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">uses</span><span class="token punctuation">:</span> actions/checkout@v2 <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Setup Node 12 <span class="token key atrule">uses</span><span class="token punctuation">:</span> actions/setup<span class="token punctuation">-</span>node@v1 <span class="token key atrule">with</span><span class="token punctuation">:</span> <span class="token key atrule">node-version</span><span class="token punctuation">:</span> 12.x <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Yarn Install and Build <span class="token key atrule">run</span><span class="token punctuation">:</span> <span class="token punctuation">|</span><span class="token scalar string"> yarn yarn build</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Waiting for 200 from the Netlify Preview <span class="token key atrule">uses</span><span class="token punctuation">:</span> jakepartusch/wait<span class="token punctuation">-</span>for<span class="token punctuation">-</span>netlify<span class="token punctuation">-</span>action@v1 <span class="token key atrule">id</span><span class="token punctuation">:</span> waitFor200 <span class="token key atrule">with</span><span class="token punctuation">:</span> <span class="token key atrule">site_name</span><span class="token punctuation">:</span> <span class="token string">"lighthouse-ci-pr"</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Audit URLs using Lighthouse <span class="token key atrule">uses</span><span class="token punctuation">:</span> treosh/lighthouse<span class="token punctuation">-</span>ci<span class="token punctuation">-</span>action@v2 <span class="token key atrule">with</span><span class="token punctuation">:</span> <span class="token key atrule">urls</span><span class="token punctuation">:</span> <span class="token punctuation">|</span><span class="token scalar string"> $DEPLOY_URL/ $DEPLOY_URL/about</span> <span class="token key atrule">runs</span><span class="token punctuation">:</span> <span class="token number">3</span> <span class="token key atrule">budgetPath</span><span class="token punctuation">:</span> ./budget.json <span class="token key atrule">env</span><span class="token punctuation">:</span> <span class="token key atrule">DEPLOY_URL</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> steps.waitFor200.outputs.url <span class="token punctuation">}</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>What is happening is that I am just creating an action on each PR. In this action, we need to pull down the code, install node, run <code class="language-text">yarn</code> and <code class="language-text">yarn build</code> to build the application, wait for Netlify to deploy our PR into a preview site, then get the URL and inject it into the next step.</p> <p>I’m just using <a href="https://github.com/marketplace/actions/wait-for-netlify" target="_blank" rel="nofollow noopener noreferrer"><code class="language-text">wait-for-netlify-action</code></a>, but it’s not that hard to implement this part. Then we will be using the <a href="https://github.com/treosh/lighthouse-ci-action/" target="_blank" rel="nofollow noopener noreferrer"><code class="language-text">lighthouse-ci-action</code></a> to run our audit on the paths we have specified.</p> <p>Notice I am not using a <strong>Lighthouse</strong> configuration file in this workflow because it’s not needed. You can pass the parameters directly to the action like I’ve done above. I am just auditing the home and about pages since I’ve only got these two pages.</p> <p>You can pass as many URL’s to this as you like, but if there are many of the, it makes more sense to add the config file back.</p> <blockquote> <p>💡 Remember to setup Netlify for your site and set it to create a deployment for every PR. Then get the site id and pass it to the <code class="language-text">wait-for-netlify-action</code> action.</p> </blockquote> <p><strong>Pro tip</strong>: When you setup your Vue CLI generated application which is using Vue Router, the non default routes won’t work if the user types them in the browser URL bar and hits enter. That’s because that route is handled on the client side and server doesn’t know about it. To fix that you need to add a URL rewrite rule to return your <code class="language-text">index.html</code> for all legitimate routes.</p> <p>In case of Netlify, just create a file named <code class="language-text">_redirects</code> inside your <em>public</em> and add the following line to it.</p> <div class="gatsby-code-button-container" data-toaster-id="26704048921441403000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`/* /index.html 200`, `26704048921441403000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">/* /index.html <span class="token number">200</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h2 id="result" style="position:relative;"><a href="#result" aria-label="result permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Result</h2> <p>I created a branch and pushed it up. Then created a PR and voila, the action kicked in and failed, since I have a large image on the about page.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/4e663/ci-results.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.074074074074076%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMFBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHTHrQkeID/xAAcEAAABgMAAAAAAAAAAAAAAAAAAQIDBBMFEDL/2gAIAQEAAQUCmmpBWui5wZDnX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAIDAQEAAAAAAAAAAAAAAAACATOREBL/2gAIAQEABj8CXy0wWNpY2id//8QAGBABAQADAAAAAAAAAAAAAAAAARAhMaH/2gAIAQEAAT8hymy6bJXQ3//aAAwDAQACAAMAAAAQbD//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAdEAACAQQDAAAAAAAAAAAAAAABEQAQIVHRMZHw/9oACAEBAAE/EGaztl2GFCDZ3CTnsz1cCv8A/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="PR validation failed on GitHub action using lighthouse CI&#39;s audit" title="" src="/static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/47311/ci-results.jpg" srcset="/static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/6f81f/ci-results.jpg 270w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/09d21/ci-results.jpg 540w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/47311/ci-results.jpg 1080w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/0047d/ci-results.jpg 1620w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/4e663/ci-results.jpg 1893w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>I then reduced the size of the image and pushed the changes up. This time it passed.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/63e3628409b060661f7e8007c50a4a98/98d66/auditsuccess.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAbMsQD//xAAZEAACAwEAAAAAAAAAAAAAAAAAAwECFAT/2gAIAQEAAQUC62XVGtxrcf/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAICAwAAAAAAAAAAAAAAAAACMqESMWH/2gAIAQEABj8CXFt8JUSo/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAFhkRH/2gAIAQEAAT8hbyF0xPgmwf/aAAwDAQACAAMAAAAQf/8A/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxAAAQQDAAAAAAAAAAAAAAAAAQARUfBBYcH/2gAIAQEAAT8QKagCWYAl1cuLV2hf/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="PR validation passing on GitHub action using lighthouse CI" title="" src="/static/63e3628409b060661f7e8007c50a4a98/47311/auditsuccess.jpg" srcset="/static/63e3628409b060661f7e8007c50a4a98/6f81f/auditsuccess.jpg 270w, /static/63e3628409b060661f7e8007c50a4a98/09d21/auditsuccess.jpg 540w, /static/63e3628409b060661f7e8007c50a4a98/47311/auditsuccess.jpg 1080w, /static/63e3628409b060661f7e8007c50a4a98/0047d/auditsuccess.jpg 1620w, /static/63e3628409b060661f7e8007c50a4a98/98d66/auditsuccess.jpg 1905w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We learned together how to use Lighthouse CI, a tool which allows you to run audits on your sites from command line in our CI/CD pipeline to make sure no one is downgrading the performance when they work on the application.</p> <p>This way, we’re always on top of our game rather than creating backlog items to find the issues and fix them later.</p> <p>In addition to that, your users are going to be happy and remain happy with their experience which is worth all the effort.</p> <p>Hope you’ve enjoyed reading this and happy performance enforcement 👋🏽.</p><![CDATA[How I recovered a day's worth of work with git 🏥]]>https://yashints.dev/blog/2020/04/05/git-logshttps://yashints.dev/blog/2020/04/05/git-logsSun, 05 Apr 2020 00:00:00 GMT<p>I was working on a project a week ago and had a local branch (with a few commits) I was going to push to upstream to create a PR (pull request). However, after pulling down master and rebasing, I realised all of my code except my first commit is gone after rebase 😱.</p> <!--more--> <h2 id="background" style="position:relative;"><a href="#background" aria-label="background permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background</h2> <p>I had a local branch which I was working on. Since I’d made a few changes before end of the day, I committed those and went about to do some parenting.</p> <p>The day after that, I restarted my work and had many other changes in a few other commits by the time I was ready to push my code to upstream. But before we do it, it’s our practice to pull down master and rebase in case there is any conflict, or changes made by someone else has had any side effects on the bit we’ve done.</p> <h2 id="rebase" style="position:relative;"><a href="#rebase" aria-label="rebase permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Rebase</h2> <p>So I pulled down the master branch and rebased it directly from origin using (don’t do this at home please, I’ll explain later):</p> <div class="gatsby-code-button-container" data-toaster-id="69783837931161140000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git pull origin master --rebase`, `69783837931161140000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">git pull origin master <span class="token operator">--</span>rebase</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once done, I realised I had some conflicts since someone else had worked on one of the files I’d modified. So I started the merge conflict process and made sure all was good. However, I didn’t realised that when I tested the web application, the latest code wasn’t refreshed, and I was seeing my own code (don’t ask me why, it’s an old code base and you need to rebuild and hard refresh every time you make a change).</p> <p>Having seen all is good I created a PR and went for lunch. One of colleagues then reviewed the PR and since all my changes had gone apart from the small parts from yesterday’s commit, he approved and completed the PR.</p> <h2 id="someone-raised-a-bug" style="position:relative;"><a href="#someone-raised-a-bug" aria-label="someone raised a bug permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Someone raised a bug</h2> <p>I was working on something else when I realised someone has raised a bug on the feature I’d implemented and when I checked the code I was in total shock since most of my code wasn’t there anymore. So I checked my local branch and saw that’s the case, in fact several of my commits were missing from that branch altogether.</p> <p>Later I realised that I’d forgotten to add everything before committing 🤦🏽‍♂️. Just to clarify this was during a really crazy time where we were working day and night for over a week to deliver this project for all of our hospitals across Australia and New Zealand to monitor their resources in intensive care like number of available beds, ventilator, etc. I will tell you all about it once I find some time.</p> <h2 id="initial-try" style="position:relative;"><a href="#initial-try" aria-label="initial try permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Initial try</h2> <p>I started by running:</p> <div class="gatsby-code-button-container" data-toaster-id="27294460749310590000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git reflog`, `27294460749310590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">git reflog</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>I saw anything but my commits which expected because that commit command never had happened due to the files that weren’t added.</p> <h2 id="checking-stash" style="position:relative;"><a href="#checking-stash" aria-label="checking stash permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking stash</h2> <p>Next thing I checked was my stashed files:</p> <div class="gatsby-code-button-container" data-toaster-id="5725013924110378000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git stash list`, `5725013924110378000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">git stash list</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This showed me there were two sets of stashed files.</p> <div class="gatsby-code-button-container" data-toaster-id="33082415153423606000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`stash@{0}: WIP on elmah: 82eb0a4 Merged PR 426: Fixed pass change page stash@{1}: WIP on availability: 87b2264 Dashboard is now grouping based on hospital category, has got a filter and a search box to search for hospitals`, `33082415153423606000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">stash@<span class="token punctuation">{</span>0<span class="token punctuation">}</span>: WIP on elmah: 82eb0a4 Merged PR 426: Fixed pass change page stash@<span class="token punctuation">{</span>1<span class="token punctuation">}</span>: WIP on availability: 87b2264 Dashboard is now grouping based on hospital category<span class="token punctuation">,</span> has got a <span class="token keyword">filter</span> and a search box to search <span class="token keyword">for</span> hospitals</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Then I looked into each of these with <code class="language-text">git stash show stash@{0}</code> and <code class="language-text">git stash show stash@{1}</code> but I didn’t see any of those.</p> <h2 id="checking-git-database" style="position:relative;"><a href="#checking-git-database" aria-label="checking git database permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>checking git database</h2> <p>At this point I realised that I needed some help and I contacted Scott one of our <code class="language-text">git</code> gurus to help me fine out what happened. He suggested we start by checking the database for any lost commit using:</p> <div class="gatsby-code-button-container" data-toaster-id="66136764890753730000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git fsck --lost-found`, `66136764890753730000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">git fsck <span class="token operator">--</span>lost-found</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>From the documentation:</p> <blockquote> <p><strong>—lost-found:</strong></p> </blockquote> <p>Write dangling objects into .git/lost-found/commit/ or .git/lost-found/other/, depending on type. If the object is a blob, the contents are written into the file, rather than its object name.</p> <p>This showed me a bunch of stuff including some dangling commits.</p> <div class="gatsby-code-button-container" data-toaster-id="15096376619924513000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`Checking object directories: 100% (256/256), done. Checking objects: 100% (4282/4282), done. dangling tree 484106954fff79e5a4d7b8fd53fca05311e56e79 dangling blob d10124a92b82ccdcb1521ef814f815b75223e0f3 dangling commit 4c8288a8c30d4171c4935982e18ebd842a2c2811 dangling tree ae02e6d9b291775c9bc1eb1489ba341f8b033f48 dangling commit 2ec37c71f59766d55c09830a5b6e2c5e1c741a95 dangling blob 40c3c7ccbd197c78ceddf71c2be01b0db2114ba9 dangling tag a70363ef35f023e57e00fc625bee362c2e9e4bc9 dangling commit 1184e4a583e3d0f9cf9f3cb994a3375b16d122cd`, `15096376619924513000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">Checking object directories: 100% <span class="token punctuation">(</span>256/256<span class="token punctuation">)</span><span class="token punctuation">,</span> done<span class="token punctuation">.</span> Checking objects: 100% <span class="token punctuation">(</span>4282/4282<span class="token punctuation">)</span><span class="token punctuation">,</span> done<span class="token punctuation">.</span> dangling tree 484106954fff79e5a4d7b8fd53fca05311e56e79 dangling blob d10124a92b82ccdcb1521ef814f815b75223e0f3 dangling commit 4c8288a8c30d4171c4935982e18ebd842a2c2811 dangling tree ae02e6d9b291775c9bc1eb1489ba341f8b033f48 dangling commit 2ec37c71f59766d55c09830a5b6e2c5e1c741a95 dangling blob 40c3c7ccbd197c78ceddf71c2be01b0db2114ba9 dangling tag a70363ef35f023e57e00fc625bee362c2e9e4bc9 dangling commit 1184e4a583e3d0f9cf9f3cb994a3375b16d122cd</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>So we started to go through some of these to find out which one contained the files I was after.</p> <p>We checked out a few of those commits and couldn’t find what we were after. Then he suggested we check those dangling blobs which technically are a tree object containing a snapshot of everything in your current branch.</p> <h2 id="checking-git-dangling-blobs" style="position:relative;"><a href="#checking-git-dangling-blobs" aria-label="checking git dangling blobs permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking git dangling blobs</h2> <p>You cannot checkout those objects, instead you need to use below command where the last part is the hash code of the blob you’re looking into:</p> <div class="gatsby-code-button-container" data-toaster-id="98010426247986430000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(` git ls-tree -r d134e9e`, `98010426247986430000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell"> git <span class="token function">ls</span><span class="token operator">-</span>tree <span class="token operator">-</span>r d134e9e</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can copy this from the output of the previous command and you don’t need the whole hash value, just a few from the beginning.</p> <p>The output of this command looks like this:</p> <div class="gatsby-code-button-container" data-toaster-id="81372345058084750000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`100644 blob ea25f3a9fe6094d700588f33c340d32281a7614b src/ARV.Database/ARV.Database.sqlproj.orig 100644 blob 2e47fe1d11bd2624065866591af00f80f16e5e1e src/ARV.Web.Reach/Partials/hird/incident.form.campuses.list.html 100644 blob 2a6b2547ace20f6bbda788dc4e97e4a749281185 src/ARV.Web.Reach/Scripts/app/core/filters.js 100644 blob a366e78d88695f3c1a2b5617ec03fd24387f2323 src/ARV.Web.Reach/Scripts/app/hird/incident.form.controller.js 100644 blob 461c0e11c1ad64a0bee7bb7f57ba9a99314b1510 src/Arv.Cases.External/App_Data/Arv.Cases.External.XML 100644 blob 276ace5a9dae6be5613beebedcfbf5a64f8e4c4b src/Arv.Services/Dtos/ReferenceDataDto.cs.orig 100644 blob 5336a10e14295222f28ef087643ac6696dc3cb73 src/Arv.Services/Reach/IIncidents.cs 100644 blob 6e186554f4de5347a754d39ebca1dd8867b7eb0a src/Arv.Services/Reach/Incidents.cs 100644 blob cf70ac7b4af8f9d8e89c2d84e45a23bdaf7c99de src/Arv.Services/ReferenceData.cs.orig 100644 blob 502e1286886624c6e0d46b9f65886fbc38b86bca src/Arv.Web.Core/Controllers/Reach/IncidentController.cs 100644 blob 5ef3891af8afa82dd7cdfc45058a6186e4656c34 src/Arv.Web.Core/Controllers/ReferenceController.cs 100644 blob 49e5d63ba2e59c6389c21c24b81809326711fd27 src/Arv.Web.Core/Controllers/ReferenceController.cs.orig`, `81372345058084750000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">100644 blob ea25f3a9fe6094d700588f33c340d32281a7614b src/ARV<span class="token punctuation">.</span>Database/ARV<span class="token punctuation">.</span>Database<span class="token punctuation">.</span>sqlproj<span class="token punctuation">.</span>orig 100644 blob 2e47fe1d11bd2624065866591af00f80f16e5e1e src/ARV<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Reach/Partials/hird/incident<span class="token punctuation">.</span>form<span class="token punctuation">.</span>campuses<span class="token punctuation">.</span>list<span class="token punctuation">.</span>html 100644 blob 2a6b2547ace20f6bbda788dc4e97e4a749281185 src/ARV<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Reach/Scripts/app/core/filters<span class="token punctuation">.</span>js 100644 blob a366e78d88695f3c1a2b5617ec03fd24387f2323 src/ARV<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Reach/Scripts/app/hird/incident<span class="token punctuation">.</span>form<span class="token punctuation">.</span>controller<span class="token punctuation">.</span>js 100644 blob 461c0e11c1ad64a0bee7bb7f57ba9a99314b1510 src/Arv<span class="token punctuation">.</span>Cases<span class="token punctuation">.</span>External/App_Data/Arv<span class="token punctuation">.</span>Cases<span class="token punctuation">.</span>External<span class="token punctuation">.</span>XML 100644 blob 276ace5a9dae6be5613beebedcfbf5a64f8e4c4b src/Arv<span class="token punctuation">.</span>Services/Dtos/ReferenceDataDto<span class="token punctuation">.</span>cs<span class="token punctuation">.</span>orig 100644 blob 5336a10e14295222f28ef087643ac6696dc3cb73 src/Arv<span class="token punctuation">.</span>Services/Reach/IIncidents<span class="token punctuation">.</span>cs 100644 blob 6e186554f4de5347a754d39ebca1dd8867b7eb0a src/Arv<span class="token punctuation">.</span>Services/Reach/Incidents<span class="token punctuation">.</span>cs 100644 blob cf70ac7b4af8f9d8e89c2d84e45a23bdaf7c99de src/Arv<span class="token punctuation">.</span>Services/ReferenceData<span class="token punctuation">.</span>cs<span class="token punctuation">.</span>orig 100644 blob 502e1286886624c6e0d46b9f65886fbc38b86bca src/Arv<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Core/Controllers/Reach/IncidentController<span class="token punctuation">.</span>cs 100644 blob 5ef3891af8afa82dd7cdfc45058a6186e4656c34 src/Arv<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Core/Controllers/ReferenceController<span class="token punctuation">.</span>cs 100644 blob 49e5d63ba2e59c6389c21c24b81809326711fd27 src/Arv<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Core/Controllers/ReferenceController<span class="token punctuation">.</span>cs<span class="token punctuation">.</span>orig</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>After checking a few of these blobs, I finally found the one which contained a version of the file close to the finishing state (yes I had to redo some of my work, but now I had to spend half an hour instead of a day).</p> <h2 id="checking-the-file" style="position:relative;"><a href="#checking-the-file" aria-label="checking the file permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking the file</h2> <p>Once we found the blob, we had to check what’s the content of those files. You can do that using:</p> <div class="gatsby-code-button-container" data-toaster-id="29735379230856520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git cat-file -p cf70ac7b`, `29735379230856520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">git <span class="token function">cat</span><span class="token operator">-</span>file <span class="token operator">-</span>p cf70ac7b</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now you can see the content printed out to the console. But if the file is bit enough like my situation, you could just pipe this command to write it to a file like so:</p> <div class="gatsby-code-button-container" data-toaster-id="85910037515168660000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git cat-file -p cf70ac7b | out-file temp.js`, `85910037515168660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">git <span class="token function">cat</span><span class="token operator">-</span>file <span class="token operator">-</span>p cf70ac7b <span class="token punctuation">|</span> <span class="token function">out-file</span> temp<span class="token punctuation">.</span>js</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>If you’re using <em>linux</em> or <em>Mac</em>, just use your version of the equivalent.</p> <p>And that’s it, repeat this until you have all of the files you need.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>A few lessons I learnt from this accident:</p> <ul> <li> <p>Always check you have added all your files before committing (I know it sounds obvious, but it could happen to you the way it happened to me).</p> </li> <li> <p>Always make sure you commit your changes often after each set of critical change.</p> </li> <li> <p>This one has become my preference now. Rebase from your local branch and not upstream:</p> </li> </ul> <div class="gatsby-code-button-container" data-toaster-id="28733538021313753000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git add . git commit -m &quot;Your awesome and informative commit message&quot; git checkout master git pull git checkout feature-branch git rebase master`, `28733538021313753000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">git add <span class="token punctuation">.</span> git commit <span class="token operator">-</span>m <span class="token string">"Your awesome and informative commit message"</span> git checkout master git pull git checkout feature-branch git rebase master</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <ul> <li>And if you lost your code, don’t give up, <code class="language-text">git</code> is a really powerful tool.</li> </ul> <p>Hope this helps someone to save some time in case of a similar accident.</p><![CDATA[Stop using `console.log`, start using your DevTools 🛠️]]>https://yashints.dev/blog/2020/03/19/debug-devtoolshttps://yashints.dev/blog/2020/03/19/debug-devtoolsThu, 19 Mar 2020 00:00:00 GMT<p>There are many situations where we want to see what’s wrong with out code without the trouble of changing source code and push the changes again, regardless of whether we’re using local environment or production. Most folks start by writing <code class="language-text">console.log</code> statements throughout their code base and go step by step to find the place where the bug is happening. That’s OK for beginners and where you have access to source code, but what if you don’t want to waste so much time or you don’t even have access to source code?</p> <!--more--> <h2 id="devtools" style="position:relative;"><a href="#devtools" aria-label="devtools permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>DevTools</h2> <p>All major browsers have developer tools (aka DevTools) nowadays. It’s important for us web developers to know them well not just because we use them as our daily drivers to test our applications and see how they look like once deployed, but also for times when something is wrong as we want to find them efficiently.</p> <p>That’s when the DevTools comes very handy if you know the ropes. DevTools have a lot of functionalities; refer to my articles <a href="https://yashints.dev/blog/2019/01/13/chromedevtools" target="_blank" rel="nofollow noopener noreferrer">Chrome DevTools can do that?</a> and <a href="https://yashints.dev/blog/2019/08/08/firefox-dev-tools" target="_blank" rel="nofollow noopener noreferrer">FireFox DevTools can do that?</a> to have a glimpse of some of these. However, in this article we only focus on debugging experience.</p> <h2 id="the-bug" style="position:relative;"><a href="#the-bug" aria-label="the bug permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The bug</h2> <p>In order to be able to have a common ground, we need a bug to fix. I’ve created <a href="https://glitch.com/edit/#!/debugger-demo" target="_blank" rel="nofollow noopener noreferrer">this demo</a> which will be working on in <a href="https://glitch.com/" target="_blank" rel="nofollow noopener noreferrer">Glitch</a>. In this demo, you would select a date and press the calculate age button. It will calculate your age and show it in the bottom section.</p> <p>However, there is a bug where sometimes it calculates the age by one year higher than actual. We will be looking into how to fix this.</p> <h2 id="devtoolss-debugger" style="position:relative;"><a href="#devtoolss-debugger" aria-label="devtoolss debugger permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>DevTools’s debugger</h2> <p>Both Chrome and Firefox have a debugger section we will be using in this article. I won’t go through Edge because it’s the same as Chrome.</p> <h3 id="chrome" style="position:relative;"><a href="#chrome" aria-label="chrome permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chrome</h3> <p>You can open your DevTools in Chrome using <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> on Windows or <kbd>Ctrl</kbd>+<kbd>Option</kbd>+<kbd>J</kbd>.</p> <p>Once opened, navigate to the <strong>Sources</strong> tab. You will see a file navigator pane on the left where you can inspect the files that the page uses. Then there is the editor pane in the middle where you can click on the file from the navigator pane and see the content and edit them locally in the browser. And last you will see the JavaScript debugging pane where you have a set of features which you’ll learn about shortly.</p> <blockquote> <p>💡 If you resize the DevTools you might see these panes in different positions.</p> </blockquote> <p><img src="/747a9023138d663f0ee47ceecf64bddf/chromedevtools.jpg" alt="Chrome DevTools Sources tab"></p> <h3 id="firefox" style="position:relative;"><a href="#firefox" aria-label="firefox permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Firefox</h3> <p>In Firefox you need to use <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd> on Windows or <kbd>Ctrl</kbd>+<kbd>Option</kbd>+<kbd>I</kbd> to open up the web developer tools.</p> <p>When opened, click on debugger tab which is very similar to what you saw before. On the left, you’ll see the navigation pane, next to it is editor pane and to the left (or below depending on how wide you’ve got your DevTools open) is the debug pane.</p> <p><img src="/b62cf79f3cab1f58d2a5b86faa600faa/firefoxdevtools.jpg" alt="Firefox DevTools debugger tab"></p> <h2 id="setting-a-breakpoint" style="position:relative;"><a href="#setting-a-breakpoint" aria-label="setting a breakpoint permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setting a breakpoint</h2> <p>When it comes to debugging, a common method is to use <code class="language-text">console.log</code> statements throughout the code base which sometimes is abused.</p> <div class="gatsby-code-button-container" data-toaster-id="92465717863640780000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const yo = document.querySelector('#yo'); function getAge() { console.log('Getting the date of birth value'); const dateString = document.querySelector('#age').value; console.log(\`date of birth is \${dateString}\`); var today = new Date(); var birthDate = new Date(dateString); var age = today.getFullYear() - birthDate.getFullYear(); console.log(\`age is \${age}\`); var m = today.getMonth() - birthDate.getMonth(); console.log(\`Birth month is \${m}\`); if (m < 0 || (m = 0 && today.getDate() < birthDate.getDate())) { console.log('The birth month is negative or is zero, we need to reduce the age by one year'); age--; console.log(\`Real age is \${age}\`); } yo.textContent = age; }`, `92465717863640780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> yo <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#yo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Getting the date of birth value'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> dateString <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#age'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">date of birth is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dateString<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> today <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> birthDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>dateString<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> age <span class="token operator">=</span> today<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> birthDate<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">age is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>age<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> m <span class="token operator">=</span> today<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> birthDate<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Birth month is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>m<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token punctuation">(</span>m <span class="token operator">=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> today<span class="token punctuation">.</span><span class="token function">getDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> birthDate<span class="token punctuation">.</span><span class="token function">getDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'The birth month is negative or is zero, we need to reduce the age by one year'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> age<span class="token operator">--</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Real age is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>age<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> yo<span class="token punctuation">.</span>textContent <span class="token operator">=</span> age<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And then you look at the console to see where the bug might be. But this process is painstakingly slow which impacts your productivity a lot. So let’s see how breakpoints help us get to the point real quick.</p> <p>Breakpoints have the advantage of being in real time compared to <code class="language-text">console.log</code> statements where you need to wait for the code to get deployed and inspect the console. Apart from that, with <code class="language-text">console.log</code> statements, you need to explicitly mention which values you want to expect whereas in a breakpoint debugger shows you all of them.</p> <p>Now let’s take one step back and see how we can go about finding where to set our breakpoint to. In some cases like this you will think OK, the age is correct sometimes and not others depending on the month. So you can find your file and set your breakpoint right where the <code class="language-text">if</code> condition is.</p> <p>In some other cases where the code base might be larger, or you might be new to the team, it makes sense to follow the flow of the page. In our case user selects a date and then clicks on the calculate age button.</p> <p>The logic behind happens under that click, you the best thing for us is to set a breakpoint on the click event listener. <strong>Event Listener Breakpoints</strong> are designed for this.</p> <h3 id="chrome-1" style="position:relative;"><a href="#chrome-1" aria-label="chrome 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chrome</h3> <p>In Chrome, in the debug page, click on the <strong>Event Listener Breakpoints</strong> and expand the section. Then find the <em>Mouse</em> category and select the click event.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 383px; " > <a class="gatsby-resp-image-link" href="/static/bffd8e2f8f9a2ca1a51cc884534f6f3e/411a4/chromeeventbreakpoint.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 202.22222222222223%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAoABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMBAgX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAH3NA0SplDh2J0AD//EABcQAAMBAAAAAAAAAAAAAAAAAAEQQTD/2gAIAQEAAQUCGNVX/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwFf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwFf/8QAFhAAAwAAAAAAAAAAAAAAAAAAEDBB/9oACAEBAAY/AjWf/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAERIRBRYZH/2gAIAQEAAT8hh0rRQgj0hyQ9EMWarP8A/9oADAMBAAIAAwAAABAzwDCAD//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8QX//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8QX//EAB0QAAICAgMBAAAAAAAAAAAAAAERADFBYRAhcaH/2gAIAQEAAT8QLuEReYndp4MIsseipkvk7hyonTgRYac0QlZY5IEBuuf/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Event listener break points for mouse click in Chrome" title="" src="/static/bffd8e2f8f9a2ca1a51cc884534f6f3e/411a4/chromeeventbreakpoint.jpg" srcset="/static/bffd8e2f8f9a2ca1a51cc884534f6f3e/6f81f/chromeeventbreakpoint.jpg 270w, /static/bffd8e2f8f9a2ca1a51cc884534f6f3e/411a4/chromeeventbreakpoint.jpg 383w" sizes="(max-width: 383px) 100vw, 383px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Now click on the calculate age button and DevTools will pause when the event listener executes. You might need to click on the <strong>Resume Script Execution</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 26px; " > <a class="gatsby-resp-image-link" href="/static/270133261d0c3a18a5824163cb358f02/d93cc/resume-script-execution.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 76.92307692307692%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAAsTAAALEwEAmpwYAAABrElEQVR42pWTSyhEURjHb8l4zJAiCxsskOys7JSSlZVSYmWehDyamhIlhYWIspAdWYgizyjFQsojjwXGIxlmMRPGPefce+695sznXGRhGNdZnU7n9/37f9//EwJPeHKbDq0qo+vKyJpy4SNhBfmD2OuT+EUiOMYRvPckr50J1RBXB0INzO1SAHR4JZX3s6FlNSRiKuv/EMIoGr7xk5IeZnFBRjOkN8LKgQ6f3JA8NzNZoWr4deNIfnzGhOCXKF649pPiLhZvg5QGsDhgaV+Hj6+lIg8z2SC+HnI7Ip0z2umtTGVeAYvIAFzo+XxMsOvvFQNsakt5DBGFYlH8LPEX7ALuKNkJ3EJWC1jHtT2vrFKkUWQINjvB4tRLJNkhyQYF7kj/gsI7xVtoCP7gU12Q1qi7EOrAPa2h/yk7INEG2a2R7ln18l4ypPzlObMJasfCO+cyN6wpxjwnOsBsh9JeNrGpBp+JSvVW84b/PWcumNMW6Zh6PbiSJQl/n/NvCct/T1jlYHhxn3JBng8xOmG/Zbusj/XNa4EnIr8L/pztH7fqIUjO7iRuj5MxtuoN0eyZdm4n410AAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="resume button" title="" src="/static/270133261d0c3a18a5824163cb358f02/d93cc/resume-script-execution.png" srcset="/static/270133261d0c3a18a5824163cb358f02/d93cc/resume-script-execution.png 26w" sizes="(max-width: 26px) 100vw, 26px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span> </span> if you’re using a platform like Glitch, but for your own app that won’t be needed. When the breakpoint reaches the button in your HTML, press Step into function <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 18px; " > <a class="gatsby-resp-image-link" href="/static/65a9018e3c40b516ffecc298e9762b79/428de/step-into.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 144.44444444444443%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCAIAAAAl5NuSAAAACXBIWXMAAAsTAAALEwEAmpwYAAACEUlEQVR42u1Uy+thcRy9/56Vn7zf5JVneRcLZedVyG6kZCULG2WhPEopimw8ig0ljzwySNSYM787ZLh+Zjs1Z3Hvt+89p3u+53zuJb4/4XQ62Ww2FosluILD4ej1+sPh8MAk/ov/GfHxeAT7crn8uAJrh8PxIDYYDA+c8/lM1Ov1XC4XjUa/XZFIJFQqFZfLvYl5PJ5cLo/H4zcO+Nlslmg2m7jpdDoajfbxCTqdDrbgT/D5/I8rwFSr1el0moDnzWZTqVRgFfZAErwGnoJjsVgKhcJqtfoVGJLY7XatVsvpdAqFwld6ch9Z1mo1UvU77d0nBoOBy+WSSCSUYpFIBHedTockU1Q1mUy8Xq9YLL5/P9bYcbvdo9HoTc/L5TIcDkulUjI2XOElEAjMZrP3QwJLi8UimUwqlUoGg4GS0M2zklpMhjGfzzOZjMfjSaVS0+n0ebxeigFMHs7f7XbH4zHWlBxqMZxDQI4hgDUZ71+dGSb7/X6pVMrn88ViEfXs9/tnPbW40WiEQiGFQoF5QmA+nw+Dsd1u34uHw6HZbGYymfg20DCqYrPZGP5er/dGjNfGYrFbybchQdXwgq/g3jzxoATsdvttku9hNBrX6/UbsdVqpRTjZ/KVmNRHIhGYfLCN2UZsX9kmgWJMJtMtMFzxS9JoNO12+yFw6qqq1WowGIRPmUym1Wr9fn+5XH6u6ifkg/drOVvsKQAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Step into function button" title="" src="/static/65a9018e3c40b516ffecc298e9762b79/428de/step-into.png" srcset="/static/65a9018e3c40b516ffecc298e9762b79/428de/step-into.png 18w" sizes="(max-width: 18px) 100vw, 18px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span> </span> and you’ll end up in our <code class="language-text">getAge</code> function. Once you’ve stepped into the function you wanted, you can go one line at a time by clicking on the step over button or pressing <kbd>F10</kbd>.</p> <p><img src="/2f49357f26e80756caa7edb7cdf77fbc/breakpointchrome.gif" alt="Mouse click breakpoint in Chrome"></p> <h3 id="firefox-1" style="position:relative;"><a href="#firefox-1" aria-label="firefox 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Firefox</h3> <p>You can use the same approach to enable a mouse click event listener breakpoint in Firefox, simply expand the <strong>Event Listener Breakpoints</strong> section in the debugger pane, then expand Mouse and select the click event.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; " > <a class="gatsby-resp-image-link" href="/static/a06ab13b3e8c1d082551f8bd5a632a91/b4294/firefox-mouseclickbreakpoint.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 132.5925925925926%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIDBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHtUVyAoWojGcA//8QAGxAAAQQDAAAAAAAAAAAAAAAAEAECAzEAIUL/2gAIAQEAAQUCDl2JLQSX1j7/AP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABQQAQAAAAAAAAAAAAAAAAAAADD/2gAIAQEABj8CT//EABoQAAEFAQAAAAAAAAAAAAAAAAABECExsRH/2gAIAQEAAT8h7JAkEuWxL22IlmzP/9oADAMBAAIAAwAAABCw2Q3/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAeEAEAAgEFAQEAAAAAAAAAAAABABEhEDFBUfBxgf/aAAgBAQABPxAIsv7tBRY38gjQuOEjGtKlHUFGvMzJVgPGm35zNj1ocY//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox mouse click breakpoint" title="" src="/static/a06ab13b3e8c1d082551f8bd5a632a91/b4294/firefox-mouseclickbreakpoint.jpg" srcset="/static/a06ab13b3e8c1d082551f8bd5a632a91/6f81f/firefox-mouseclickbreakpoint.jpg 270w, /static/a06ab13b3e8c1d082551f8bd5a632a91/09d21/firefox-mouseclickbreakpoint.jpg 540w, /static/a06ab13b3e8c1d082551f8bd5a632a91/b4294/firefox-mouseclickbreakpoint.jpg 600w" sizes="(max-width: 600px) 100vw, 600px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Once enables, you could follow the same procedure we described before. First click on the calculate age button and the debugger automatically pauses on the first function call. In case of using a platform like Glitch or CodePen, that might not be what you’re after, so simply press the <strong>Resume</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 40px; " > <a class="gatsby-resp-image-link" href="/static/501c68561b6f855c6cf1de6ce7ace252/92935/firefoxplaypause.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 105%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAVABQDASIAAhEBAxEB/8QAGAABAQADAAAAAAAAAAAAAAAAAAEDBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHtXFDZBKAH/8QAGhAAAgIDAAAAAAAAAAAAAAAAAQIAEgMRIP/aAAgBAQABBQJ2qFYMJlOgBd+P/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHhAAAQIHAQAAAAAAAAAAAAAAAQACEBESICExUrH/2gAIAQEABj8C1NYg0npB4FI9t//EABwQAQACAgMBAAAAAAAAAAAAAAEQEQBBMWFx4f/aAAgBAQABPyGmbJaAyxP3qCQUAtxKQN7+YQeZ/9oADAMBAAIAAwAAABBjDzz/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEBAAEFAQAAAAAAAAAAAAABERAAIUFRcTH/2gAIAQEAAT8QlxW0Cr7rfkjAkV0nDgtDtGAb6aACWQ+k49b+YAgE+xLn/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox resume button" title="" src="/static/501c68561b6f855c6cf1de6ce7ace252/92935/firefoxplaypause.jpg" srcset="/static/501c68561b6f855c6cf1de6ce7ace252/92935/firefoxplaypause.jpg 40w" sizes="(max-width: 40px) 100vw, 40px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span> </span> button until you see the breakpoint stop at the <code class="language-text">getAge</code> function. Then click on the <strong>Step In</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 24px; " > <a class="gatsby-resp-image-link" href="/static/b79eefda6281883132a3243493b5955e/0bf61/firefoxstepin.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 83.33333333333334%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAARABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAECBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHuVZjagWBAP//EABoQAQEAAgMAAAAAAAAAAAAAAAECABAREiD/2gAIAQEAAQUCXjJrtq0CSpfH/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHBAAAgICAwAAAAAAAAAAAAAAAREAIQJBECAy/9oACAEBAAY/AvJMNELiyo8zT1vr/8QAGxABAQEAAgMAAAAAAAAAAAAAAREAEDFRcZH/2gAIAQEAAT8hbp6Mx9wUR4mUrpDIz1RD9YaXzjHH/9oADAMBAAIAAwAAABATwDz/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAdEAEAAgICAwAAAAAAAAAAAAABESEAMRCBQWGR/9oACAEBAAE/EDy63On1McJUAzPS8UT2yUTzQ4DtGGS6UesAg0JJzZzbj//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox step in button" title="" src="/static/b79eefda6281883132a3243493b5955e/0bf61/firefoxstepin.jpg" srcset="/static/b79eefda6281883132a3243493b5955e/0bf61/firefoxstepin.jpg 24w" sizes="(max-width: 24px) 100vw, 24px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span> </span> button or press <kbd>F11</kbd> to go inside the function. Once you’re inside the function simply press <strong>Step over</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 18px; " > <a class="gatsby-resp-image-link" href="/static/28df88b8fcd63653687b9d1528a2c4a1/156d6/firefoxstepover.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 88.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAGQABAAMBAQAAAAAAAAAAAAAAAAECAwQF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB9yKYnYoIzDoB/8QAHBAAAgICAwAAAAAAAAAAAAAAAQIAAxASETIz/9oACAEBAAEFAiQIGDY15st2iDVX6UeE/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHBAAAgIDAQEAAAAAAAAAAAAAAAECIRARcUGB/9oACAEBAAY/Areinht/DcYX40JEuEOY/8QAHBABAAEEAwAAAAAAAAAAAAAAAQAQETFhIaHh/9oACAEBAAE/ITbkNzHTTiO4FpBcK+yacneVD//aAAwDAQACAAMAAAAQ4A88/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHRABAAICAgMAAAAAAAAAAAAAAREhADFRgRBB8P/aAAgBAQABPxCxwRKjJsXLQbOsEdM4ImCBsOWOdY8BCVHYGK3qcvVUWvtyrn2ONUVWFvj/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox step over button" title="" src="/static/28df88b8fcd63653687b9d1528a2c4a1/156d6/firefoxstepover.jpg" srcset="/static/28df88b8fcd63653687b9d1528a2c4a1/156d6/firefoxstepover.jpg 18w" sizes="(max-width: 18px) 100vw, 18px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span> </span> button or <kbd>F11</kbd> to go line by line from thereon.</p> <p><img src="/252ca5c56aa00b316ffccba44665a81b/firefoxclickbreakpoint.gif" alt="Firefox mouse click breakpoint"></p> <h2 id="line-breakpoint" style="position:relative;"><a href="#line-breakpoint" aria-label="line breakpoint permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Line breakpoint</h2> <p>Line breakpoints are mainly used when you’ve narrowed down where the bug might actually be. In our case when we stepped through the <code class="language-text">getAge</code> function, we saw that the age is calculated based on the year, then there is an if condition which will be responsible to reduce the age by one if the month is less than the current month minus the month of birth.</p> <p>So we roughly know that if the age is calculated right in some cases and wrong by one year in others, the if condition is where we should set our line breakpoint on.</p> <p>There are two ways to do this in DevTools, one is to follow the event listener breakpoint flow explained above. But if you know the filename beforehand, you can simply open the file in the editor pane and scroll through until you reach the line you want.</p> <p>Once you’re there, simply click the line number and it will put a <strong>Line Breakpoint</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 34px; " > <a class="gatsby-resp-image-link" href="/static/18dd708cb3542c6fb2b4bd9d923f3f88/fec30/linebreakpoint.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 47.05882352941176%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMCBf/EABUBAQEAAAAAAAAAAAAAAAAAAAQF/9oADAMBAAIQAxAAAAGe4qIO6snu/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAIBAxAy/9oACAEBAAEFAhSiWmrF5//EABYRAQEBAAAAAAAAAAAAAAAAAAABMf/aAAgBAwEBPwFMf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAMf/aAAgBAgEBPwFJ2//EABcQAQEBAQAAAAAAAAAAAAAAAAEAERD/2gAIAQEABj8CnVjel//EABwQAAEEAwEAAAAAAAAAAAAAAAEAESFREHGRof/aAAgBAQABPyFzZ6mEMERKKg6N58y//9oADAMBAAIAAwAAABDM7//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxAUY4C//8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAECAQE/EBSepy//xAAeEAACAQMFAAAAAAAAAAAAAAAAASEQEUFRcZGh8f/aAAgBAQABPxD3xKIVza+di/mcpjlMOmUdGf/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Line Breakpoint icon" title="" src="/static/18dd708cb3542c6fb2b4bd9d923f3f88/fec30/linebreakpoint.jpg" srcset="/static/18dd708cb3542c6fb2b4bd9d923f3f88/fec30/linebreakpoint.jpg 34w" sizes="(max-width: 34px) 100vw, 34px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span> </span> icon on that line so that you’d know where the breakpoint is set. You can remove the breakpoint by simply clicking on it again.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 478px; " > <a class="gatsby-resp-image-link" href="/static/f26cdc68eb50c273efdd2c7472a3219d/0c439/linebreakpointcode.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 48.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHuVtIpf//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEAAQUCX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAQACAwAAAAAAAAAAAAAAAAEAIREgUf/aAAgBAQABPyG2whnmv//aAAwDAQACAAMAAAAQzw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAACAwEBAAAAAAAAAAAAAAABEQAhMRDR/9oACAEBAAE/EDUQGGiMifCgzI77/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Line breakpoint" title="" src="/static/f26cdc68eb50c273efdd2c7472a3219d/0c439/linebreakpointcode.jpg" srcset="/static/f26cdc68eb50c273efdd2c7472a3219d/6f81f/linebreakpointcode.jpg 270w, /static/f26cdc68eb50c273efdd2c7472a3219d/0c439/linebreakpointcode.jpg 478w" sizes="(max-width: 478px) 100vw, 478px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Now if you click the calculate age button, the program stops on the if condition. This part is exactly the same in both Chrome and Firefox.</p> <h2 id="checking-variable-values" style="position:relative;"><a href="#checking-variable-values" aria-label="checking variable values permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking variable values</h2> <p>When you’re stopped at the if condition, if you want to see what is the value of a variable, simply have a look at the debugger pane’s <strong>Scope</strong> section in Chrome or <strong>Scopes</strong> section in Firefox.</p> <h3 id="chrome-2" style="position:relative;"><a href="#chrome-2" aria-label="chrome 2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chrome</h3> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 948px; " > <a class="gatsby-resp-image-link" href="/static/49ae1e69c058eab1ab6c6609c5be18be/64e16/chromescope.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 38.51851851851852%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd2AsD//xAAWEAEBAQAAAAAAAAAAAAAAAAAAEUH/2gAIAQEAAQUCjX//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAZEAABBQAAAAAAAAAAAAAAAAARABAhQVH/2gAIAQEAAT8hLULS3//aAAwDAQACAAMAAAAQcA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAADAAMBAAAAAAAAAAAAAAAAAREhQVGB/9oACAEBAAE/EMmvgpam0Gl2H//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Scope section in Chrome&#39;s debug pane" title="" src="/static/49ae1e69c058eab1ab6c6609c5be18be/64e16/chromescope.jpg" srcset="/static/49ae1e69c058eab1ab6c6609c5be18be/6f81f/chromescope.jpg 270w, /static/49ae1e69c058eab1ab6c6609c5be18be/09d21/chromescope.jpg 540w, /static/49ae1e69c058eab1ab6c6609c5be18be/64e16/chromescope.jpg 948w" sizes="(max-width: 948px) 100vw, 948px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h3 id="firefox-2" style="position:relative;"><a href="#firefox-2" aria-label="firefox 2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Firefox</h3> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 886px; " > <a class="gatsby-resp-image-link" href="/static/0a4db696d8d23420ec7288a50cc025a8/72f09/firefoxscopes.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 53.333333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAIBBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe6uSWj/xAAXEAADAQAAAAAAAAAAAAAAAAAAARAR/9oACAEBAAEFAsHXP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABYQAAMAAAAAAAAAAAAAAAAAABAgMf/aAAgBAQAGPwIRP//EABsQAAICAwEAAAAAAAAAAAAAAAABEXEQMUFR/9oACAEBAAE/IbEoXaJfvGgj/9oADAMBAAIAAwAAABCb7//EABcRAQADAAAAAAAAAAAAAAAAAAABEVH/2gAIAQMBAT8QVOv/xAAWEQEBAQAAAAAAAAAAAAAAAAAAIVH/2gAIAQIBAT8QTH//xAAcEAEAAgEFAAAAAAAAAAAAAAABABExEFGRodH/2gAIAQEAAT8QENnSVWGewlmec91FRP/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Scopes section in Chrome&#39;s debug pane" title="" src="/static/0a4db696d8d23420ec7288a50cc025a8/72f09/firefoxscopes.jpg" srcset="/static/0a4db696d8d23420ec7288a50cc025a8/6f81f/firefoxscopes.jpg 270w, /static/0a4db696d8d23420ec7288a50cc025a8/09d21/firefoxscopes.jpg 540w, /static/0a4db696d8d23420ec7288a50cc025a8/72f09/firefoxscopes.jpg 886w" sizes="(max-width: 886px) 100vw, 886px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="spotting-the-bug" style="position:relative;"><a href="#spotting-the-bug" aria-label="spotting the bug permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Spotting the bug</h2> <p>Now let’s see where the bug is and how to fix it. If you have a look at the if condition more closely, you’ll see that there are two main parts in there. First one is <code class="language-text">m &lt; 0</code> to check whether the month is less than zero, and the second is <code class="language-text">m = 0 &amp;&amp; today.getDate() &lt; birthDate.getDate()</code> to check if the month is zero and today is less than birthday.</p> <p>Now we know that someone’s used an equal sign instead of equality operator which has caused this bug. So let’s replace the <code class="language-text">=</code> with <code class="language-text">===</code> and then press <kbd>Ctrl</kbd>+<kbd>S</kbd> to save the changes. You can leave the breakpoint or remove it test with some dates to see if the bug is fixed or not. But after some tests we know that the bug is fixed. It’s time for you to go and write a test for this function so you won’t face the same bug again 😁.</p> <h2 id="console-window" style="position:relative;"><a href="#console-window" aria-label="console window permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Console window</h2> <p>Don’t forget that you can evaluate your expressions in the console window of the browser. As in you could simply put your condition in the console and see whether it’s returning <code class="language-text">true</code> or <code class="language-text">false</code>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 410px; " > <a class="gatsby-resp-image-link" href="/static/f797b0fd457c2e9bb9dbbedf0fcafcca/0d3fb/consoleexpressionevaluation.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 21.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAEABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3gUH/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFhABAQEAAAAAAAAAAAAAAAAAAAER/9oACAEBAAE/IYxH/9oADAMBAAIAAwAAABAAD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABcQAAMBAAAAAAAAAAAAAAAAAAABEeH/2gAIAQEAAT8QSrCZiEih/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Evaluating expressions in console window" title="" src="/static/f797b0fd457c2e9bb9dbbedf0fcafcca/0d3fb/consoleexpressionevaluation.jpg" srcset="/static/f797b0fd457c2e9bb9dbbedf0fcafcca/6f81f/consoleexpressionevaluation.jpg 270w, /static/f797b0fd457c2e9bb9dbbedf0fcafcca/0d3fb/consoleexpressionevaluation.jpg 410w" sizes="(max-width: 410px) 100vw, 410px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="what-else" style="position:relative;"><a href="#what-else" aria-label="what else permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What else?</h2> <p>There are heaps of other breakpoints you could use such as conditional breakpoints which are triggered only if a condition you provide is <code class="language-text">true</code>, breakpoints on caught and uncaught exceptions, and XHR breakpoints which are triggered when a URL matches a substring you’ve set. Let’s try a XHR breakpoint in , open up your DevTools, head over to debug pane and open the <strong>XHR Breakpoints</strong> section. Click in the box to add a line and enter <code class="language-text">raw</code> and press <kbd>Enter</kbd>. Now refresh the page and you’ll see the breakpoint hit when the request is made. You can now use the same technique we saw earlier to step in the code and set a like breakpoint to debug further.</p> <h2 id="small-catch" style="position:relative;"><a href="#small-catch" aria-label="small catch permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Small catch</h2> <p>One catch is that you need to make sure that the function you’re debugging is in the scope which is tricky if you’re using DevTools. In order to get it working you need to set a line breakpoint somewhere where the function is in scope, then trigger the breakpoint and call <code class="language-text">debug()</code> in the DevTools console while the code is still paused on the line breakpoint.</p> <div class="gatsby-code-button-container" data-toaster-id="59841837111534320000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`(function () { function hello() { console.log('hello'); } function world() { console.log(' world'); } hello(yo); // This works. world(); })(); debug(hello); // This doesn't work. hey() is out of scope.`, `59841837111534320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">world</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">' world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">hello</span><span class="token punctuation">(</span>yo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This works.</span> <span class="token function">world</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">debug</span><span class="token punctuation">(</span>hello<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This doesn't work. hey() is out of scope.</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw how powerful the DevTools are and how much they can help us to find and fix bugs in our code. So stop using <code class="language-text">console.log</code> and get to know your DevTools better. Happy coding from home ❤️.</p><![CDATA[What you need to know about Full screen API 💻]]>https://yashints.dev/blog/2020/03/10/fullscreen-apihttps://yashints.dev/blog/2020/03/10/fullscreen-apiTue, 10 Mar 2020 00:00:00 GMT<p>There are many situations where we’d like to see our web page in fullscreen mode. Be it games, online courses, video tutorials, or simply wanting more reading space while reading a book. What we usually do in these sort of scenarios is we manually set our browser’s tab/window in fullscreen mode (<kbd>F11</kbd>), but the result is not always what we expect, because some content is not designed to be viewed in fullscreen mode. Besides, what if we help our users to go fullscreen automatically instead, again it all comes to having a better user experience.</p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API" target="_blank" rel="nofollow noopener noreferrer">Full Screen API</a> adds methods to the HTML <code class="language-text">Element</code> to enable us to programmatically turn any content on a page to enter in fullscreen mode via JavaScript. <code class="language-text">WebGL</code>, <code class="language-text">canvas</code>, and <code class="language-text">video</code> elements are the usual targets when it comes to going fullscreen. Online newspapers and magazines are other areas where this can be helpful.</p> <p>So let’s see this in action first and then go through some details:</p> <iframe height="265" style="width: 100%;" scrolling="no" title="Full Screen API Demo" src="https://codepen.io/yashints/embed/preview/mdJpqYx?height=265&theme-id=light&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/mdJpqYx'>Full Screen API Demo</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <p>All we’re doing here is to call a method which is added by the Full Screen API:</p> <div class="gatsby-code-button-container" data-toaster-id="73531617577875590000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const vid = document.getElementById('shuttle'); function toggleFullScreen() { if (!document.fullscreenElement && vid.requestFullscreen) { vid.requestFullscreen(); } else { if (document.exitFullscreen) { document.exitFullscreen(); } } } document.addEventListener(&quot;keydown&quot;, function(e) { if (e.keyCode == 13) { toggleFullScreen(); } }, false);`, `73531617577875590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> vid <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'shuttle'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">toggleFullScreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>document<span class="token punctuation">.</span>fullscreenElement <span class="token operator">&amp;&amp;</span> vid<span class="token punctuation">.</span>requestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> vid<span class="token punctuation">.</span><span class="token function">requestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>exitFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">exitFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"keydown"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>keyCode <span class="token operator">==</span> <span class="token number">13</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">toggleFullScreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="exposed-properties" style="position:relative;"><a href="#exposed-properties" aria-label="exposed properties permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Exposed properties</h2> <p>There are two properties exposed on the <code class="language-text">document</code> object:</p> <p>💡 <strong><code class="language-text">DocumentOrShadowRoot.fullscreenElement</code></strong></p> <p>The <code class="language-text">fullscreenElement</code> property will give you the element that is displayed in fullscreen mode at the moment. It’s a way to check whether we’re in full screen mode or not.</p> <p>💡 <strong><code class="language-text">Document.fullscreenEnabled</code></strong></p> <p>The <code class="language-text">fullscreenEnabled</code> property tells you whether or not the document is currently in a state that would allow fullscreen mode to be requested.</p> <h2 id="exiting-fullscreen" style="position:relative;"><a href="#exiting-fullscreen" aria-label="exiting fullscreen permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Exiting fullscreen</h2> <p>You’ll want to be sure to let your users know that they can press the <kbd>Esc</kbd> key (or <kbd>F11</kbd>) to exit fullscreen mode.</p> <p>In addition, navigating to another page, changing tabs, or switching to another application (using, for example, <kbd>Alt</kbd>-<kbd>Tab</kbd>) while in fullscreen mode exits fullscreen mode as well.</p> <p>As you saw in the example above, exiting the fullscreen mode can be done using <code class="language-text">document.exitFullscreen</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="20149396862981070000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if (document.exitFullscreen) { document.exitFullscreen(); }`, `20149396862981070000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>exitFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">exitFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="feature-detection" style="position:relative;"><a href="#feature-detection" aria-label="feature detection permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Feature detection</h2> <p>You can simply detect whether the feature is supported or not using either <code class="language-text">document.requestFullscreen</code> or <code class="language-text">Element.requestFullscreen</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="25393447962627990000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if(element.requestFullscreen) { element.requestFullscreen(); }`, `25393447962627990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">if</span><span class="token punctuation">(</span>element<span class="token punctuation">.</span>requestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> element<span class="token punctuation">.</span><span class="token function">requestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>or:</p> <div class="gatsby-code-button-container" data-toaster-id="39974229463510520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if(document.requestFullscreen) { // enter fullscreen mode }`, `39974229463510520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">if</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>requestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// enter fullscreen mode</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="finding-whether-or-not-youre-in-fullscreen-mode" style="position:relative;"><a href="#finding-whether-or-not-youre-in-fullscreen-mode" aria-label="finding whether or not youre in fullscreen mode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Finding whether or not you’re in fullscreen mode</h2> <p>As mentioned earlier, the <code class="language-text">document.fullscreenElement</code> is a good way to check whether the browser is in full screen mode or not. The value of this property will be <code class="language-text">null</code> if we’re not in fullscreen, and the current fullscreen element otherwise.</p> <div class="custom-block warning"><div class="custom-block-body"> ⚠️ There is also a <code class="language-text">boolean</code> property called <code class="language-text">fullscreen</code> which is deprecated and should not be used. Although most of the browsers still support it.</div></div> <h2 id="presentation" style="position:relative;"><a href="#presentation" aria-label="presentation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Presentation</h2> <p>When toggling fullscreen mode programmatically, you’re responsible for how the elements will look like and what appears on the screen. It’s obvious you will need to change the width and height of the element to <code class="language-text">%100</code>, and fortunately, there is a CSS pseudo-selector for you to use:</p> <div class="gatsby-code-button-container" data-toaster-id="13898467466611630000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`#shuttle:fullscreen { width: 100%; height: 100%; }`, `13898467466611630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">#shuttle:fullscreen</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Also you might want to hide some other elements on the screen to reduce clutter:</p> <div class="gatsby-code-button-container" data-toaster-id="75907844657769510000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`:fullscreen .hide { display: none; }`, `75907844657769510000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">:fullscreen .hide</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="browser-support" style="position:relative;"><a href="#browser-support" aria-label="browser support permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Browser support</h2> <p>The browser support is really good at this point, almost all major browsers fully support it. Only <strong>IE11</strong> and <strong>Safari</strong> have partial support. Opera mini and Android Browser do not support it at this point.</p> <p><img src="/2f6bdf83bea61460d60ed9d65117439e/caniuse.png" alt="Browser support for Full Screen API"></p> <p>Hope you’ve learned a new trick if you didn’t know about this API and happy fullscreening (just made up the word 😁).</p><![CDATA[Stop gobbling up that memory 🛑]]>https://yashints.dev/blog/2020/02/28/mem-leakhttps://yashints.dev/blog/2020/02/28/mem-leakFri, 28 Feb 2020 00:00:00 GMT<p>I’ve been writing web applications for more than a decade. From <em>classic ASP</em> to <em>PHP</em>, <em>ASP.Net web forms</em> and the list goes on and on. However, something that’s been common between all those years for me has been to care about how performing the site is. One important part of that has been to look out for memory leaks, because they can cause the page to go super slow or even crashing in more serious scenarios.</p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p>Memory leaks are a common problem in software development, regardless of whether the language you’re using is memory managed or not. By that I mean languages which come with a garbage collector. Memory leaks happen when a piece of memory is allocated, but never freed by the application, and is not returned to the container app or the operating system.</p> <p>I remember going through the concept in uni, but I can’t remember anything apart from the fact that usually there is a tree made up of all the occupied memory locations. Every time the garbage collector is looking into the memory parses that tree, and if a node is not connected to any branch, it gets recollected and returned to the main program.</p> <p>Most of us web developers are likely to use one of the major frameworks or libraries to write our applications. Some maybe using a bit older languages like PHP or Ruby, but no matter what we use, there will be a high chance that we come face to face with this problem one way or another.</p> <h2 id="consequences" style="position:relative;"><a href="#consequences" aria-label="consequences permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Consequences</h2> <p>So what happens when there is a memory leak in our applications 🤔?</p> <p>In some cases the memory consumption just keeps going up. If the user is using a decent spec machine, they might not even realise it. Not everyone is obsessed like us developers checking their task manager often to see how much memory is consumed.</p> <p>Regardless, it slows down the page, makes interactions not responsive, and might even cause the tab or the whole window to crash.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 454px; " > <a class="gatsby-resp-image-link" href="/static/cdb290cc2bda873f8fddf9f864018bbb/b3c1d/memoryleak.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 63.70370370370371%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAABU0lEQVR42qVT2U7DMBDMv/MR/AAgIcQv9AmJSjxUPKRtAki5KCKHczmNkjhexm56qkKQWhrtOrbH49mNEQTBSxzHLvCeJMnHGODsW5Zlq/l8/mCs1+uQNkPSyNFjqAhxU4Mx9u15HjmO07dtK8egaRqhCMHxbIA1XC6XBLkS0klKSdhEXdf9GSDsB8KpAZIwiiLyfV9yzv9FdJawLMtw8EEqdcqOiwjjOAp936PPr5W0bFsp1c9WG4UQZ9GL/mgOi/aEKHcIlcTSVEZxRAljVNc1VVW1AzoBke9yrnM+5BXh/DGhWkS1ZVEUtEWe5xpYR8woRcQe/Y2lbJMXOaWIqMPvHupnIW4hRH80P/0Oe/aEuH3FealublHlDn50DdCeAMbv8/Yw12uNInRd98mAL1qhatCh4S/7U2az12vbtu8ty7pFg9+ZpjkGN4vF4nEymVz9AHP3234WL8NyAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Memory leak in google chrome" title="" src="/static/cdb290cc2bda873f8fddf9f864018bbb/b3c1d/memoryleak.png" srcset="/static/cdb290cc2bda873f8fddf9f864018bbb/01bf6/memoryleak.png 270w, /static/cdb290cc2bda873f8fddf9f864018bbb/b3c1d/memoryleak.png 454w" sizes="(max-width: 454px) 100vw, 454px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="memory-leak-in-javascript" style="position:relative;"><a href="#memory-leak-in-javascript" aria-label="memory leak in javascript permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Memory leak in JavaScript</h2> <p>It’s way easy in JavaScript to allocate some memory and forget about it. Even if you’re not writing plain JavaScript, it’s still possible that a memory leak happen, without you noticing it.</p> <h3 id="but-how-does-it-happen" style="position:relative;"><a href="#but-how-does-it-happen" aria-label="but how does it happen permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>But how does it happen?</h3> <p>In JavaScript there are a few possible ways a memory leak can happen.</p> <ul> <li>Unintentionally creating global variables</li> <li>Timers and callbacks</li> <li>Out of DOM references</li> <li>Closures</li> <li>Event listeners</li> </ul> <h3 id="global-variables" style="position:relative;"><a href="#global-variables" aria-label="global variables permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Global variables</h3> <p>It’s very simple to create an unwanted global variable in JavaScript. Consider below code:</p> <div class="gatsby-code-button-container" data-toaster-id="51585912225749420000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function helloWorld() { name = 'Yas'; console.log(\`Hello \${name}\`); }`, `51585912225749420000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">helloWorld</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> name <span class="token operator">=</span> <span class="token string">'Yas'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>In this simple function we have created a global variable called name. We didn’t want to, but we did it anyway.</p> <blockquote> <p>💡 A reference to an undeclared variable creates a new variable inside the global object.</p> </blockquote> <p>Same thing can happen if you use <code class="language-text">this</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="49211717792267180000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function helloWorld(args) { this.name = 'Yas'; console.log(\`Hello \${name}\`); }`, `49211717792267180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">helloWorld</span><span class="token punctuation">(</span><span class="token parameter">args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Yas'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block danger"><div class="custom-block-body"> To prevent these sorts of leaks, use JavaScript in <code class="language-text">strict</code> mode. You can do it by adding <code class="language-text">use strinct;</code> at the top of your JavaScript file.</div></div> <p>Even thought we consider accidental global variables one of the memory leak sources, there are still many global variables defined by the framework we use, or even the ones we intend to be there. Remember these are non collectable variables and unless nulled or reassigned, garbage collectors can’t do anything about them.</p> <h3 id="timers-and-callbacks" style="position:relative;"><a href="#timers-and-callbacks" aria-label="timers and callbacks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Timers and callbacks</h3> <p>The use of <code class="language-text">setInternal</code> and <code class="language-text">setTimeout</code> has gotten less and less popular as we’ve moved towards more modern concepts like <code class="language-text">async/await</code>. Furthermore, some libraries and frameworks provide observables to facilitate callbacks. In which case they’re responsible for making sure the callbacks are unreachable once their own instance gets destroyed.</p> <p>However, there are quite a number of scenarios where we need to use it in order to call a function at a later time or on a schedule.</p> <div class="gatsby-code-button-container" data-toaster-id="38325495827427880000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let data = fetchData(); setInternal(function() { let node = document.querySelector('#list'); // loop through data and create the html node.innerHTML = transform(data); }, 1000)`, `38325495827427880000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setInternal</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> node <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#list'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// loop through data and create the html</span> node<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token function">transform</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This example shows how a timer can turn into something that cannot be collected. Even if the list node is removed from the DOM, the reference inside the handler remains active and cannot be collected. That causes their dependencies to be non collectable as well. So the data variable which might be really large, would sit in memory long after its need has ended.</p> <p>Now let’s see how we can improve this to avoid a memory leak:</p> <div class="gatsby-code-button-container" data-toaster-id="40458136445738615000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let node = document.querySelector('#list'); let data = fetchData(); function handler(data) { if(node) { // do stuff with data and create the list node.innerHTML = transform(data); } }; setInterval(handler, 1000);`, `40458136445738615000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> node <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#list'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handler</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// do stuff with data and create the list</span> node<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token function">transform</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token function">setInterval</span><span class="token punctuation">(</span>handler<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="out-of-dom-references-detached-dom" style="position:relative;"><a href="#out-of-dom-references-detached-dom" aria-label="out of dom references detached dom permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Out of DOM references (detached DOM)</h3> <p>When some nodes are removed from the DOM but still exists in memory through JavaScript, we have out of DOM references or detached DOM. Usually it means there is a reference to a variable which was referencing that node.</p> <p>DOM is a doubly linked tree, meaning any reference to any node would mean the entire tree would not be garbage collected.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 700px; " > <a class="gatsby-resp-image-link" href="/static/9d443868683b68fba2c69fac2697b125/8c557/doublylinkedtree.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 67.4074074074074%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABsklEQVR42lVSh5acMAzk/38ue5e8e3k5WExZsxQbFwwGY8hQtpwA4yJ5RiMF67oueHYbnR0mY6ce4zhbrpqquWvdSSnVYVIvy+kMC/DN3ikrxcCN1f3Y4TVjZ92QVUl+zzhjDYM1nPMw/ad6+cQLnHetaaZ5XF83rsfcCNnWTWcMILXWpjO0zpmuwOtElkMLto+Q5XwXvwWzZhDtfvB+8dr2bANDsOjZ+gP0NLClcUKTFBMsvffLbps0swXkM/il2Tb33jJWxeQj/PUn+iij2ArxrpNfvBw4dhDMz+D9GBlSQrKvv2VbQgvW1RUvye/PsiiQ9p7B5iZ7DpnP4BPTTTQK6Y2GWRTTEDvILS/Ta3bNsryIwnV2BwHQ3oLbvsHPjlN9L8jloqUECTVIbeVxI8qR8RibWsjkcmF13Q+DOJDVINwyFRWNrt+ExLS6bTqj2o96gCdwMOIoTUgKo4R3tV/mAMSQABaTGyEpMCGG2PV4poO2AUHZt/M8wwel7aw6Owzg3aiers5PoHTW9lH4yU9H8d8teDXU7m2lFEmq8lzmeRvHLSGYqNvNVPX6owO39vwPbwPtUDZoATEAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Doubly linked tree" title="" src="/static/9d443868683b68fba2c69fac2697b125/8c557/doublylinkedtree.png" srcset="/static/9d443868683b68fba2c69fac2697b125/01bf6/doublylinkedtree.png 270w, /static/9d443868683b68fba2c69fac2697b125/07484/doublylinkedtree.png 540w, /static/9d443868683b68fba2c69fac2697b125/8c557/doublylinkedtree.png 700w" sizes="(max-width: 700px) 100vw, 700px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Let’s go through an example to make this a bit more clear:</p> <div class="gatsby-code-button-container" data-toaster-id="94865107132604680000" data-toaster-class="gatsby-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 create() { let ul = document.createElement('ul'); ul.id = 'list'; for (var i = 0; i < 10; i++) { var li = document.createElement('li'); li.textContent = \`Item # \${i}\`; ul.appendChild(li); } return ul; } const list = create(); document.body.appendChild(list); function deleteList() { document.body.removeChild(document.getElementById('list')); } document.getElementById('delete').addEventListener('click', deleteList);`, `94865107132604680000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> ul <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'ul'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> ul<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">'list'</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</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> <span class="token number">10</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">var</span> li <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'li'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> li<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Item # </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> ul<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>li<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> ul<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> list <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">deleteList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">removeChild</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'list'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'delete'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> deleteList<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Clicking the delete button, will remove the list from the DOM, but there is a reference in JavaScript, so the list never gets garbage collected. We could identify detached node using heap snapshots in your browser DevTools. I am using Chrome here, but you can use Edge (similar to Chrome), and <a href="https://developer.mozilla.org/en-US/docs/Tools/Memory/Basic_operations#Taking_a_heap_snapshot" target="_blank" rel="nofollow noopener noreferrer">Firefox</a> too.</p> <p><img src="/7159b04df500677056bf34af6120b1a0/heapsnapshot.jpg" alt="taking a heap snapshot"></p> <p>And once the snapshot is taken, type detached in the filter text box and you’ll see the detached DOM nodes.</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/71db567c4424ae973a3e36f47b4d2484/00d7d/detachednodes.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 50.74074074074074%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAgADBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHtHUqJR//EABgQAAMBAQAAAAAAAAAAAAAAAAABAhIg/9oACAEBAAEFAnJiRyuP/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEB/9oACAEDAQE/Aauv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGRABAAIDAAAAAAAAAAAAAAAAAQAyICGR/9oACAEBAAY/AtgypyVMP//EABwQAQEAAAcAAAAAAAAAAAAAAAEAECExQXHB0f/aAAgBAQABPyEE4DKEehD8CdLbD//aAAwDAQACAAMAAAAQ4D//xAAYEQACAwAAAAAAAAAAAAAAAAAAARFBYf/aAAgBAwEBPxCSs0P/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAYEAEBAQEBAAAAAAAAAAAAAAABADEhEf/aAAgBAQABPxD36w6PCSCcLAZ0mZxO3//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="See detached DOM nodes from heap snapshot" title="" src="/static/71db567c4424ae973a3e36f47b4d2484/47311/detachednodes.jpg" srcset="/static/71db567c4424ae973a3e36f47b4d2484/6f81f/detachednodes.jpg 270w, /static/71db567c4424ae973a3e36f47b4d2484/09d21/detachednodes.jpg 540w, /static/71db567c4424ae973a3e36f47b4d2484/47311/detachednodes.jpg 1080w, /static/71db567c4424ae973a3e36f47b4d2484/00d7d/detachednodes.jpg 1218w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>The way to fix these kind of issues is to always use local variables so that the reference is destroyed once the function execution is done.</p> <h3 id="closures" style="position:relative;"><a href="#closures" aria-label="closures permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Closures</h3> <p>Closures are one of the JavaScript’s features where most beginners struggle with. But once you’ve got it, it’s really easy to follow. In it’s core, a closure gives you access to an outer function’s scope from an inner function.</p> <p>A more technical definition is that a closure is a combination of a function bundled together with references to it’s surrounding state (the lexical environment).</p> <div class="gatsby-code-button-container" data-toaster-id="25727460746675600000" data-toaster-class="gatsby-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 init() { var hello = 'Hello'; // hello is a local variable created by init function helloWorld() { // helloWorld() is the inner function, a closure console.log(\`\${hello} world!\`); // use variable declared in the parent function } helloWorld(); } init();`, `25727460746675600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> hello <span class="token operator">=</span> <span class="token string">'Hello'</span><span class="token punctuation">;</span> <span class="token comment">// hello is a local variable created by init</span> <span class="token keyword">function</span> <span class="token function">helloWorld</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// helloWorld() is the inner function, a closure</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>hello<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> world!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// use variable declared in the parent function</span> <span class="token punctuation">}</span> <span class="token function">helloWorld</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">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now that we know what’s a closure, let’s see how they can cause memory leaks. Imagine the following code:</p> <div class="gatsby-code-button-container" data-toaster-id="32648895707627946000" data-toaster-class="gatsby-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 newElem; function outer() { var someText = new Array(1000000); var elem = newElem; function inner() { if (elem) return someText; } return function () {}; } setInterval(function () { newElem = outer(); }, 5);`, `32648895707627946000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> newElem<span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">outer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> someText <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span><span class="token number">1000000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> elem <span class="token operator">=</span> newElem<span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">inner</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>elem<span class="token punctuation">)</span> <span class="token keyword">return</span> someText<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</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 punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> newElem <span class="token operator">=</span> <span class="token function">outer</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 number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In the above code, the <code class="language-text">inner</code> function is never called, but it holds a reference to the <code class="language-text">elem</code>. Keep in mind the scope of the inner is the same as <code class="language-text">function () {}</code> which is returned by the outer function. Since <code class="language-text">newElem</code> is a global variable, as long as a reference is pointing to <code class="language-text">function () {}</code>, the shared context is preserved and <code class="language-text">someText</code> is kept. Each call will then result in a remaining reference and as time goes by, we run out of memory eventually.</p> <p>So what we can we do about these type of scenarios? First we need to stop using <code class="language-text">var</code>. And furthermore, if we call the inner function like <code class="language-text">outer()()</code>, then there won’t be any references left.</p> <h3 id="event-listeners" style="position:relative;"><a href="#event-listeners" aria-label="event listeners permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Event listeners</h3> <p>Every time you attach an event handler to a specific element, you need to keep a reference and remove it when you’re finished. So instead of:</p> <div class="gatsby-code-button-container" data-toaster-id="76989839566612480000" data-toaster-class="gatsby-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 deleteList() {} document.getElementById('delete').addEventListener('click', deleteList);`, `76989839566612480000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">deleteList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'delete'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> deleteList<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>We should be doing:</p> <div class="gatsby-code-button-container" data-toaster-id="50649739389577904000" data-toaster-class="gatsby-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 deleteList() {} document.getElementById('delete').addEventListener('click', deleteList); // do stuff document.getElementById('delete').removeEventListener('click', deleteList);`, `50649739389577904000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">deleteList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'delete'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> deleteList<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// do stuff</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'delete'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> deleteList<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw what will cause a potential memory leak in JavaScript and how to fix those issues, however, keep in mind that in most cases if you’re using a framework or library, these things are handled for you. If you’re using a library which you might suspect is causing memory leaks, you could easily find out using your browser DevTools memory profiler.</p> <p>Hope this article has raised some awareness so that you can write more performing code and make user experience much better. No one wants to have their browser chew up memory like cheesecake right 😁?</p> <h2 id="resources" style="position:relative;"><a href="#resources" aria-label="resources permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Resources</h2> <ul> <li>More about <a href="https://developers.google.com/web/tools/chrome-devtools/memory-problems" target="_blank" rel="nofollow noopener noreferrer">Chrome DevTools memory profiler</a>.</li> <li>Find out about <a href="https://developer.mozilla.org/en-US/docs/Tools/Memory" target="_blank" rel="nofollow noopener noreferrer">Firefox DevTools memory profiling</a>.</li> </ul><![CDATA[Run code analysis with sonarqube using docker]]>https://yashints.dev/blog/2020/02/23/sonarqube-dockerhttps://yashints.dev/blog/2020/02/23/sonarqube-dockerSun, 23 Feb 2020 00:00:00 GMT<p>I help some of my friends perform code reviews on their code bases from time to time as a side activity. I’ve used <a href="https://www.npmjs.com/package/codelyzer" target="_blank" rel="nofollow noopener noreferrer"><code class="language-text">codelyzer</code></a> before and it’s very similar to <code class="language-text">tslint</code> in a sense. However, I wanted to test something new and thought let’s give <a href="https://www.sonarqube.org/" target="_blank" rel="nofollow noopener noreferrer">SonarQube</a> a shot this time.</p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p><a href="https://www.sonarqube.org/" target="_blank" rel="nofollow noopener noreferrer">SonarQube</a>® is an automatic code review tool to detect bugs, vulnerabilities and code smells in your code. It can integrate with your existing workflow to enable continuous code inspection across your project branches and pull requests.</p> <p>It has a server component where you can create projects and apply configurations like adding plugins and updating existing ones. And then there is a scanner component where it scans your code base and sends the result to the server to show in the <em>SonarQube</em> dashboard.</p> <p>There are multiple versions of <em>SonarQube</em> but we’re going to use the <a href="https://www.sonarqube.org/community/" target="_blank" rel="nofollow noopener noreferrer">community edition</a> which is free and open source.</p> <p>So without further ado, let’s get to it.</p> <h2 id="setup" style="position:relative;"><a href="#setup" aria-label="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>Setup</h2> <p><a href="https://docs.sonarqube.org/" target="_blank" rel="nofollow noopener noreferrer">The documentation</a> is really great, and there is a great <a href="https://docs.sonarqube.org/latest/setup/overview/" target="_blank" rel="nofollow noopener noreferrer">two minute get started</a> which is what I used to get my hand wet real quick. However, soon I realised that I have to install a lot of dependencies to get it working.</p> <p>I was thinking how to avoid the extra installations, when suddenly a smile came to my face when I saw there is a docker image as well.</p> <p>On the <a href="https://hub.docker.com/_/sonarqube/" target="_blank" rel="nofollow noopener noreferrer">Docker Hub</a>, you can find the information you need to get started, but for the purpose of this article, I just use a single command to get it going.</p> <div class="gatsby-code-button-container" data-toaster-id="95151748345780800000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`docker run -d --name sonarqube -p 9000:9000 sonarqube`, `95151748345780800000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--name</span> sonarqube <span class="token parameter variable">-p</span> <span class="token number">9000</span>:9000 sonarqube</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This command will pull the image down and create a container from it. Run the container in the background mode and then exposes the port 9000 through to host.</p> <p>Once done, you need to wait for a few mistunes for the server to get started. You can open a browser of your choice and go to <code class="language-text">localhost:9000</code> to see the server dashboard.</p> <p>Use the default username as <code class="language-text">admin</code> and the password <code class="language-text">admin</code> to login.</p> <p><img src="/9572ec987eacfab62a0913acfc3f9a05/sonarhome.jpg" alt="SonarQube home page"></p> <h2 id="create-a-project" style="position:relative;"><a href="#create-a-project" aria-label="create a 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>Create a project</h2> <p>I don’t want to go deep into <em>SonarQube</em> here, but a project represents a code base where you can see the result of a scan done by the scanner. So once logged in, click on create a new project button in the centre of the page, then enter a unique project key and a display name.</p> <p>On the next page enter a name for your project token. This is the key which scanner will use to authenticate to the server and send the result of a scan up.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 502px; " > <a class="gatsby-resp-image-link" href="/static/06fd8f70fa3859909660ea319638ea41/6f76c/newproj.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 69.25925925925927%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3aoUf//EABYQAQEBAAAAAAAAAAAAAAAAABABEf/aAAgBAQABBQLGP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAAIDAQAAAAAAAAAAAAAAAAERACAxUf/aAAgBAQABPyFOQIYKv//aAAwDAQACAAMAAAAQUA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAgIDAAAAAAAAAAAAAAABABEQcUFhkf/aAAgBAQABPxA5Q6GAaQNS9+SjaFV1n//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="New Project screen" title="" src="/static/06fd8f70fa3859909660ea319638ea41/6f76c/newproj.jpg" srcset="/static/06fd8f70fa3859909660ea319638ea41/6f81f/newproj.jpg 270w, /static/06fd8f70fa3859909660ea319638ea41/6f76c/newproj.jpg 502w" sizes="(max-width: 502px) 100vw, 502px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Take note of this key as you can never see it once you’re navigated away from this page. Click continue and you’ll see a screen where you can specify your project configuration.</p> <p>I wanted to run this on an Angular project with TypeScript, so I chose other, and then windows from the OS prompt.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 605px; " > <a class="gatsby-resp-image-link" href="/static/86a93b55b1d4586818b60c320e2b8049/3cb18/projectconfig.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 63.33333333333333%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHtN1KF/8QAGBAAAgMAAAAAAAAAAAAAAAAAAAERICL/2gAIAQEAAQUCbg3X/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxAAAwEAAAAAAAAAAAAAAAAAABEgQv/aAAgBAQAGPwJGZ//EABsQAAEFAQEAAAAAAAAAAAAAAAEAEBEhMWGR/9oACAEBAAE/IQFaCcpZ3wWFkqOt/9oADAMBAAIAAwAAABCfz//EABURAQEAAAAAAAAAAAAAAAAAABEQ/9oACAEDAQE/EBn/xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCn/8QAGRABAAMBAQAAAAAAAAAAAAAAAQARMWEh/9oACAEBAAE/EBpOIquQMuMDPZYVpUEOoT//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="project config screen" title="" src="/static/86a93b55b1d4586818b60c320e2b8049/3cb18/projectconfig.jpg" srcset="/static/86a93b55b1d4586818b60c320e2b8049/6f81f/projectconfig.jpg 270w, /static/86a93b55b1d4586818b60c320e2b8049/09d21/projectconfig.jpg 540w, /static/86a93b55b1d4586818b60c320e2b8049/3cb18/projectconfig.jpg 605w" sizes="(max-width: 605px) 100vw, 605px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="downloading-the-scanner" style="position:relative;"><a href="#downloading-the-scanner" aria-label="downloading the scanner permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Downloading the scanner</h2> <p>At this point you need to download the scanner and unzip it in a folder named <code class="language-text">sonarqube</code> on your drive. I usually use <code class="language-text">c:\tools</code> for these sort of usage (replace this with what you used if you chose to unzip it elsewhere).</p> <p>Once done, open your scanner config file named <code class="language-text">sonar-scanner.properties</code> from <code class="language-text">c:\tools\sonarqube\config</code> folder and uncomment the line which specifies the server address.</p> <div class="gatsby-code-button-container" data-toaster-id="8659847303247603000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`#Configure here general information about the environment, such as SonarQube server connection details for example #No information about specific project should appear here #----- Default SonarQube server sonar.host.url=http://localhost:9000 #----- Default source code encoding sonar.sourceEncoding=UTF-8`, `8659847303247603000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="yaml"><pre style="counter-reset: linenumber NaN" class="language-yaml line-numbers"><code class="language-yaml"><span class="token comment">#Configure here general information about the environment, such as SonarQube server connection details for example</span> <span class="token comment">#No information about specific project should appear here</span> <span class="token comment">#----- Default SonarQube server</span> sonar.host.url=http<span class="token punctuation">:</span>//localhost<span class="token punctuation">:</span><span class="token number">9000</span> <span class="token comment">#----- Default source code encoding</span> sonar.sourceEncoding=UTF<span class="token punctuation">-</span><span class="token number">8</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="running-a-scan" style="position:relative;"><a href="#running-a-scan" aria-label="running a scan permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Running a scan</h2> <p>Once done, you’re ready to go. Run the command below from your project root and wait for the scan to finish.</p> <div class="gatsby-code-button-container" data-toaster-id="91427911059093830000" data-toaster-class="gatsby-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:\tools\sonar\bin\sonar-scanner.bat -D&quot;sonar.projectKey=fp&quot; -D&quot;sonar.sources=.&quot; -D&quot;sonar.host.url=http://localhost:9000&quot; -D&quot;sonar.login=**********************************&quot; -D&quot;sonar.exclusions=node_modules/**/*&quot;`, `91427911059093830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">C:\tools\sonar\bin\sonar-scanner<span class="token punctuation">.</span>bat <span class="token operator">-</span>D<span class="token string">"sonar.projectKey=fp"</span> <span class="token operator">-</span>D<span class="token string">"sonar.sources=."</span> <span class="token operator">-</span>D<span class="token string">"sonar.host.url=http://localhost:9000"</span> <span class="token operator">-</span>D<span class="token string">"sonar.login=**********************************"</span> <span class="token operator">-</span>D<span class="token string">"sonar.exclusions=node_modules/**/*"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Don’t forget to replace the key you got from the previous step in the <code class="language-text">sonar.login</code> argument.</p> <blockquote> <p>💡 In the last step when you downloaded the scanner zip file, the command you need to execute is written down for you ready to go, just add the exclude folder to avoid code analysis on external libraries.</p> </blockquote> <p>It takes a while for the scan to finish based on the size of your code base. But once done, you can see the result in the <em>SonarQube</em> dashboard.</p> <blockquote> <p>ℹ️ Remember to run <code class="language-text">npm install</code> or <code class="language-text">yarn</code> if you’ve just forked the code base from your <code class="language-text">git</code> repository. I faced a few errors before I realised I didn’t have those installed and they are used by the scanner.</p> </blockquote> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/29df73690949903c226b2735ef7d93db/9288f/scan.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 40.74074074074074%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQD/2gAMAwEAAhADEAAAAciBJBf/xAAWEAADAAAAAAAAAAAAAAAAAAAAARD/2gAIAQEAAQUCHP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABYQAAMAAAAAAAAAAAAAAAAAAAAQEf/aAAgBAQABPyFIf//aAAwDAQACAAMAAAAQ9D//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAACAwEAAAAAAAAAAAAAAAAAAREhQVH/2gAIAQEAAT8QbqC2EuH/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="scan in progress" title="" src="/static/29df73690949903c226b2735ef7d93db/47311/scan.jpg" srcset="/static/29df73690949903c226b2735ef7d93db/6f81f/scan.jpg 270w, /static/29df73690949903c226b2735ef7d93db/09d21/scan.jpg 540w, /static/29df73690949903c226b2735ef7d93db/47311/scan.jpg 1080w, /static/29df73690949903c226b2735ef7d93db/0047d/scan.jpg 1620w, /static/29df73690949903c226b2735ef7d93db/274e1/scan.jpg 2160w, /static/29df73690949903c226b2735ef7d93db/9288f/scan.jpg 2626w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>And once done, here is yow your dashboard will look like. Obviously the code base I was reviewing was a bit chaotic.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 892px; " > <a class="gatsby-resp-image-link" href="/static/303844ddea00bcb177f38ea50a1773ee/65069/scanresult.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 83.7037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAARABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3aAAFB//xAAUEAEAAAAAAAAAAAAAAAAAAAAw/9oACAEBAAEFAh//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAUEAEAAAAAAAAAAAAAAAAAAAAw/9oACAEBAAY/Ah//xAAaEAABBQEAAAAAAAAAAAAAAAABABARIDFR/9oACAEBAAE/IYFuI43/2gAMAwEAAgADAAAAEADHAP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8QH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8QH//EACAQAAEEAAcBAAAAAAAAAAAAAAEAESExEEFxgZGx0fD/2gAIAQEAAT8QAi7FzFpmvtNrygBHiymNl9SN4j//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="scan results" title="" src="/static/303844ddea00bcb177f38ea50a1773ee/65069/scanresult.jpg" srcset="/static/303844ddea00bcb177f38ea50a1773ee/6f81f/scanresult.jpg 270w, /static/303844ddea00bcb177f38ea50a1773ee/09d21/scanresult.jpg 540w, /static/303844ddea00bcb177f38ea50a1773ee/65069/scanresult.jpg 892w" sizes="(max-width: 892px) 100vw, 892px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>And you when you click on issues you can see them by category and also the rules used to perform the scan.</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/50e9086321a0ebdc46828894b5557fd9/3bd77/errordetails.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 68.14814814814815%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAduxKB//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAEFAl//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAaEAACAgMAAAAAAAAAAAAAAAAAARARITFx/9oACAEBAAE/IeCsyPSFH//aAAwDAQACAAMAAAAQGz//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8QkY//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPxBn/8QAHBABAAIBBQAAAAAAAAAAAAAAAQARIRAxQZHh/9oACAEBAAE/EGwHBuJmb6jl5pNk5Z//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="scan error details" title="" src="/static/50e9086321a0ebdc46828894b5557fd9/47311/errordetails.jpg" srcset="/static/50e9086321a0ebdc46828894b5557fd9/6f81f/errordetails.jpg 270w, /static/50e9086321a0ebdc46828894b5557fd9/09d21/errordetails.jpg 540w, /static/50e9086321a0ebdc46828894b5557fd9/47311/errordetails.jpg 1080w, /static/50e9086321a0ebdc46828894b5557fd9/3bd77/errordetails.jpg 1171w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </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>In terms of the speed, I was very happy with the result. It took nearly 2 minutes to scan my entire code base with more than 520 files and thousands line of code.</p> <p>In term of the scan result, I would say based on the default rule set and considering that this was the community edition, the results are slightly better than <code class="language-text">tslint</code> or <code class="language-text">codelyzer</code>. I could easily navigate through issues, find out what line of code needed attention. It showed me the results with syntax highlighting and a lo of categories and tags where I could drill down and find what I wanted quickly.</p> <p>So go ahead and give it a shot, I am sure you’ll find enough to keep you busy for a while to fix those. And bare in mind that it not only gives you linting errors, it will also give you some security hints based on <a href="https://en.wikipedia.org/wiki/OWASP" target="_blank" rel="nofollow noopener noreferrer">OWASP top 10</a> as well.</p><![CDATA[Retro HTML, let's create marquees 😃]]>https://yashints.dev/blog/2020/02/09/marqueehttps://yashints.dev/blog/2020/02/09/marqueeSun, 09 Feb 2020 00:00:00 GMT<p>One of the first things I learnt to do with HTML was using marquee to move text across the screen horizontally. It was so cool to be able to create advertisements on a page and make users notice things with just a tag. Of course people overused it and then it became a out of fashion item in the new designs just like baggy jeans from 90s.</p> <!--more--> <h2 id="history" style="position:relative;"><a href="#history" aria-label="history permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>History</h2> <p>The HTML <code class="language-text">&lt;marquee></code> element was used to insert a scrolling area of text. You could control what happened when the text reached the edge of it’s area using its attribute. Of course when I use past tense it doesn’t mean it’s not supported anymore. It became obsolete a while back, but most browsers still support it.</p> <p>You can see it in action:</p> <iframe height="265" style="width: 100%;" scrolling="no" title="Marquee" src="https://codepen.io/yashints/embed/preview/QWbwVKr?height=265&theme-id=default&default-tab=html,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/QWbwVKr'>Marquee</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h2 id="css-marquees" style="position:relative;"><a href="#css-marquees" aria-label="css marquees permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CSS marquees</h2> <p>So I want to simulate some of these with just <code class="language-text">CSS</code>. We’ll be using <code class="language-text">CSS</code> animations and play with <code class="language-text">overflow</code> to simulate text reaching to the edge.</p> <h3 id="scrolling-text" style="position:relative;"><a href="#scrolling-text" aria-label="scrolling 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>Scrolling text</h3> <p>So let’s play with <code class="language-text">translateX()</code> to specify the content placement at the start and end of the animation. We’ll use this to keep the text moving between start and end.</p> <p>For the animation we will use an infinite linear with 10 seconds duration.</p> <div class="gatsby-code-button-container" data-toaster-id="91083718191215580000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.marquee { height: 50px; overflow: hidden; position: relative; } .marquee span { font-size: 2em; color: turquoise; position: absolute; width: 100%; height: 100%; margin: 0; line-height: 50px; text-align: center; transform:translateX(100%); animation: cssmarquee 10s linear infinite; } @keyframes cssmarquee { 0% { transform: translateX(100%); } 100% { transform: translateX(-100%); } }`, `91083718191215580000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.marquee</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.marquee span</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> turquoise<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">line-height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token property">transform</span><span class="token punctuation">:</span><span class="token function">translateX</span><span class="token punctuation">(</span>100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">animation</span><span class="token punctuation">:</span> cssmarquee 10s linear infinite<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@keyframes</span> cssmarquee</span> <span class="token punctuation">{</span> <span class="token selector">0%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>-100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And the HTML is simple:</p> <div class="gatsby-code-button-container" data-toaster-id="30715582201475880000" data-toaster-class="gatsby-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;marquee&quot;> <span>Scrolling Text </span> </div>`, `30715582201475880000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>marquee<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 punctuation">></span></span>Scrolling Text <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>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <iframe height="265" style="width: 100%;" scrolling="no" title="CSS-Marquee-ScrollText" src="https://codepen.io/yashints/embed/preview/ZEGYMLw?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/ZEGYMLw'>CSS-Marquee-ScrollText</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h3 id="slide-in" style="position:relative;"><a href="#slide-in" aria-label="slide in permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Slide in</h3> <p>Now let’s slide in the text and fix it at the beginning. We’ll use <code class="language-text">ease-out</code> with a <code class="language-text">200%</code> value for <code class="language-text">translateX</code> start and <code class="language-text">0%</code> for the end.</p> <div class="gatsby-code-button-container" data-toaster-id="52663661602963520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.marquee { height: 50px; overflow: hidden; position: relative; } .marquee span { font-size: 2em; color: green; position: absolute; width: 100%; height: 100%; margin: 0; line-height: 50px; text-align: left; animation: cssmarquee 10s ease-out; } @keyframes cssmarquee { 0% { transform: translateX(200%); } 100% { transform: translateX(0%); } }`, `52663661602963520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.marquee</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.marquee span</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">line-height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span> <span class="token property">animation</span><span class="token punctuation">:</span> cssmarquee 10s ease-out<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@keyframes</span> cssmarquee</span> <span class="token punctuation">{</span> <span class="token selector">0%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>200%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>0%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I won’t repeat the <code class="language-text">HTML</code> code again to save some typing 😁. It’s exactly as above.</p> <iframe height="265" style="width: 100%;" scrolling="no" title="CSS-Marquee-SlineIn" src="https://codepen.io/yashints/embed/preview/wvaBEJp?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/wvaBEJp'>CSS-Marquee-SlineIn</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h3 id="left-to-right" style="position:relative;"><a href="#left-to-right" aria-label="left to right permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Left to right</h3> <p>Now let’s move the text from left to right this time. Again, we’ll use a linear infinite animation with the reverse values for <code class="language-text">translateX</code> as our first example.</p> <p>The only other difference will be the initial value for transform property.</p> <div class="gatsby-code-button-container" data-toaster-id="22963678218631967000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.marquee { height: 50px; overflow: hidden; position: relative; } .marquee span { font-size: 2em; position: absolute; width: 100%; height: 100%; color: green; margin: 0; line-height: 50px; text-align: center; /* Starting position */ transform: translateX(-100%); animation: cssmarquee 20s linear infinite; } @keyframes cssmarquee { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }`, `22963678218631967000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.marquee</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.marquee span</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">line-height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token comment">/* Starting position */</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>-100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">animation</span><span class="token punctuation">:</span> cssmarquee 20s linear infinite<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@keyframes</span> cssmarquee</span> <span class="token punctuation">{</span> <span class="token selector">0%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>-100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <iframe height="265" style="width: 100%;" scrolling="no" title="CSS-Marquee-L2R" src="https://codepen.io/yashints/embed/preview/xxGbarb?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/xxGbarb'>CSS-Marquee-L2R</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h3 id="scroll-vertically" style="position:relative;"><a href="#scroll-vertically" aria-label="scroll vertically permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 vertically</h3> <p>By now you should be comfortable guessing what will be using. Instead of <code class="language-text">translateX</code>, we will be using <code class="language-text">translateY</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="31945275416211750000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.marquee { height: 100px; overflow: hidden; position: relative; } .marquee span { font-size: 2em; position: absolute; color: green; width: 100%; height: 100%; margin: 0; line-height: 50px; text-align: center; transform: translateY(-100%); animation: cssmarquee 5s linear infinite; } @keyframes cssmarquee { 0% { transform: translateY(-100%); } 100% { transform: translateY(100%); } }`, `31945275416211750000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.marquee</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.marquee span</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">line-height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>-100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">animation</span><span class="token punctuation">:</span> cssmarquee 5s linear infinite<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@keyframes</span> cssmarquee</span> <span class="token punctuation">{</span> <span class="token selector">0%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>-100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>100%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <iframe height="265" style="width: 100%;" scrolling="no" title="CSS-Marquee-Down" src="https://codepen.io/yashints/embed/preview/LYVEJjG?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/LYVEJjG'>CSS-Marquee-Down</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h3 id="bouncing-text" style="position:relative;"><a href="#bouncing-text" aria-label="bouncing 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>Bouncing text</h3> <p>Now let’s assume back then people wanted to get fancy. We want to bounce the text this time 😃. We will need to add <code class="language-text">alternate</code> to our animation and reduce the delay. We will also add <code class="language-text">trnslateX</code> so that the content doesn’t bounce off the whole page.</p> <div class="gatsby-code-button-container" data-toaster-id="31285348306438610000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.marquee { height: 200px; overflow: hidden; position: relative; } .marquee span { font-size: 2em; position: absolute; color: turquoise; width: 100%; height: 100%; margin: 0; line-height: 50px; text-align: center; transform: translateY(70%); animation: cssmarquee 1s linear infinite alternate; } @keyframes cssmarquee { 0% { transform: translateY(70%); } 100% { transform: translateY(0%); } }`, `31285348306438610000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.marquee</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.marquee span</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> turquoise<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">line-height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>70%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">animation</span><span class="token punctuation">:</span> cssmarquee 1s linear infinite alternate<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@keyframes</span> cssmarquee</span> <span class="token punctuation">{</span> <span class="token selector">0%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>70%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>0%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <iframe height="265" style="width: 100%;" scrolling="no" title="CSS-Marquee-Bounce" src="https://codepen.io/yashints/embed/preview/ZEGYMJP?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/ZEGYMJP'>CSS-Marquee-Bounce</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h3 id="typewriting-effect" style="position:relative;"><a href="#typewriting-effect" aria-label="typewriting effect permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Typewriting effect</h3> <p>Now this time we want to mix our animation with a bit of stepping to create a typewriter effect. We will be using <code class="language-text">from</code> and <code class="language-text">to</code> for our keyframes. Then use <code class="language-text">steps</code> and <code class="language-text">step-end</code> to simulate the text and blink cursor effect.</p> <div class="gatsby-code-button-container" data-toaster-id="89549766710814970000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`body { font-family: 'Special Elite', cursive; background: #efefef; padding-top: 5em; display: flex; justify-content: center; } .typewriter h1 { overflow: hidden; border-right: .15em solid green; white-space: nowrap; margin: 0 auto; letter-spacing: .15em; animation: type 4s steps(50, end), blink-cursor .7s step-end infinite; } @keyframes type { from { width: 0 } to { width: 100% } } @keyframes blink-cursor { from, to { border-color: transparent } 50% { border-color: green; } }`, `89549766710814970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Special Elite'</span><span class="token punctuation">,</span> cursive<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> #efefef<span class="token punctuation">;</span> <span class="token property">padding-top</span><span class="token punctuation">:</span> 5em<span class="token punctuation">;</span> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span> <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.typewriter h1</span> <span class="token punctuation">{</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token property">border-right</span><span class="token punctuation">:</span> .15em solid green<span class="token punctuation">;</span> <span class="token property">white-space</span><span class="token punctuation">:</span> nowrap<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0 auto<span class="token punctuation">;</span> <span class="token property">letter-spacing</span><span class="token punctuation">:</span> .15em<span class="token punctuation">;</span> <span class="token property">animation</span><span class="token punctuation">:</span> type 4s <span class="token function">steps</span><span class="token punctuation">(</span>50<span class="token punctuation">,</span> end<span class="token punctuation">)</span><span class="token punctuation">,</span> blink-cursor .7s step-end infinite<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@keyframes</span> type</span> <span class="token punctuation">{</span> <span class="token selector">from</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 0 <span class="token punctuation">}</span> <span class="token selector">to</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100% <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@keyframes</span> blink-cursor</span> <span class="token punctuation">{</span> <span class="token selector">from, to</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> transparent <span class="token punctuation">}</span> <span class="token selector">50%</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Don’t forget to add the <code class="language-text">Special Elite</code> font from Google fonts.</p> <div class="gatsby-code-button-container" data-toaster-id="59066118398498670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<head> <link href=&quot;https://fonts.googleapis.com/css?family=Special+Elite&display=swap&quot; rel=&quot;stylesheet&quot;> </head>`, `59066118398498670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</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://fonts.googleapis.com/css?family=Special+Elite&amp;display=swap<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<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>head</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <iframe height="265" style="width: 100%;" scrolling="no" title="CSS-Marquee-TypeWriter" src="https://codepen.io/yashints/embed/preview/qBdEMxb?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/qBdEMxb'>CSS-Marquee-TypeWriter</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <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>That was it. You can go back to whatever important job you were doing. A bit of distraction is always good for me and hope this bit was good for you too 😊. Until next time 👋🏼.</p><![CDATA[If you consider Puppeteer cool, then Playwright is awesomeness 😍]]>https://yashints.dev/blog/2020/01/24/playwrighthttps://yashints.dev/blog/2020/01/24/playwrightFri, 24 Jan 2020 00:00:00 GMT<p>If you’ve ever used <a href="https://github.com/puppeteer/puppeteer" target="_blank" rel="nofollow noopener noreferrer">Puppeteer</a>, you’d know it enables you to control a Chrome instance (or any other <strong>Chrome DevTools</strong> Protocol based browser) and execute common actions, much like in a real browser - programmatically, through a decent API. The same team has now build a new product called <a href="https://github.com/microsoft/playwright" target="_blank" rel="nofollow noopener noreferrer">Playwright</a> which apparently is their new favourite.</p> <!--more--> <h2 id="what-is-playwright-" style="position:relative;"><a href="#what-is-playwright-" aria-label="what is playwright permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 Playwright? 🤔</h2> <p><a href="https://github.com/microsoft/playwright" target="_blank" rel="nofollow noopener noreferrer">Playwright</a> is a Node library which allows you to automate all major browsers - Chrome, Firefox, WebKit, and the new Microsoft Edge - plus the ability to execute actions, take screenshots, and much more, similar to Puppeteer.</p> <p>In their own words:</p> <blockquote> <p>Playwright is focused on enabling cross-browser web automation platform that is <strong>ever-green</strong>, <strong>capable</strong>, <strong>reliable</strong> and <strong>fast</strong>. Our primary goal with Playwright is to improve automated UI testing by eliminating flakiness, improving the speed of execution and offering insights into the browser operation.</p> </blockquote> <p>Imagine the possibility of running end to end tests on all major browsers before you ship your any product to your users.</p> <h2 id="is-is-replacing-puppeteer" style="position:relative;"><a href="#is-is-replacing-puppeteer" aria-label="is is replacing puppeteer permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Is is replacing Puppeteer?</h2> <p>Based on what I see and how they’ve answered, I’d say YES. But with a promise to contain all of the functionality of Puppeteer, and make it a cross platform, vendor-neutral, and a collaboration effort between all major parties.</p> <p>The lessons learnt are incorporated into it, APIs are testing-friendly, and it will be a cloud native product. For example all the user agent/device emulation is setup consistently on an object called <code class="language-text">BrowserContext</code> to enable <em>multi-page</em> scenarios, <code class="language-text">click</code> waits for the element to be available and visible by default, there is a way to wait for <em>network</em> and other events, etc.</p> <h2 id="getting-started" style="position:relative;"><a href="#getting-started" aria-label="getting started permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 started</h2> <p>You can install Playwright via <code class="language-text">npm</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="37942214326639575000" data-toaster-class="gatsby-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 i playwright`, `37942214326639575000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i playwright</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This will install Playwright and its dependencies. Note that it will also download the browser binaries which are quite bulky (~50MB to ~150MB).</p> <h3 id="launching-a-browser" style="position:relative;"><a href="#launching-a-browser" aria-label="launching a browser permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Launching a browser</h3> <p>Playwright module provides a method to launch a browser instance. The following is a typical example of using Playwright to drive automation. Below snippet shows opening a Chrome instance and browsing <code class="language-text">example.com</code> page.</p> <div class="gatsby-code-button-container" data-toaster-id="91535198069414480000" data-toaster-class="gatsby-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 playwright = require('playwright').chromium; // Or 'firefox' or 'webkit'. (async () => { const browser = await playwright.launch(); const context = await browser.newContext(); const page = await context.newPage('http://example.com'); // other actions... await browser.close(); })();`, `91535198069414480000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> playwright <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>chromium<span class="token punctuation">;</span> <span class="token comment">// Or 'firefox' or 'webkit'.</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">const</span> browser <span class="token operator">=</span> <span class="token keyword">await</span> playwright<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> <span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token keyword">await</span> browser<span class="token punctuation">.</span><span class="token function">newContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">await</span> context<span class="token punctuation">.</span><span class="token function">newPage</span><span class="token punctuation">(</span><span class="token string">'http://example.com'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// other actions...</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><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="taking-a-screenshot-of-the-page" style="position:relative;"><a href="#taking-a-screenshot-of-the-page" aria-label="taking a screenshot of the page permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Taking a screenshot of the page</h3> <p>You can execute most of the actions available on DevTools. For example we can take a screenshot of the page like so:</p> <div class="gatsby-code-button-container" data-toaster-id="6840665403810009000" data-toaster-class="gatsby-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 pw = require('playwright'); (async () => { const browser = await pw.webkit.launch(); // or 'chromium', 'firefox' const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://www.example.com/'); await page.screenshot({ path: 'example.png' }); await browser.close(); })();`, `6840665403810009000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> pw <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 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">const</span> browser <span class="token operator">=</span> <span class="token keyword">await</span> pw<span class="token punctuation">.</span>webkit<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> <span class="token comment">// or 'chromium', 'firefox'</span> <span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token keyword">await</span> browser<span class="token punctuation">.</span><span class="token function">newContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">await</span> context<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><span class="token string">'https://www.example.com/'</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">screenshot</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'example.png'</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><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="emulate-a-device" style="position:relative;"><a href="#emulate-a-device" aria-label="emulate a device permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Emulate a device</h3> <div class="gatsby-code-button-container" data-toaster-id="29936000306996613000" data-toaster-class="gatsby-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 playwright = require('playwright').firefox; const iPhone = playwright.devices['iPhone 11 Pro']; (async () => { const browser = await playwright.launch(); const context = await browser.newContext({ viewport: iPhone.viewport, userAgent: iPhone.userAgent }); const page = await context.newPage('http://example.com'); // other actions... await browser.close(); })();`, `29936000306996613000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> playwright <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>firefox<span class="token punctuation">;</span> <span class="token keyword">const</span> iPhone <span class="token operator">=</span> playwright<span class="token punctuation">.</span>devices<span class="token punctuation">[</span><span class="token string">'iPhone 11 Pro'</span><span class="token punctuation">]</span><span class="token punctuation">;</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">const</span> browser <span class="token operator">=</span> <span class="token keyword">await</span> playwright<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> <span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token keyword">await</span> browser<span class="token punctuation">.</span><span class="token function">newContext</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">viewport</span><span class="token operator">:</span> iPhone<span class="token punctuation">.</span>viewport<span class="token punctuation">,</span> <span class="token literal-property property">userAgent</span><span class="token operator">:</span> iPhone<span class="token punctuation">.</span>userAgent <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">await</span> context<span class="token punctuation">.</span><span class="token function">newPage</span><span class="token punctuation">(</span><span class="token string">'http://example.com'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// other actions...</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><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="going-beyond-simple" style="position:relative;"><a href="#going-beyond-simple" aria-label="going beyond simple permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Going beyond simple</h3> <p>Playwright allows you to easily emulate geo-location data.</p> <div class="gatsby-code-button-container" data-toaster-id="73580442438152070000" data-toaster-class="gatsby-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 pw = require('playwright'); const pixel2 = pw.devices['Pixel 2']; (async () => { const browser = await pw.chromium.launch(); const context = await browser.newContext({ viewport: pixel2.viewport, userAgent: pixel2.userAgent, geolocation: { longitude: 12.492507, latitude: 41.889938 }, permissions: { 'https://www.google.com': ['geolocation'] } }); const page = await context.newPage('https://maps.google.com'); await page.click('text=&quot;Your location&quot;'); await page.waitForRequest(/.*pwa\/net.js.*/); await page.screenshot({ path: 'colosseum-android.png' }); await browser.close(); })();`, `73580442438152070000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> pw <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> pixel2 <span class="token operator">=</span> pw<span class="token punctuation">.</span>devices<span class="token punctuation">[</span><span class="token string">'Pixel 2'</span><span class="token punctuation">]</span><span class="token punctuation">;</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">const</span> browser <span class="token operator">=</span> <span class="token keyword">await</span> pw<span class="token punctuation">.</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> <span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token keyword">await</span> browser<span class="token punctuation">.</span><span class="token function">newContext</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">viewport</span><span class="token operator">:</span> pixel2<span class="token punctuation">.</span>viewport<span class="token punctuation">,</span> <span class="token literal-property property">userAgent</span><span class="token operator">:</span> pixel2<span class="token punctuation">.</span>userAgent<span class="token punctuation">,</span> <span class="token literal-property property">geolocation</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">longitude</span><span class="token operator">:</span> <span class="token number">12.492507</span><span class="token punctuation">,</span> <span class="token literal-property property">latitude</span><span class="token operator">:</span> <span class="token number">41.889938</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">permissions</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'https://www.google.com'</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'geolocation'</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> page <span class="token operator">=</span> <span class="token keyword">await</span> context<span class="token punctuation">.</span><span class="token function">newPage</span><span class="token punctuation">(</span><span class="token string">'https://maps.google.com'</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">'text="Your location"'</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">waitForRequest</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">.*pwa\/net.js.*</span><span class="token regex-delimiter">/</span></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">screenshot</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'colosseum-android.png'</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><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Note how we had to set the grant the necessary permission on the context, which means this is exactly what happens when a user browses the page.</p> <h3 id="accessing-elements-on-page" style="position:relative;"><a href="#accessing-elements-on-page" aria-label="accessing elements on page permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Accessing elements on page</h3> <p><code class="language-text">ElementHandle</code> represents an in-page DOM element. <code class="language-text">ElementHandles</code> can be created with the <code class="language-text">page.$</code> method, similar to what we’ve been using in DevTools.</p> <div class="gatsby-code-button-container" data-toaster-id="40286607661475540000" data-toaster-class="gatsby-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 playwright = require('playwright').chromium; // Or 'firefox' or 'webkit'. (async () => { const browser = await playwright.launch(); const context = await browser.newContext(); const page = await context.newPage('https://example.com'); const hrefElement = await page.\$('a'); await hrefElement.click(); // ... })();`, `40286607661475540000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> playwright <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>chromium<span class="token punctuation">;</span> <span class="token comment">// Or 'firefox' or 'webkit'.</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">const</span> browser <span class="token operator">=</span> <span class="token keyword">await</span> playwright<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> <span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token keyword">await</span> browser<span class="token punctuation">.</span><span class="token function">newContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">await</span> context<span class="token punctuation">.</span><span class="token function">newPage</span><span class="token punctuation">(</span><span class="token string">'https://example.com'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> hrefElement <span class="token operator">=</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> hrefElement<span class="token punctuation">.</span><span class="token function">click</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><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="typing-in-text-boxes" style="position:relative;"><a href="#typing-in-text-boxes" aria-label="typing in text boxes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Typing in text boxes</h3> <p>You can emulate a user typing into text fields, for example performing a search action:</p> <div class="gatsby-code-button-container" data-toaster-id="77459110189444000000" data-toaster-class="gatsby-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 elementHandle = await page.\$('input'); await elementHandle.type('Hello'); // Types instantly await elementHandle.type('World', {delay: 100}); // Types slower, like a user await elementHandle.press('Enter');`, `77459110189444000000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> elementHandle <span class="token operator">=</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> elementHandle<span class="token punctuation">.</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token string">'Hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Types instantly</span> <span class="token keyword">await</span> elementHandle<span class="token punctuation">.</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token string">'World'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">delay</span><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> <span class="token comment">// Types slower, like a user</span> <span class="token keyword">await</span> elementHandle<span class="token punctuation">.</span><span class="token function">press</span><span class="token punctuation">(</span><span class="token string">'Enter'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="what-else" style="position:relative;"><a href="#what-else" aria-label="what else permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What else?</h3> <p>You can even play with mouse (pun intended):</p> <div class="gatsby-code-button-container" data-toaster-id="54907526726631620000" data-toaster-class="gatsby-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 ‘page.mouse’ to trace a 100x100 square. await page.mouse.move(0, 0); await page.mouse.down(); await page.mouse.move(0, 100); await page.mouse.move(100, 100); await page.mouse.move(100, 0); await page.mouse.move(0, 0); await page.mouse.up();`, `54907526726631620000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// Using ‘page.mouse’ to trace a 100x100 square.</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span>mouse<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span>mouse<span class="token punctuation">.</span><span class="token function">down</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>mouse<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span>mouse<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span>mouse<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span>mouse<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span>mouse<span class="token punctuation">.</span><span class="token function">up</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="what-next" style="position:relative;"><a href="#what-next" aria-label="what 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>What next?</h2> <p>The list of the available actions and what is available on the <a href="https://github.com/microsoft/playwright/blob/master/docs/api.md" target="_blank" rel="nofollow noopener noreferrer">API documentation page</a>. The list is almost overwhelming, in a good way 😁.</p> <h2 id="what-browsers-are-supported" style="position:relative;"><a href="#what-browsers-are-supported" aria-label="what browsers are supported permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 browsers are supported?</h2> <ul> <li><strong>Chromium</strong>: Playwright uses upstream versions of Chromium.</li> <li><strong>WebKit</strong>: Playwright makes a number of modifications to WebCore and WebKit2 in order to extend WebKit’s remote debugging capabilities and support the full set of Playwright APIs.</li> <li><strong>Firefox</strong>: Playwright makes a number of modifications to Firefox as well. Those are adding support for content script debugging, workers, CSP, emulation, network interception, etc. etc.</li> <li><strong>MS Edge</strong>: Since it’s based on Chromium, it’s supported as well.</li> </ul> <h2 id="what-is-the-update-cadence" style="position:relative;"><a href="#what-is-the-update-cadence" aria-label="what is the update cadence permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the update cadence?</h2> <p>The team follow <a href="https://semver.org/" target="_blank" rel="nofollow noopener noreferrer">semver</a>, and the team are trying to keep in sync with Chromium update cycle, possibly once a month.</p> <h2 id="but" style="position:relative;"><a href="#but" aria-label="but permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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</h2> <p>Playwright is in a stage where there might be breaking changes coming up as it progresses through full support for those browsers. You can find more information around this on their <a href="https://aslushnikov.github.io/isplaywrightready/" target="_blank" rel="nofollow noopener noreferrer">Is Playwright Ready?</a> page.</p> <p>So go have fun and enjoy this awesome emerging web technology 👍🏼. I will be exploring this on a couple of my side projects too, so stay tuned for more posts.</p><![CDATA[Get to know the Clipboard API, be smarter with user interactions 📋]]>https://yashints.dev/blog/2020/01/09/clipboard-apihttps://yashints.dev/blog/2020/01/09/clipboard-apiThu, 09 Jan 2020 00:00:00 GMT<p>We face many situations in which we need to interact with user’s clipboard. Up until recently, browsers were using <code class="language-text">document.execCommand</code> for clipboard interactions. It sounded great and it was (and still is) widely supported way to copy, cut, and paste into web apps, but the catch was that clipboard access is asynchronous and can just write to DOM.</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>The fact that clipboard access is asynchronous means the user experience was suffering because a clipboard transfer was happening. This got worst when pasting because in most cases you need to sanitise the content can be safely processed.</p> <p>It even got worst when permissions got into the equation, or the browser had to copy information from a link in the text and page had to wait for a network request, so the usage wasn’t that widespread.</p> <h2 id="clipboard-api" style="position:relative;"><a href="#clipboard-api" aria-label="clipboard 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>Clipboard API</h2> <p>It was all sad and gloomy until the new <a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API" target="_blank" rel="nofollow noopener noreferrer">Clipboard API</a> was born. This API is a replacement for <code class="language-text">document.execCommand</code> based copy and pasting that has a well defined permissions model and doesn’t block the page.</p> <p>This API is a property of the <code class="language-text">window.navigator</code> and is constructed from below properties and methods:</p> <ul> <li><code class="language-text">read()</code></li> <li><code class="language-text">readText()</code></li> <li><code class="language-text">write(data)</code></li> <li><code class="language-text">writeText(text)</code></li> <li><code class="language-text">addEventListener(event, handler)</code></li> <li><code class="language-text">removeEventListener(event, handler)</code></li> <li><code class="language-text">dispatchEvent(event)</code></li> </ul> <p>To detect whether the feature is supported in the browser or not you can do:</p> <div class="gatsby-code-button-container" data-toaster-id="66262144229503230000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if (navigator.clipboard) { // yep, happy coding. } else { // oh no 😢. Use execCommand for now }`, `66262144229503230000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// yep, happy coding.</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// oh no 😢. Use execCommand for now</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In addition to that goodness, it can also read from and write to system clipboard 😍. Access to clipboard is behind <a href="https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API" target="_blank" rel="nofollow noopener noreferrer">Permissions API</a>, which means without user’s permission none of these operations are permitted.</p> <h2 id="copy-text-to-clipboard" style="position:relative;"><a href="#copy-text-to-clipboard" aria-label="copy text to clipboard permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Copy text to clipboard</h2> <p>Text can be copied to the clipboard by calling the <code class="language-text">writeText</code> method. This function returns a promise that will be resolved or rejected based on how the operation was performed.</p> <div class="gatsby-code-button-container" data-toaster-id="49726515044695654000" data-toaster-class="gatsby-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.clipboard.writeText('I am writing to clipboard 📋') .then(() => { console.log('Woohoo'); }) .catch(err => { console.error('Oh no: ', err); });`, `49726515044695654000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">writeText</span><span class="token punctuation">(</span><span class="token string">'I am writing to clipboard 📋'</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 punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Woohoo'</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">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Oh no: '</span><span class="token punctuation">,</span> err<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>On of the reasons the catch function might be called is that the permission is not granted by the user or they deny it.</p> <p>You can use an <code class="language-text">async</code> function and <code class="language-text">await</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="63876741631863080000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async function writeTextToClipboard() { try { await navigator.clipboard.writeText('I am writing to clipboard 📋'); console.log('Woohoo'); } catch (err) { console.error('Oh no: ', err); } }`, `63876741631863080000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">writeTextToClipboard</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> navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">writeText</span><span class="token punctuation">(</span><span class="token string">'I am writing to clipboard 📋'</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">'Woohoo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</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">error</span><span class="token punctuation">(</span><span class="token string">'Oh no: '</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="read-from-clipboard" style="position:relative;"><a href="#read-from-clipboard" aria-label="read from clipboard permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 from clipboard</h2> <p>To read the copied text from clipboard, you can use the <code class="language-text">readText</code> method and wait for the returned promise:</p> <div class="gatsby-code-button-container" data-toaster-id="68269377297824410000" data-toaster-class="gatsby-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.clipboard.readText() .then(text => { console.log('Pasted content: ', text); }) .catch(err => { console.error('Oh no: ', err); });`, `68269377297824410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">readText</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">text</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Pasted content: '</span><span class="token punctuation">,</span> text<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">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Oh no: '</span><span class="token punctuation">,</span> err<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And with <code class="language-text">async/await</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="94600391361393200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async function getCopiedTextFromClioboard() { try { const text = await navigator.clipboard.readText(); console.log('Pasted content: ', text); } catch (err) { console.error('Oh no: ', err); } }`, `94600391361393200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getCopiedTextFromClioboard</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">const</span> text <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">readText</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Pasted content: '</span><span class="token punctuation">,</span> text<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</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">error</span><span class="token punctuation">(</span><span class="token string">'Oh no: '</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Let’s see this in a demo.</p> <iframe height="265" style="width: 100%;" scrolling="no" title="Clipboard API Demo" src="https://codepen.io/yashints/embed/preview/oNgqbaX?height=265&theme-id=default&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/oNgqbaX'>Clipboard API Demo</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <p>Notice you had to give permission for it to work.</p> <h2 id="handling-paste" style="position:relative;"><a href="#handling-paste" aria-label="handling paste permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Handling paste</h2> <p>You can hook up to the (surprise) <code class="language-text">paste</code> event on the <code class="language-text">document</code> to be able to receive the text when it’s copied into clipboard and a paste action is triggered by user agent. If you want to modify the received data, you need to prevent the event from bubbling up.</p> <div class="gatsby-code-button-container" data-toaster-id="69771551268990020000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`document.addEventListener('paste', async (e) => { e.preventDefault(); // need to do something with the text try { let text = await navigator.clipboard.readText(); text = text.toUpperCase(); console.log('Pasted UPPERCASE text: ', text); } catch (err) { console.error('Oh no: ', err); } });`, `69771551268990020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'paste'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// need to do something with the text</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> text <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">readText</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> text <span class="token operator">=</span> text<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> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Pasted UPPERCASE text: '</span><span class="token punctuation">,</span> text<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</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">error</span><span class="token punctuation">(</span><span class="token string">'Oh no: '</span><span class="token punctuation">,</span> err<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="handling-copy" style="position:relative;"><a href="#handling-copy" aria-label="handling copy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Handling copy</h2> <p>Similar to paste, you can handle copy events too:</p> <div class="gatsby-code-button-container" data-toaster-id="99639889581143240000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`document.addEventListener('paste', async (e) => { e.preventDefault(); try { for (const item of e.clipboardData.items) { await navigator.clipboard.write([ new ClipboardItem({ [blob.type]: blob }) ]); } console.log('Image copied.'); } catch (err) { console.error('Oh no: ', err); } });`, `99639889581143240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'paste'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</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">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> item <span class="token keyword">of</span> e<span class="token punctuation">.</span>clipboardData<span class="token punctuation">.</span>items<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token keyword">new</span> <span class="token class-name">ClipboardItem</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token punctuation">[</span>blob<span class="token punctuation">.</span>type<span class="token punctuation">]</span><span class="token operator">:</span> blob <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> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Image copied.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</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">error</span><span class="token punctuation">(</span><span class="token string">'Oh no: '</span><span class="token punctuation">,</span> err<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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>The <code class="language-text">navigator.clipboard</code> is only supported for pages served over <em>HTTPS</em>, plus clipboard access is restricted only when allowed to prevent further abuse. Active pages can write to clipboard, but reading requires granted permission.</p> <p>There two new permissions which was introduced when Clipboard API was developed:</p> <ul> <li>The <code class="language-text">clipboard-write</code> is granted automatically to any active tab.</li> <li>The <code class="language-text">clipboard-read</code> must be requested.</li> </ul> <div class="gatsby-code-button-container" data-toaster-id="13781350049450580000" data-toaster-class="gatsby-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 queryOpts = { name: 'clipboard-read' }; const permissionStatus = await navigator.permissions.query(queryOpts); // Will be 'granted', 'denied' or 'prompt': console.log(permissionStatus.state); // Listen for changes to the permission state permissionStatus.onchange = () => { console.log(permissionStatus.state); };`, `13781350049450580000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> queryOpts <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'clipboard-read'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> permissionStatus <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>permissions<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>queryOpts<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Will be 'granted', 'denied' or 'prompt':</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>permissionStatus<span class="token punctuation">.</span>state<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Listen for changes to the permission state</span> permissionStatus<span class="token punctuation">.</span><span class="token function-variable function">onchange</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> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>permissionStatus<span class="token punctuation">.</span>state<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="images" style="position:relative;"><a href="#images" aria-label="images permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Images</h2> <p>We don’t always use text, so the new <code class="language-text">write()</code> method was introduced to allow us to write other data formats to the clipboard. This method is asynchronous too and truth is, <code class="language-text">writeText</code> is calling this method behind the scenes.</p> <h3 id="write-to-clipboard" style="position:relative;"><a href="#write-to-clipboard" aria-label="write to clipboard permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Write to clipboard</h3> <p>To write an image to clipboard, you need to convert your image to a <code class="language-text">Blob</code>. You can do it using a canvas element by calling the <code class="language-text">toBlob()</code> function. At this point you can only pass one image at a time and multi image is under progress by Chrome team.</p> <div class="gatsby-code-button-container" data-toaster-id="14171695340269564000" data-toaster-class="gatsby-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 canvas = document.getElementById(&quot;myCanvas&quot;); const ctx = canvas.getContext('2d'); var img = new Image(); img.setAttribute('crossorigin', 'anonymous'); img.onload = function() { ctx.drawImage(img, 0, 0, 150, 150); img.style.display = 'none'; canvas.toBlob(function(blob) { navigator.clipboard.write([ new ClipboardItem({ [blob.type]: blob }) ]); }) }; img.src = 'https://image-url';`, `14171695340269564000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> canvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"myCanvas"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> ctx <span class="token operator">=</span> canvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">'2d'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> img <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> img<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'crossorigin'</span><span class="token punctuation">,</span> <span class="token string">'anonymous'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> img<span class="token punctuation">.</span><span class="token function-variable function">onload</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ctx<span class="token punctuation">.</span><span class="token function">drawImage</span><span class="token punctuation">(</span>img<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">150</span><span class="token punctuation">,</span> <span class="token number">150</span><span class="token punctuation">)</span><span class="token punctuation">;</span> img<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">'none'</span><span class="token punctuation">;</span> canvas<span class="token punctuation">.</span><span class="token function">toBlob</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">blob</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token keyword">new</span> <span class="token class-name">ClipboardItem</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token punctuation">[</span>blob<span class="token punctuation">.</span>type<span class="token punctuation">]</span><span class="token operator">:</span> blob <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> img<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'https://image-url'</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="read-the-image-from-clipboard" style="position:relative;"><a href="#read-the-image-from-clipboard" aria-label="read the image from clipboard permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the image from clipboard</h3> <p>To read the image you’ll need to use the <code class="language-text">read()</code> method, which reads the data and returns a list of <code class="language-text">ClipboardItem</code> objects. You can use <code class="language-text">for...of</code> which handles the <code class="language-text">async</code> part for you as well.</p> <p>Each returned object can have different type, so best option would be to call <code class="language-text">getType()</code> on it and act accordingly. In our case the corresponding type would be <code class="language-text">Blob</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="27604428011343974000" data-toaster-class="gatsby-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 items = await navigator.clipboard.read(); for (const clipboardItem of items) { for (const type of clipboardItem.types) { if (type === &quot;image/png&quot;) { console.log(type); const blob = await clipboardItem.getType(type); } } }`, `27604428011343974000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> items <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>clipboard<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</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">const</span> clipboardItem <span class="token keyword">of</span> items<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">const</span> type <span class="token keyword">of</span> clipboardItem<span class="token punctuation">.</span>types<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token string">"image/png"</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>type<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> blob <span class="token operator">=</span> <span class="token keyword">await</span> clipboardItem<span class="token punctuation">.</span><span class="token function">getType</span><span class="token punctuation">(</span>type<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can see a full demo here:</p> <iframe height="265" style="width: 100%;" scrolling="no" title="Clipboard API Image Demo" src="https://codepen.io/yashints/embed/preview/bGNvpGM?height=265&theme-id=default&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/bGNvpGM'>Clipboard API Image Demo</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h2 id="browser-support" style="position:relative;"><a href="#browser-support" aria-label="browser support permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Browser support</h2> <p>The browser support for this API as of writing this article is not there yet. Chrome and Firefox are fully supporting both the Clipboard API and ClipboardEvent API.</p> <p>Edge doesn’t support it and it’s been worked on in Safari.</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 easy and convenient it is to work with clipboard with this awesome API, and how much better the user experience will be.</p> <p>So without further ado, happy coding 💻.</p><![CDATA[A year in review, what's coming 📆]]>https://yashints.dev/blog/2020/01/06/2019-2020https://yashints.dev/blog/2020/01/06/2019-2020Mon, 06 Jan 2020 00:00:00 GMT<p>I am back from a well deserved holiday and thought first thing first, I should review the last year and set some goals for the new one to be able to focus my energy to the right direction and learn from any mistake or missed opportunities.</p> <!--more--> <h2 id="a-review-on-2019" style="position:relative;"><a href="#a-review-on-2019" aria-label="a review on 2019 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>A review on 2019</h2> <p>Last year was a super hectic year for me personally. I was working a full time consultancy job, advancing in my public speaking journey (more on this later), kicking some goals and missing others. All in all, it was a year with some ‘wow great’ and some ‘oh boy’ moments.</p> <p>But let me start with the good parts first:</p> <ul> <li>Learnt so many new topics and concepts.</li> <li>Spoke at 8 major conferences and 7 meetups.</li> <li>Got promoted to lead consultant.</li> <li>Published 38 blog post.</li> <li>Restarted going to gym two to three times a week.</li> <li>Started on <a href="https://dev.to" target="_blank" rel="nofollow noopener noreferrer">Dev.to</a> and reached 15K followers, 170K post views, 6.5K reactions.</li> <li>Published two <em>npm</em> packages.</li> <li>Contributed to <em>Open Source</em>.</li> <li>Read 60 books 🤯 (technical and non-technical).</li> <li>Finished 10 side projects.</li> <li>Met so many amazing people and made new friends.</li> <li>And finished up with a position as a developer advocate for TelstraDev.</li> </ul> <p>It was so good and I couldn’t believe what a little motivation could do.</p> <p>However, this came with a cost, I felt nearly burnt down and exhausted from all of these activities, so I reduced them towards the end of the year and gave myself some time to recover. I didn’t touch Twitter (apart from posting some photos of my woodworking), didn’t check LinkedIn, read some books, restarted woodworking, enjoyed doing nothing basically.</p> <p>I don’t want to go through too much detail, overall it was a great year.</p> <h2 id="2020-where-to" style="position:relative;"><a href="#2020-where-to" aria-label="2020 where to permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>2020, where to?</h2> <p>Starting 2020 for me was a with mixed feelings. I wanted to fix some errors I made last year, but at the same time I had to take some tough decisions. So here are my 2020 goals:</p> <ul> <li>Be a better person.</li> <li>Read more books.</li> <li>Publish more targeted blog posts.</li> <li>Take good care of my body and mind.</li> <li>Learn more, listen more, talk less.</li> <li>Continue public speaking, but be more selective, get more invitation, maybe a keynote/locknote, help others get started.</li> <li>Be a caring and mindful advocate for developers out there.</li> <li>Continue woodworking, spend more time with family, and spend less of weekends on technical subjects to balance lifestyle.</li> <li>Be more productive by sleeping more, eating healthy food, and more exercise.</li> <li>Make new friends, surround myself with good people.</li> <li>And a nice to have one is to start a video podcast on web and front end.</li> </ul> <p>This list is not a far fetched list, it’s a carefully drafted one based on last year’s review and feedback.</p> <p>And I am so grateful for the support I’ve received by all of you. Keep your positive energy coming and stay tuned for some quality content coming up.</p><![CDATA[Image aspect ratio done right 😍]]>https://yashints.dev/blog/2019/12/19/image-aspect-ratiohttps://yashints.dev/blog/2019/12/19/image-aspect-ratioThu, 19 Dec 2019 00:00:00 GMT<p>If you have an image on the page which is 600x200 pixels, what is the chance of it shown exactly with that size? I’d say not likely, because most of the time it’s put inside a container which defined the width and the image is set to <code class="language-text">width: %100</code>. But the size of the image is not that important at this point, what is important is that you will have a DOM reflow once the image is loaded.</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>Let’s see this in action. I’ll use Glitch to quickly whip up a demo. We need three <code class="language-text">div</code>s, two of those contain a piece of text and the one in between contains an image.</p> <div class="gatsby-code-button-container" data-toaster-id="25370791109440470000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<head> <title>Image aspect ratio</title> <style> .image-container { width: 500px; } img { width: 100%; } </style> </head> <body> <h1>Image aspect ratio done right</h1> <div > <p> This is the first bit of text here! </p> </div> <div class=&quot;image-container&quot;> <img src=&quot;https://www.hindustantimes.com/rf/image_size_960x540/HT/p2/2018/09/08/Pictures/_7ae928c8-b34e-11e8-bb15-a1f88311a832.jpg&quot; width=&quot;960&quot; height=&quot;540&quot;/> </div> <div> <p> This is the second bit of text here! </p> </div> </body>`, `25370791109440470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Image aspect ratio<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"> <span class="token selector">.image-container</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 500px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">img</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Image aspect ratio done right<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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>p</span><span class="token punctuation">></span></span> This is the first bit of text here! <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 attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image-container<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">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.hindustantimes.com/rf/image_size_960x540/HT/p2/2018/09/08/Pictures/_7ae928c8-b34e-11e8-bb15-a1f88311a832.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>960<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>540<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> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span> This is the second bit of text here! <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>body</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can see the full page in <a href="https://glitch.com/~ruddy-gym" target="_blank" rel="nofollow noopener noreferrer">this Glitch app</a>.</p> <p>If we load the site under a slow network now (on high speed network you can’t see much of a difference), you will the page load like this:</p> <p><img src="/c4677bfe4e08c2658e0caf81766c19c7/before.gif" alt="Page loads with text first close together, then image loads and fills the gap"></p> <p>First the two paragraphs appear close to each other, then when the network request is finished, the image fills its gap and there is a DOM reflow performed to push the second paragraph down. How sad is that 😥?</p> <h2 id="solution-1" style="position:relative;"><a href="#solution-1" aria-label="solution 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Solution #1</h2> <p>The very first thing we can do is to simply set the image height to <code class="language-text">auto</code>. This is a new feature which has landed in FireFox and Chrome. This will tell the browser to find out the metadata from image attributes, calculate the necessary height and reserve that space. So all we need to do is this:</p> <div class="gatsby-code-button-container" data-toaster-id="46107975873344230000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<style> img { width: 100%; } </style>`, `46107975873344230000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"> <span class="token selector">img</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And we we reload the page on the same network, you can see the page load like this:</p> <p><img src="/9ee89c4d3dc4766a686e9856d9002a24/after.gif" alt="Page loads with text first with enough vertical distance between them based on image aspect ratio, then image loads and fills the gap"></p> <p>How good is that 😍?</p> <h2 id="solution-2" style="position:relative;"><a href="#solution-2" aria-label="solution 2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Solution #2</h2> <p>There is a <a href="https://drafts.csswg.org/css-sizing-4/#ratios" target="_blank" rel="nofollow noopener noreferrer">new proposal in a draft state</a> which is introducing a new CSS property called, well <code class="language-text">aspect-ratio</code>. With this you can simply add the property to <code class="language-text">img</code> tag and use the <code class="language-text">width</code> and <code class="language-text">height</code> attributes to tell the browser how much space should be reserved.</p> <div class="gatsby-code-button-container" data-toaster-id="9688266267918166000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`img { aspect-ratio: attr(width) / attr(height); }`, `9688266267918166000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">img</span> <span class="token punctuation">{</span> <span class="token property">aspect-ratio</span><span class="token punctuation">:</span> <span class="token function">attr</span><span class="token punctuation">(</span>width<span class="token punctuation">)</span> / <span class="token function">attr</span><span class="token punctuation">(</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>This has the benefit of being super simple, readable, and supporting most of the images on the web because many people already have put <code class="language-text">width</code> and <code class="language-text">height</code> attributes on their images.</p> <p>On the other hand, a junior developer who’s starting with HTML and CSS doesn’t have any trouble understanding what’s happening and how little should be done to do something properly.</p> <p>This has been implemented in Firefox, Chrome and Edge.</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>Getting image aspect ratio is very important especially if it impacts your site’s user experience. So knowing how to fix that issue is also important. Hope you’ve enjoyed this article and till next time 👋🏼.</p><![CDATA[Tensorflow.js available on WebAssembly backend 🔥]]>https://yashints.dev/blog/2019/12/17/tfjs-wasmhttps://yashints.dev/blog/2019/12/17/tfjs-wasmTue, 17 Dec 2019 00:00:00 GMT<p><a href="https://www.tensorflow.org/js/" target="_blank" rel="nofollow noopener noreferrer">Tensorflow.js</a> is a library which lets you perform machine learning in the browser or in Node. It uses the GPU or CPU to do training and calculation, but recently the team have done a great job and brought WebAssembly backend to its ecosystem so that you can perform predictions faster. So without further ado, let’s deep dive into this greatness.</p> <!--more--> <h2 id="scenario" style="position:relative;"><a href="#scenario" aria-label="scenario permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Scenario</h2> <p>Let’s assume you want to perform object detection in a given image. For this you can use multiple models, but for now let’s focus on <a href="https://github.com/tensorflow/tfjs-examples/tree/master/mobilenet" target="_blank" rel="nofollow noopener noreferrer">MobileNet</a>.</p> <p>We will use parcel to setup our app.</p> <h2 id="setup-without-wasm-backend" style="position:relative;"><a href="#setup-without-wasm-backend" aria-label="setup without wasm backend permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup without WASM backend</h2> <h3 id="packages" style="position:relative;"><a href="#packages" aria-label="packages permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Packages</h3> <p>We will need to have a <code class="language-text">package.json</code> file with below setup:</p> <div class="gatsby-code-button-container" data-toaster-id="5279301656714308000" data-toaster-class="gatsby-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;name&quot;: &quot;wasm-parcel&quot;, &quot;version&quot;: &quot;1.0.0&quot;, &quot;description&quot;: &quot;Sample parcel app that uses the WASM backend&quot;, &quot;scripts&quot;: { &quot;watch&quot;: &quot;parcel index.html --open&quot;, &quot;build&quot;: &quot;parcel build index.html&quot; }, &quot;dependencies&quot;: { &quot;@tensorflow/tfjs&quot;: &quot;^1.4.0&quot;, &quot;@tensorflow/tfjs-backend-wasm&quot;: &quot;1.4.0-alpha3&quot; }, &quot;browserslist&quot;: [ &quot;defaults&quot; ], &quot;devDependencies&quot;: { &quot;@babel/core&quot;: &quot;7.7.5&quot;, &quot;@babel/plugin-transform-runtime&quot;: &quot;^7.7.6&quot;, &quot;@babel/preset-env&quot;: &quot;^7.7.6&quot;, &quot;parcel-bundler&quot;: &quot;^1.12.4&quot;, &quot;parcel-plugin-static-files-copy&quot;: &quot;^2.2.1&quot; }, &quot;keywords&quot;: [] }`, `5279301656714308000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"wasm-parcel"</span><span class="token punctuation">,</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0.0"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Sample parcel app that uses the WASM backend"</span><span class="token punctuation">,</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"watch"</span><span class="token operator">:</span> <span class="token string">"parcel index.html --open"</span><span class="token punctuation">,</span> <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"parcel build index.html"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"dependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"@tensorflow/tfjs"</span><span class="token operator">:</span> <span class="token string">"^1.4.0"</span><span class="token punctuation">,</span> <span class="token property">"@tensorflow/tfjs-backend-wasm"</span><span class="token operator">:</span> <span class="token string">"1.4.0-alpha3"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"browserslist"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"defaults"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"@babel/core"</span><span class="token operator">:</span> <span class="token string">"7.7.5"</span><span class="token punctuation">,</span> <span class="token property">"@babel/plugin-transform-runtime"</span><span class="token operator">:</span> <span class="token string">"^7.7.6"</span><span class="token punctuation">,</span> <span class="token property">"@babel/preset-env"</span><span class="token operator">:</span> <span class="token string">"^7.7.6"</span><span class="token punctuation">,</span> <span class="token property">"parcel-bundler"</span><span class="token operator">:</span> <span class="token string">"^1.12.4"</span><span class="token punctuation">,</span> <span class="token property">"parcel-plugin-static-files-copy"</span><span class="token operator">:</span> <span class="token string">"^2.2.1"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"keywords"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="html" style="position:relative;"><a href="#html" aria-label="html permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>HTML</h3> <p>Let’s setup our app like we do normally with <strong>Tensorflow.js</strong>. We need to add a <code class="language-text">div</code> to show the status, and another <code class="language-text">div</code> which contains an image tag:</p> <div class="gatsby-code-button-container" data-toaster-id="149691386930328.47" data-toaster-class="gatsby-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;tfjs-example-container&quot;> <section class=&quot;title-area&quot;> <h1>TensorFlow.js running on WebAssembly backend</h1> </section> <section> <p class=&quot;section-head&quot;>Status</p> <div id=&quot;status&quot;></div> </section> <section> <p class=&quot;section-head&quot;>Image used</p> <img id=&quot;img&quot; src=&quot;https://cdn.glitch.com/6e79f1d1-4e57-42bc-a2aa-0aaca87b6f6d%2Fpiano.jpg?v=1576551575229&quot; width=&quot;224px&quot; /> </section> </div>`, `149691386930328.47`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>tfjs-example-container<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>section</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>title-area<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>h1</span><span class="token punctuation">></span></span>TensorFlow.js running on WebAssembly backend<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</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>section-head<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Status<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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>status<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>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</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>section-head<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Image used<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>img</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>img<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://cdn.glitch.com/6e79f1d1-4e57-42bc-a2aa-0aaca87b6f6d%2Fpiano.jpg?v=1576551575229<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>224px<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>section</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And let’s our JavaScript file before body close tag:</p> <div class="gatsby-code-button-container" data-toaster-id="65684385860574855000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script src=&quot;index.js&quot;></script>`, `65684385860574855000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>index.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Altogether your HTML should look something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="30589066744232428000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE html> <html lang=&quot;en&quot;> <head> <title>Hello!</title> <meta charset=&quot;utf-8&quot; /> <meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /> <meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /> <link rel=&quot;stylesheet&quot; href=&quot;style.css&quot; /> </head> <body> <div class=&quot;tfjs-example-container&quot;> <section class=&quot;title-area&quot;> <h1>TensorFlow.js running on WebAssembly backend</h1> </section> <section> <p class=&quot;section-head&quot;>Status</p> <div id=&quot;status&quot;></div> </section> <section> <p class=&quot;section-head&quot;>Image used</p> <img id=&quot;img&quot; src=&quot;https://cdn.glitch.com/6e79f1d1-4e57-42bc-a2aa-0aaca87b6f6d%2Fpiano.jpg?v=1576551575229&quot; width=&quot;224px&quot; /> </section> <script src=&quot;index.js&quot;></script> </div> </body> </html>`, `30589066744232428000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<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>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Hello!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-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>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<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>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></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>style.css<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>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</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>tfjs-example-container<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>section</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>title-area<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>h1</span><span class="token punctuation">></span></span>TensorFlow.js running on WebAssembly backend<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</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>section-head<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Status<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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>status<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>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</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>section-head<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Image used<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>img</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>img<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://cdn.glitch.com/6e79f1d1-4e57-42bc-a2aa-0aaca87b6f6d%2Fpiano.jpg?v=1576551575229<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>224px<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>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>index.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</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>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="css" style="position:relative;"><a href="#css" aria-label="css permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CSS</h3> <p>Let’s add some basic styling so that it’s not an ugly app when we run it. We’re doing some cool stuff here and it deserves good look 😉:</p> <div class="gatsby-code-button-container" data-toaster-id="86894502868278640000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`/* CSS files add styling rules to your content */ body { font-family: helvetica, arial, sans-serif; margin: 2em; } p { max-width: 960px; line-height: 1.6em; } p.section-head { font-variant: small-caps; text-transform: uppercase; letter-spacing: 0.17em; line-height: 1.2em; font-weight: 500; margin-top: 2em; margin-bottom: 1em; border-left: 2px solid #ef6c00; padding-left: 24px; margin-left: -24px; color: #818181; } `, `86894502868278640000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token comment">/* CSS files add styling rules to your content */</span> <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">font-family</span><span class="token punctuation">:</span> helvetica<span class="token punctuation">,</span> arial<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">p</span> <span class="token punctuation">{</span> <span class="token property">max-width</span><span class="token punctuation">:</span> 960px<span class="token punctuation">;</span> <span class="token property">line-height</span><span class="token punctuation">:</span> 1.6em<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">p.section-head</span> <span class="token punctuation">{</span> <span class="token property">font-variant</span><span class="token punctuation">:</span> small-caps<span class="token punctuation">;</span> <span class="token property">text-transform</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span> <span class="token property">letter-spacing</span><span class="token punctuation">:</span> 0.17em<span class="token punctuation">;</span> <span class="token property">line-height</span><span class="token punctuation">:</span> 1.2em<span class="token punctuation">;</span> <span class="token property">font-weight</span><span class="token punctuation">:</span> 500<span class="token punctuation">;</span> <span class="token property">margin-top</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">border-left</span><span class="token punctuation">:</span> 2px solid #ef6c00<span class="token punctuation">;</span> <span class="token property">padding-left</span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> -24px<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> #818181<span class="token punctuation">;</span> <span class="token punctuation">}</span> </code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="javascript" style="position:relative;"><a href="#javascript" aria-label="javascript permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>JavaScript</h3> <p>In the code we need to perform two main operations, load the model, and use it for prediction. So lets load the model first:</p> <div class="gatsby-code-button-container" data-toaster-id="19041343057199930000" data-toaster-class="gatsby-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 * as tf from &quot;@tensorflow/tfjs&quot;; let model = await tf.loadGraphModel( &quot;https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/2&quot;, { fromTFHub: true } );`, `19041343057199930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> tf <span class="token keyword">from</span> <span class="token string">"@tensorflow/tfjs"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> model <span class="token operator">=</span> <span class="token keyword">await</span> tf<span class="token punctuation">.</span><span class="token function">loadGraphModel</span><span class="token punctuation">(</span> <span class="token string">"https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/2"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">fromTFHub</span><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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And we get a reference to the image tag, use <code class="language-text">browser.fromPixel</code> method of <strong>Tensorflow.js</strong> to load the image and normalise it. And at last, feed it into predict method of our model:</p> <div class="gatsby-code-button-container" data-toaster-id="80463804453293690000" data-toaster-class="gatsby-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 imgElement = document.getElementById(&quot;img&quot;); let img = tf.browser .fromPixels(imgElement) .resizeBilinear([224, 224]) .expandDims(0) .toFloat(); const prediction = model.predict(img);`, `80463804453293690000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> imgElement <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"img"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> img <span class="token operator">=</span> tf<span class="token punctuation">.</span>browser <span class="token punctuation">.</span><span class="token function">fromPixels</span><span class="token punctuation">(</span>imgElement<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">resizeBilinear</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">224</span><span class="token punctuation">,</span> <span class="token number">224</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">expandDims</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">toFloat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> prediction <span class="token operator">=</span> model<span class="token punctuation">.</span><span class="token function">predict</span><span class="token punctuation">(</span>img<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Since we want to compare the timing between the two approach, let’s add some timers into our method and measure how long the operation would take. Altogether your JavaScript file should look like this:</p> <div class="gatsby-code-button-container" data-toaster-id="81801666886140220000" data-toaster-class="gatsby-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 * as tf from &quot;@tensorflow/tfjs&quot;; function status(text) { document.getElementById(&quot;status&quot;).textContent = text; } async function main() { let model = await tf.loadGraphModel( &quot;https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/2&quot;, { fromTFHub: true } ); const startTime1 = performance.now(); const imgElement = document.getElementById(&quot;img&quot;); status(&quot;Model loaded!&quot;); let img = tf.browser .fromPixels(imgElement) .resizeBilinear([224, 224]) .expandDims(0) .toFloat(); let startTime2 = performance.now(); const logits = model.predict(img); const totalTime1 = performance.now() - startTime1; const totalTime2 = performance.now() - startTime2; status(\`Done in \${Math.floor(totalTime1)} ms \` + \`(not including preprocessing: \${Math.floor(totalTime2)} ms)\`); const values = await logits.data(); console.log(values); } document.addEventListener(&quot;DOMContentLoaded&quot;, main);`, `81801666886140220000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> tf <span class="token keyword">from</span> <span class="token string">"@tensorflow/tfjs"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">status</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"status"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> text<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> model <span class="token operator">=</span> <span class="token keyword">await</span> tf<span class="token punctuation">.</span><span class="token function">loadGraphModel</span><span class="token punctuation">(</span> <span class="token string">"https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/2"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">fromTFHub</span><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 keyword">const</span> startTime1 <span class="token operator">=</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> imgElement <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"img"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">status</span><span class="token punctuation">(</span><span class="token string">"Model loaded!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> img <span class="token operator">=</span> tf<span class="token punctuation">.</span>browser <span class="token punctuation">.</span><span class="token function">fromPixels</span><span class="token punctuation">(</span>imgElement<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">resizeBilinear</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">224</span><span class="token punctuation">,</span> <span class="token number">224</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">expandDims</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">toFloat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> startTime2 <span class="token operator">=</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> logits <span class="token operator">=</span> model<span class="token punctuation">.</span><span class="token function">predict</span><span class="token punctuation">(</span>img<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> totalTime1 <span class="token operator">=</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime1<span class="token punctuation">;</span> <span class="token keyword">const</span> totalTime2 <span class="token operator">=</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime2<span class="token punctuation">;</span> <span class="token function">status</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Done in </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>totalTime1<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ms </span><span class="token template-punctuation string">`</span></span> <span class="token operator">+</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">(not including preprocessing: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>totalTime2<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ms)</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> values <span class="token operator">=</span> <span class="token keyword">await</span> logits<span class="token punctuation">.</span><span class="token function">data</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>values<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"DOMContentLoaded"</span><span class="token punctuation">,</span> main<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="babelrc" style="position:relative;"><a href="#babelrc" aria-label="babelrc permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>.babelrc</h3> <p>If you don’t setup the babel plugins properly, you will get an error like below:</p> <div class="custom-block danger"><div class="custom-block-body"> ❌ Uncaught ReferenceError: regeneratorRuntime is not defined at HTMLDocument.main (index.js:8)</div></div> <p>That’s because we’re using an <code class="language-text">async</code> function on the top level. Add the below config to your <code class="language-text">.babelrc</code> file to get around the error.</p> <div class="gatsby-code-button-container" data-toaster-id="47104661353617880000" data-toaster-class="gatsby-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;presets&quot;: [&quot;@babel/preset-env&quot;], &quot;plugins&quot;: [&quot;@babel/plugin-transform-runtime&quot;] }`, `47104661353617880000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"@babel/preset-env"</span><span class="token punctuation">]</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 string">"@babel/plugin-transform-runtime"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="running-the-app" style="position:relative;"><a href="#running-the-app" aria-label="running 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>Running the app</h2> <p>Now you can run <code class="language-text">yarn</code> followed by <code class="language-text">yarn watch</code> and a browser window opens with the app inside. You should see a page 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/44070d465bc15837e513a2e69afdddde/e5166/before.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 67.03703703703704%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAEDBQb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAG8gGZMQf/EABkQAAIDAQAAAAAAAAAAAAAAAAADAgQ0Ev/aAAgBAQABBQIfnFw5ZZzn/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHBAAAQQDAQAAAAAAAAAAAAAAAQACEHEDERIx/9oACAEBAAY/AvSn1Dj0TtZKj//EABoQAAIDAQEAAAAAAAAAAAAAAAABESExEKH/2gAIAQEAAT8hgFi17G7G2WYz0ef/2gAMAwEAAgADAAAAECMP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBABAAICAwEAAAAAAAAAAAAAAQARIVEQcZHw/9oACAEBAAE/ELq+EZtm7qMpHESJEVxC1oMXifK1x//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Tensorflow.js prediction using GPU backend in browser to detect an object in a photo" title="" src="/static/44070d465bc15837e513a2e69afdddde/47311/before.jpg" srcset="/static/44070d465bc15837e513a2e69afdddde/6f81f/before.jpg 270w, /static/44070d465bc15837e513a2e69afdddde/09d21/before.jpg 540w, /static/44070d465bc15837e513a2e69afdddde/47311/before.jpg 1080w, /static/44070d465bc15837e513a2e69afdddde/e5166/before.jpg 1200w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Note the time taken to predict what’s in the picture. Now lets add the WebAssebly backend and run the app to see how it performs.</p> <h2 id="with-wasm-backend" style="position:relative;"><a href="#with-wasm-backend" aria-label="with wasm backend permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>With WASM backend</h2> <p>In order to add the WebAssembly backend you need to install the <code class="language-text">@tensorflow/tfjs-backend-wasm</code> package:</p> <div class="gatsby-code-button-container" data-toaster-id="20388491349616288000" data-toaster-class="gatsby-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;dependencies&quot;: { &quot;@tensorflow/tfjs&quot;: &quot;^1.4.0&quot;, &quot;@tensorflow/tfjs-backend-wasm&quot;: &quot;1.4.0-alpha3&quot; }, ... }`, `20388491349616288000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"dependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"@tensorflow/tfjs"</span><span class="token operator">:</span> <span class="token string">"^1.4.0"</span><span class="token punctuation">,</span> <span class="token property">"@tensorflow/tfjs-backend-wasm"</span><span class="token operator">:</span> <span class="token string">"1.4.0-alpha3"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Next step is to let Parcel know how to load the WASM file. When the WASM backend is initialized, there will be a <code class="language-text">fetch</code> / <code class="language-text">readFile</code> for a file named <code class="language-text">tfjs-backend-wasm.wasm</code> relative to the main JS file. That’s why we need to use this section if we’re using a bundler.</p> <div class="gatsby-code-button-container" data-toaster-id="11146441855731149000" data-toaster-class="gatsby-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;staticFiles&quot;: { &quot;staticPath&quot;: &quot;./node_modules/@tensorflow/tfjs-backend-wasm/dist&quot;, &quot;excludeGlob&quot;: [ &quot;**/!(*.wasm)&quot; ] }, ... }`, `11146441855731149000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"staticFiles"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"staticPath"</span><span class="token operator">:</span> <span class="token string">"./node_modules/@tensorflow/tfjs-backend-wasm/dist"</span><span class="token punctuation">,</span> <span class="token property">"excludeGlob"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"**/!(*.wasm)"</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And the last thing we need to do is to tell <strong>Tensorflow.js</strong> to use this backend:</p> <div class="gatsby-code-button-container" data-toaster-id="5618359467777289000" data-toaster-class="gatsby-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;@tensorflow/tfjs-backend-wasm&quot;; async function main() { await tf.setBackend(&quot;wasm&quot;); //... }`, `5618359467777289000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token string">"@tensorflow/tfjs-backend-wasm"</span><span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> tf<span class="token punctuation">.</span><span class="token function">setBackend</span><span class="token punctuation">(</span><span class="token string">"wasm"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//...</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And that’s all you need in order to enable the WebAssembly backend. Now let’s run the app and see the difference:</p> <div class="gatsby-code-button-container" data-toaster-id="23213483836999970000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`yarn && yarn watch`, `23213483836999970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">yarn</span> <span class="token operator">&amp;&amp;</span> <span class="token function">yarn</span> <span class="token function">watch</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You should see the app compiled and a browser window open:</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/83a3c64e1260df608a8921be9ac4bf6c/e5166/after.jpg" 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/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAEDBQb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAG8gYZMQf/EABkQAAIDAQAAAAAAAAAAAAAAAAACAwQ0Ef/aAAgBAQABBQIsZxE5LZzn/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHBAAAQMFAAAAAAAAAAAAAAAAAgAQcQESITFB/9oACAEBAAY/Ato4YiurniOG/8QAGxAAAgMAAwAAAAAAAAAAAAAAAAERITEQUaH/2gAIAQEAAT8hi9CRa9jdjZj7MPT4/9oADAMBAAIAAwAAABCjD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQACAgMBAAAAAAAAAAAAAAEAETFRECFB8P/aAAgBAQABPxBSqy4iNW2eRlItMoEVaojQe9VPna4//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Tensorflow.js running on WebAssembly backend to detect an object in an image" title="" src="/static/83a3c64e1260df608a8921be9ac4bf6c/47311/after.jpg" srcset="/static/83a3c64e1260df608a8921be9ac4bf6c/6f81f/after.jpg 270w, /static/83a3c64e1260df608a8921be9ac4bf6c/09d21/after.jpg 540w, /static/83a3c64e1260df608a8921be9ac4bf6c/47311/after.jpg 1080w, /static/83a3c64e1260df608a8921be9ac4bf6c/e5166/after.jpg 1200w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>And boom 🤯, look at the difference there. Almost down by 2 seconds, and that’s just doing a single operation. Imagine if we were doing more operations and the benefits we gain from this approach.</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>You can find <a href="https://github.com/yashints/tjfs-wasm-demo" target="_blank" rel="nofollow noopener noreferrer">the full demo on my GitHub repo</a>.</p> <p>This feature is defo one of the best thing that’s happened since introducing <strong>Tensorflow.js</strong> to allow web developers get into ML and AI within the browser in my opinion. So go ahead use this feature and benefit from the massive performance improvements.</p> <p>However, there is a catch 👇🏼:</p> <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>The catch is that not all functions are implemented in the WASM backend. It means you can’t run many of the demo’s on it unless the team implement them. You can <a href="https://github.com/tensorflow/tfjs/tree/master/tfjs-backend-wasm" target="_blank" rel="nofollow noopener noreferrer">follow the progress on their GitHub repo</a> to stay on top of the game.</p><![CDATA[Transfer learning with Tensorflow.js]]>https://yashints.dev/blog/2019/12/16/tfjs-transfer-learninghttps://yashints.dev/blog/2019/12/16/tfjs-transfer-learningMon, 16 Dec 2019 00:00:00 GMT<p><a href="https://www.tensorflow.org/js/" target="_blank" rel="nofollow noopener noreferrer">Tensorflow.js</a> is a library which lets you perform machine learning in the browser or in Node. A while ago I wrote <a href="https://yashints.dev/blog/2018/11/27/get-started-with-tensorflowjs" target="_blank" rel="nofollow noopener noreferrer">an intro</a> on it and also gave a few talks including one which had a live demo where I re-trained the <a href="https://github.com/tensorflow/tfjs-models/tree/master/speech-commands" target="_blank" rel="nofollow noopener noreferrer">Speech Command</a> model and flew a drone using my voice 😍. Many people asked about the details, so I decided to blog the whole thing down.</p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p><a href="https://github.com/tensorflow/tfjs-models/tree/master/speech-commands" target="_blank" rel="nofollow noopener noreferrer">Speech Command</a> is a machine learning model which allow you to classify 1-second audio snippets from the speech command dataset which has about 18 basic words (i.e. up, left, right, down, yes, no, etc) in it at the moment.</p> <p>In this article we want to expand the dataset using three words which we will use to fly a drone with. To do this we will be using a method called transfer learning, where we will use the pre-trained model and retrain it to learn new words.</p> <h2 id="requirements" style="position:relative;"><a href="#requirements" aria-label="requirements permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Requirements</h2> <p>You will need some basic knowledge around web development and JavaScript, and nothing else.</p> <h2 id="get-started" style="position:relative;"><a href="#get-started" aria-label="get started permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Get started</h2> <p>We will be using <a href="https://codesandbox.io/" target="_blank" rel="nofollow noopener noreferrer">Glitch</a> to quickly implement the app. So go ahead and<a href="https://glitch.com/~tfjs-glitch-starter" target="_blank" rel="nofollow noopener noreferrer">remix this starter template</a>.</p> <p>First thing first we should add the <code class="language-text">tensorflowjs</code> and <code class="language-text">speech-command</code> script to our page:</p> <div class="gatsby-code-button-container" data-toaster-id="36938800630281410000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE html> <html lang=&quot;en&quot;> <head> <title>Transfer learning with Tensorflow.js and Speech Command</title> <script src=&quot;https://unpkg.com/@tensorflow/tfjs&quot;></script> <script src=&quot;https://unpkg.com/@tensorflow-models/speech-commands&quot;></script> </head> <body> <h1>Tensorflow.js</h1> <div id=&quot;info&quot;></div> <!-- include the Glitch button to show what the webpage is about and to make it easier for folks to view source and remix --> <div class=&quot;glitchButton&quot; style=&quot;position:fixed;top:20px;right:20px;&quot;></div> <script src=&quot;https://button.glitch.me/button.js&quot;></script> <!-- import the webpage's javascript file --> <script src=&quot;/script.js&quot; defer></script> </body> </html>`, `36938800630281410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<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>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Transfer learning with Tensorflow.js and Speech Command<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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://unpkg.com/@tensorflow/tfjs<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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://unpkg.com/@tensorflow-models/speech-commands<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Tensorflow.js<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>info<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 comment">&lt;!-- include the Glitch button to show what the webpage is about and to make it easier for folks to view source and remix --></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>glitchButton<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">position</span><span class="token punctuation">:</span>fixed<span class="token punctuation">;</span><span class="token property">top</span><span class="token punctuation">:</span>20px<span class="token punctuation">;</span><span class="token property">right</span><span class="token punctuation">:</span>20px<span class="token punctuation">;</span></span><span class="token punctuation">"</span></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>script</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://button.glitch.me/button.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token comment">&lt;!-- import the webpage's javascript file --></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>/script.js<span class="token punctuation">"</span></span> <span class="token attr-name">defer</span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can leave the default Glitch button for now or delete it if you want. That just gives you ability to share it with others after it’s finished so they can remix and use it.</p> <p>We will use the <code class="language-text">&lt;div id="info"></code> tag to show output of model and training on the screen.</p> <h2 id="load-the-model" style="position:relative;"><a href="#load-the-model" aria-label="load the model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Load the model</h2> <p>Now we need to load the model which is very simple. All you need to do is to call the <code class="language-text">create</code> method on the speech commands’ object. The <code class="language-text">BROWSER_FFT</code> argument passed to it is just telling speech command to use the browser’s native Fourier transform. For more information regarding <a href="https://github.com/tensorflow/tfjs-models/blob/master/speech-commands/README.md" target="_blank" rel="nofollow noopener noreferrer">Speech Command’s APIs have a look at their ReadMe</a>.</p> <div class="gatsby-code-button-container" data-toaster-id="32321127884012892000" data-toaster-class="gatsby-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 recogniser; async function app() { recogniser = speechCommands.create('BROWSER_FFT'); await recogniser.ensureModelLoaded(); } app();`, `32321127884012892000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> recogniser<span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> recogniser <span class="token operator">=</span> speechCommands<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'BROWSER_FFT'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> recogniser<span class="token punctuation">.</span><span class="token function">ensureModelLoaded</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">app</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>💡 Note: If you’re using your local editor and <em>npm</em> to pull down the packages, you need to import the <code class="language-text">speechCommand</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="14986493179507554000" data-toaster-class="gatsby-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 * as speechCommands from '@tensorflow-models/speech-commands';`, `14986493179507554000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> speechCommands <span class="token keyword">from</span> <span class="token string">'@tensorflow-models/speech-commands'</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h2 id="collecting-data" style="position:relative;"><a href="#collecting-data" aria-label="collecting data permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Collecting data</h2> <p>It’s time to collect our sample audio to be able to feed it into our model. Our intention is to add three words (take off, land, and flip) to Speech Command dataset. For this we use three buttons to represent our words (labels in the world of machine learning) and another to capture background noise. The background noise bit is really important because it can make or break the whole setup (my first demo failed just because of this).</p> <div class="gatsby-code-button-container" data-toaster-id="66573558680450785000" data-toaster-class="gatsby-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 id=&quot;takeoff&quot; onmousedown=&quot;collectSample(0)&quot; onmouseup=&quot;collectSample(null)&quot;>Take Off</button> <button id=&quot;Land&quot; onmousedown=&quot;collectSample(1)&quot; onmouseup=&quot;collectSample(null)&quot;>Land</button> <button id=&quot;flip&quot; onmousedown=&quot;collectSample(2)&quot; onmouseup=&quot;collectSample(null)&quot;>Flip</button> <button id=&quot;noise&quot; onmousedown=&quot;collectSample(3)&quot; onmouseup=&quot;collectSample(null)&quot;>Noise</button>`, `66573558680450785000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>takeoff<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Take Off<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>button</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>Land<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Land<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>button</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>flip<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Flip<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>button</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>noise<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">collectSample</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Noise<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And we will need to implement the <code class="language-text">collectSample</code> method:</p> <div class="gatsby-code-button-container" data-toaster-id="61151517216818240000" data-toaster-class="gatsby-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 NUM_FRAMES = 6; let samples = []; function collectSample(label) { if (recogniser.isListening()) { return recogniser.stopListening(); } if (label == null) { return; } recogniser.listen(async ({spectrogram: {frameSize, data}}) => { let vals = normalise(data.subarray(-frameSize * NUM_FRAMES)); samples.push({vals, label}); document.querySelector('#info').textContent = \`\${samples.length} sample collected\`; }, { overlapFactor: 0.999, includeSpectrogram: true, invokeCallbackOnNoiseAndUnknown: true }); } function normalise(x) { const mean = -100; const std = 10; return x.map(x => (x - mean) / std); }`, `61151517216818240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token constant">NUM_FRAMES</span> <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span> <span class="token keyword">let</span> samples <span class="token operator">=</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">collectSample</span><span class="token punctuation">(</span><span class="token parameter">label</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>recogniser<span class="token punctuation">.</span><span class="token function">isListening</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> recogniser<span class="token punctuation">.</span><span class="token function">stopListening</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>label <span class="token operator">==</span> <span class="token keyword">null</span><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> recogniser<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span><span class="token literal-property property">spectrogram</span><span class="token operator">:</span> <span class="token punctuation">{</span>frameSize<span class="token punctuation">,</span> data<span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> vals <span class="token operator">=</span> <span class="token function">normalise</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span><span class="token function">subarray</span><span class="token punctuation">(</span><span class="token operator">-</span>frameSize <span class="token operator">*</span> <span class="token constant">NUM_FRAMES</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> samples<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>vals<span class="token punctuation">,</span> label<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#info'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>samples<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> sample collected</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 literal-property property">overlapFactor</span><span class="token operator">:</span> <span class="token number">0.999</span><span class="token punctuation">,</span> <span class="token literal-property property">includeSpectrogram</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">invokeCallbackOnNoiseAndUnknown</span><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">function</span> <span class="token function">normalise</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> mean <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">100</span><span class="token punctuation">;</span> <span class="token keyword">const</span> std <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token keyword">return</span> x<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> <span class="token punctuation">(</span>x <span class="token operator">-</span> mean<span class="token punctuation">)</span> <span class="token operator">/</span> std<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Let’s go through what’s happening here. The <code class="language-text">collectSample</code> method associates a label with the output of <code class="language-text">recogniser.listen()</code>. The <code class="language-text">includeSpectrogram</code> flag makes sure that recogniser gives the raw data frequency of 1 sec of audio which then is divided into 43 frames.</p> <p>Because we’re aiming for short sound tracks, we will take into accounts only the last 6 frames (~140ms), enough to give us time to pronounce the words:</p> <div class="gatsby-code-button-container" data-toaster-id="54658135634461530000" data-toaster-class="gatsby-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 vals = normalize(data.subarray(-frameSize * NUM_FRAMES));`, `54658135634461530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> vals <span class="token operator">=</span> <span class="token function">normalize</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span><span class="token function">subarray</span><span class="token punctuation">(</span><span class="token operator">-</span>frameSize <span class="token operator">*</span> <span class="token constant">NUM_FRAMES</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And last, to avoid any numerical issues, we normalise the data to have an average of 0 and a <a href="https://en.wikipedia.org/wiki/Standard_deviation" target="_blank" rel="nofollow noopener noreferrer">standard deviation</a> of 1. In our case the spectrogram values are usually large negative numbers around -100 with deviation of 10.</p> <p>All this info is saved to the samples variable.</p> <p>Feel free to test your sample collection to see if everything works fine so far.</p> <h2 id="train-the-model" style="position:relative;"><a href="#train-the-model" aria-label="train the model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Train the model</h2> <p>Now we need to build a model with the correct architecture (like Speech Command) and feed our sample data to it for training. We will use another button to trigger the training:</p> <div class="gatsby-code-button-container" data-toaster-id="47761075810599650000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<br/><br/> <button id=&quot;train&quot; onclick=&quot;train()&quot;>Train</button>`, `47761075810599650000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>train<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">train</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Train<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <div class="gatsby-code-button-container" data-toaster-id="87752915222844260000" data-toaster-class="gatsby-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 INPUT_SHAPE = [NUM_FRAMES, 232, 1]; let model; async function train() { toggleButtons(false); const ys = tf.oneHot(samples.map(e => e.label), 3); const xsShape = [samples.length, ...INPUT_SHAPE]; const xs = tf.tensor(flatten(samples.map(e => e.vals)), xsShape); await model.fit(xs, ys, { batchSize: 16, epochs: 10, callbacks: { onEpochEnd: (epoch, logs) => { document.querySelector('#info').textContent = \`Accuracy: \${(logs.acc * 100).toFixed(1)}% Epoch: \${epoch + 1}\`; } } }); tf.dispose([xs, ys]); toggleButtons(true); } function buildModel() { model = tf.sequential(); model.add(tf.layers.depthwiseConv2d({ depthMultiplier: 8, kernelSize: [NUM_FRAMES, 3], activation: 'relu', inputShape: INPUT_SHAPE })); model.add(tf.layers.maxPooling2d({poolSize: [1, 2], strides: [2, 2]})); model.add(tf.layers.flatten()); model.add(tf.layers.dense({units: 3, activation: 'softmax'})); const optimizer = tf.train.adam(0.01); model.compile({ optimizer, loss: 'categoricalCrossentropy', metrics: ['accuracy'] }); } function toggleButtons(enable) { document.querySelectorAll('button').forEach(b => b.disabled = !enable); } function flatten(tensors) { const size = tensors[0].length; const result = new Float32Array(tensors.length * size); tensors.forEach((arr, i) => result.set(arr, i * size)); return result; }`, `87752915222844260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token constant">INPUT_SHAPE</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token constant">NUM_FRAMES</span><span class="token punctuation">,</span> <span class="token number">232</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 keyword">let</span> model<span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">train</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">toggleButtons</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> ys <span class="token operator">=</span> tf<span class="token punctuation">.</span><span class="token function">oneHot</span><span class="token punctuation">(</span>samples<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">e</span> <span class="token operator">=></span> e<span class="token punctuation">.</span>label<span class="token punctuation">)</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 keyword">const</span> xsShape <span class="token operator">=</span> <span class="token punctuation">[</span>samples<span class="token punctuation">.</span>length<span class="token punctuation">,</span> <span class="token operator">...</span><span class="token constant">INPUT_SHAPE</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> xs <span class="token operator">=</span> tf<span class="token punctuation">.</span><span class="token function">tensor</span><span class="token punctuation">(</span><span class="token function">flatten</span><span class="token punctuation">(</span>samples<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">e</span> <span class="token operator">=></span> e<span class="token punctuation">.</span>vals<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> xsShape<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> model<span class="token punctuation">.</span><span class="token function">fit</span><span class="token punctuation">(</span>xs<span class="token punctuation">,</span> ys<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">batchSize</span><span class="token operator">:</span> <span class="token number">16</span><span class="token punctuation">,</span> <span class="token literal-property property">epochs</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token literal-property property">callbacks</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">onEpochEnd</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">epoch<span class="token punctuation">,</span> logs</span><span class="token punctuation">)</span> <span class="token operator">=></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">'#info'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Accuracy: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token punctuation">(</span>logs<span class="token punctuation">.</span>acc <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">% Epoch: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>epoch <span class="token operator">+</span> <span class="token number">1</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> tf<span class="token punctuation">.</span><span class="token function">dispose</span><span class="token punctuation">(</span><span class="token punctuation">[</span>xs<span class="token punctuation">,</span> ys<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">toggleButtons</span><span class="token punctuation">(</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 keyword">function</span> <span class="token function">buildModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> model <span class="token operator">=</span> tf<span class="token punctuation">.</span><span class="token function">sequential</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> model<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>tf<span class="token punctuation">.</span>layers<span class="token punctuation">.</span><span class="token function">depthwiseConv2d</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">depthMultiplier</span><span class="token operator">:</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token literal-property property">kernelSize</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">NUM_FRAMES</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 literal-property property">activation</span><span class="token operator">:</span> <span class="token string">'relu'</span><span class="token punctuation">,</span> <span class="token literal-property property">inputShape</span><span class="token operator">:</span> <span class="token constant">INPUT_SHAPE</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> model<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>tf<span class="token punctuation">.</span>layers<span class="token punctuation">.</span><span class="token function">maxPooling2d</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">poolSize</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 punctuation">,</span> <span class="token literal-property property">strides</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">2</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> model<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>tf<span class="token punctuation">.</span>layers<span class="token punctuation">.</span><span class="token function">flatten</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> model<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>tf<span class="token punctuation">.</span>layers<span class="token punctuation">.</span><span class="token function">dense</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">units</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token literal-property property">activation</span><span class="token operator">:</span> <span class="token string">'softmax'</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> optimizer <span class="token operator">=</span> tf<span class="token punctuation">.</span>train<span class="token punctuation">.</span><span class="token function">adam</span><span class="token punctuation">(</span><span class="token number">0.01</span><span class="token punctuation">)</span><span class="token punctuation">;</span> model<span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span><span class="token punctuation">{</span> optimizer<span class="token punctuation">,</span> <span class="token literal-property property">loss</span><span class="token operator">:</span> <span class="token string">'categoricalCrossentropy'</span><span class="token punctuation">,</span> <span class="token literal-property property">metrics</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'accuracy'</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">toggleButtons</span><span class="token punctuation">(</span><span class="token parameter">enable</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">b</span> <span class="token operator">=></span> b<span class="token punctuation">.</span>disabled <span class="token operator">=</span> <span class="token operator">!</span>enable<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">flatten</span><span class="token punctuation">(</span><span class="token parameter">tensors</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> size <span class="token operator">=</span> tensors<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Float32Array</span><span class="token punctuation">(</span>tensors<span class="token punctuation">.</span>length <span class="token operator">*</span> size<span class="token punctuation">)</span><span class="token punctuation">;</span> tensors<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">arr<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=></span> result<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> i <span class="token operator">*</span> size<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> result<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And we add a call to build model in our entry function when the app loads:</p> <div class="gatsby-code-button-container" data-toaster-id="94432609312643040000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async function app() { recogniser = speechCommands.create(&quot;BROWSER_FFT&quot;); await recogniser.ensureModelLoaded(); document.getElementById(&quot;info&quot;).textContent = &quot;Model loaded&quot;; buildModel(); }`, `94432609312643040000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> recogniser <span class="token operator">=</span> speechCommands<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">"BROWSER_FFT"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> recogniser<span class="token punctuation">.</span><span class="token function">ensureModelLoaded</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"info"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">"Model loaded"</span><span class="token punctuation">;</span> <span class="token function">buildModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>At this point, you can see a train button on the page and if you click it after you’ve collected some sample data, you can see the training happen and the accuracy of the model shown after it’s finished.</p> <p>So let’s break this down because it does look a bit busy. First thing first we need to build a model with the right architecture. This model will have four layers, a convolutional layer that processes the audio data, a max pool layer, a flatten layer, and a dense layer that maps to all three actions.</p> <p>The input shape of the model is <code class="language-text">[NUM_FRAMES, 232, 1]</code> where each frame is 23ms of audio containing 232 numbers that correspond to different frequencies. In this demo we’re using samples that are 6 frames long (~140ms) because we’re using short words to control the drone.</p> <p>For the training part, we’re using 1- epochs (imagine the number of iterations which model uses to go through running it’s operations end to end).</p> <h2 id="capturing-the-words" style="position:relative;"><a href="#capturing-the-words" aria-label="capturing the words permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Capturing the words</h2> <p>It’s time to capture a word, feed it into the model and see how accurate it is. Let’s add another button to trigger listening:</p> <div class="gatsby-code-button-container" data-toaster-id="22568931098126700000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<br/><br/> <button id=&quot;listen&quot; onclick=&quot;listen()&quot;>Listen</button>`, `22568931098126700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>listen<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">listen</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Listen<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Then we need to listen to the microphone through browser and feed that into the model to see what is the output.</p> <div class="gatsby-code-button-container" data-toaster-id="99865701415914180000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async function controlDrone(labelTensor) { const label = (await labelTensor.data())[0]; if (label == 3) { return; } let recognisedWord = &quot;none&quot;; switch (label) { case 0: recognisedWord = &quot;take off&quot;; break; case 1: recognisedWord = &quot;land&quot;; break; case 2: recognisedWord = &quot;flip&quot;; break; } document.getElementById(&quot;info&quot;).textContent = recognisedWord; } function listen() { if (recogniser.isListening()) { recogniser.stopListening(); toggleButtons(true); document.getElementById(&quot;listen&quot;).textContent = &quot;Listen&quot;; return; } toggleButtons(false); document.getElementById(&quot;listen&quot;).textContent = &quot;Stop&quot;; document.getElementById(&quot;listen&quot;).disabled = false; recogniser.listen( async ({ spectrogram: { frameSize, data } }) => { const vals = normalise(data.subarray(-frameSize * NUM_FRAMES)); const input = tf.tensor(vals, [1, ...INPUT_SHAPE]); const probs = model.predict(input); const predLabel = probs.argMax(1); await controlDrone(predLabel); tf.dispose([input, probs, predLabel]); }, { overlapFactor: 0.999, includeSpectrogram: true, invokeCallbackOnNoiseAndUnknown: true } ); }`, `99865701415914180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">controlDrone</span><span class="token punctuation">(</span><span class="token parameter">labelTensor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> label <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">await</span> labelTensor<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</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> <span class="token keyword">if</span> <span class="token punctuation">(</span>label <span class="token operator">==</span> <span class="token number">3</span><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">let</span> recognisedWord <span class="token operator">=</span> <span class="token string">"none"</span><span class="token punctuation">;</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>label<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token number">0</span><span class="token operator">:</span> recognisedWord <span class="token operator">=</span> <span class="token string">"take off"</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span> recognisedWord <span class="token operator">=</span> <span class="token string">"land"</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">2</span><span class="token operator">:</span> recognisedWord <span class="token operator">=</span> <span class="token string">"flip"</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"info"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> recognisedWord<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">listen</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>recogniser<span class="token punctuation">.</span><span class="token function">isListening</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> recogniser<span class="token punctuation">.</span><span class="token function">stopListening</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">toggleButtons</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"listen"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">"Listen"</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 function">toggleButtons</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"listen"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">"Stop"</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"listen"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>disabled <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> recogniser<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token literal-property property">spectrogram</span><span class="token operator">:</span> <span class="token punctuation">{</span> frameSize<span class="token punctuation">,</span> data <span class="token punctuation">}</span> <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> vals <span class="token operator">=</span> <span class="token function">normalise</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span><span class="token function">subarray</span><span class="token punctuation">(</span><span class="token operator">-</span>frameSize <span class="token operator">*</span> <span class="token constant">NUM_FRAMES</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> input <span class="token operator">=</span> tf<span class="token punctuation">.</span><span class="token function">tensor</span><span class="token punctuation">(</span>vals<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">...</span><span class="token constant">INPUT_SHAPE</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> probs <span class="token operator">=</span> model<span class="token punctuation">.</span><span class="token function">predict</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> predLabel <span class="token operator">=</span> probs<span class="token punctuation">.</span><span class="token function">argMax</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 keyword">await</span> <span class="token function">controlDrone</span><span class="token punctuation">(</span>predLabel<span class="token punctuation">)</span><span class="token punctuation">;</span> tf<span class="token punctuation">.</span><span class="token function">dispose</span><span class="token punctuation">(</span><span class="token punctuation">[</span>input<span class="token punctuation">,</span> probs<span class="token punctuation">,</span> predLabel<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 literal-property property">overlapFactor</span><span class="token operator">:</span> <span class="token number">0.999</span><span class="token punctuation">,</span> <span class="token literal-property property">includeSpectrogram</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">invokeCallbackOnNoiseAndUnknown</span><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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Again, let’s break this down a bit. The <code class="language-text">listen</code> method will listens to the microphone real time and feeds that into the model for predictions. The logic is very similar to <code class="language-text">collectSample</code> method where we normalise the data and drop all frames except the <code class="language-text">NUM_FRAMES</code> (6) frames. The difference is that we call <code class="language-text">model.predict</code> method to see what is been spoken.</p> <p>The output of the prediction is a tensor with the shape of <code class="language-text">[1, numClasses]</code> representing a probability distribution over all our classes (labels). We will use the first one returned to as it will be the strongest match using <code class="language-text">probs.argMax(1)</code>.</p> <p>Now we can call the <code class="language-text">.data()</code> and get it’s first argument to get our label from it:</p> <div class="gatsby-code-button-container" data-toaster-id="83991969441856230000" data-toaster-class="gatsby-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 label = (await labelTensor.data())[0];`, `83991969441856230000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> label <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">await</span> labelTensor<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>I’ve used a switch case for simplicity, but feel free to chuck them all in a set and use it’s index.</p> <p><strong>Note:</strong> It’s very important to dispose the output tensors to clean up the memory through a call to <code class="language-text">tf.dispose([input, probs, predLabel]);</code>.</p> <h2 id="test-the-whole-demo" style="position:relative;"><a href="#test-the-whole-demo" aria-label="test the whole 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>Test the whole demo</h2> <p>It’s time to give our full demo a shot. Record the samples and the background noise, then train the model and then verify it using the listen button.</p> <blockquote> <p>💡 For my demo, I had to use a recording of the drone’s flying in order to be able to run it successfully. That’s because the first command always works because there is no background noise, but once the drone is up, the noise of the drone will mask the consequent words 😁. So when recording noise, use a drone’s actual noise which you can find on <a href="">YouTube</a>.</p> </blockquote> <p><a href="https://glitch.com/~abrasive-ixora" target="_blank" rel="nofollow noopener noreferrer">See the full working demo on Glitch</a>.</p> <p>I will do another post on how to wire this up with the server side code to fly the drone 🚁 (think of a drone when you look at the helicopter emoji 😁).</p><![CDATA[State management in Vue.js]]>https://yashints.dev/blog/2019/11/18/vue-state-managementhttps://yashints.dev/blog/2019/11/18/vue-state-managementMon, 18 Nov 2019 00:00:00 GMT<p><a href="https://vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue.js</a> is an approachable, versatile, performant, and progressive framework to build user interfaces with. I’ve written three separate articles on it so far:</p> <ul> <li><a href="https://yashints.dev/blog/2019/10/18/vue-intro" target="_blank" rel="nofollow noopener noreferrer">A comprehensive intro to Vue.js</a></li> <li><a href="https://yashints.dev/blog/2019/10/30/vue-router" target="_blank" rel="nofollow noopener noreferrer">Deliver a better user experience using Vue Router</a></li> <li><a href="https://yashints.dev/blog/2019/11/10/vue-form-handling" target="_blank" rel="nofollow noopener noreferrer">Form handling in Vue.js</a></li> </ul> <p>We will be looking at state management in <strong>Vue.js</strong> this time which is the centre of communication in large applications.</p> <!--more--> <h2 id="why-do-we-need-state-management" style="position:relative;"><a href="#why-do-we-need-state-management" aria-label="why do we need state management permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 do we need state management</h2> <p>When dealing with large applications, we definitely have to pass information between components. Shopping card needs to know whether the user is logged in or not, the search needs to get updated based on changes to filter data, and many more scenarios.</p> <p>The usual ways of passing data such as props only gets us just that far. Things get complex when we want to pass the data in multiple layers of component hierarchy. Or even when we want to pass data into components outside of those hierarchies.</p> <p>At the end of the day, it’s important to have a single source of truth and that’s what <strong>Vue</strong> is offering to solve using <a href="https://github.com/vuejs/vuex" target="_blank" rel="nofollow noopener noreferrer">vuex</a>. But consider using a state management library if:</p> <ul> <li>Multiple views may depend on the same piece of state.</li> <li>Actions from different views may need to mutate the same piece of state.</li> </ul> <h2 id="vuex" style="position:relative;"><a href="#vuex" aria-label="vuex permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Vuex</h2> <p><a href="https://github.com/vuejs/vuex" target="_blank" rel="nofollow noopener noreferrer">vuex</a> is an Elm-inspired state management library. It integrates really well into <a href="https://github.com/vuejs/vue-devtools" target="_blank" rel="nofollow noopener noreferrer">vue-devtools</a>, providing zero-setup access to <a href="https://raw.githubusercontent.com/vuejs/vue-devtools/master/media/demo.gif" target="_blank" rel="nofollow noopener noreferrer">time travel debugging</a>.</p> <p><strong>Vuex</strong> is based on <a href="https://facebook.github.io/flux/docs/in-depth-overview.html" target="_blank" rel="nofollow noopener noreferrer">Flux</a> (a state management design pattern introduced by Facebook). The TLDR version looks like:</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/60d4ac77bd07e6fa65d021649e97a070/aa276/flux.webp" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 32.59259259259259%; position: relative; bottom: 0; left: 0; background-image: url('data:image/webp;base64,UklGRhoBAABXRUJQVlA4WAoAAAAQAAAAEwAABgAAQUxQSGEAAAABcBvbtqrcL7hrAe6ZQ04BFOSnARwiGmVm4zVExATYn/Pb7XZ07W8nfAUoeP+EwrYDHoFA1KxWq5WsUuvVEsV+v9+1Ur1TA2gBLA4AOX5OPrb3j/KHpFVyI2k6k7QIriQBAFZQOCCSAAAAUAQAnQEqFAAHAD7RVqNLqCSjIbAIAQAaCWwAnTKCgAAKZN1O7fxDkjZmAAD3igfpRGIB88Q0VvvQCD9QDGJ4BiJdDeJgd8m6ZmNz/+s3qU6aeOcGLJX7rU+HI5wsW6/QpQ+azqTvYkoCT6vlL1PLva5Kdrz0EV0L7aaNf08cRYvdO4ZVBw3EN/tF5G3GhcWHwAA='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="flux data flow" title="" src="/static/60d4ac77bd07e6fa65d021649e97a070/260c2/flux.webp" srcset="/static/60d4ac77bd07e6fa65d021649e97a070/3e767/flux.webp 270w, /static/60d4ac77bd07e6fa65d021649e97a070/9e625/flux.webp 540w, /static/60d4ac77bd07e6fa65d021649e97a070/260c2/flux.webp 1080w, /static/60d4ac77bd07e6fa65d021649e97a070/7509d/flux.webp 1620w, /static/60d4ac77bd07e6fa65d021649e97a070/6d2c9/flux.webp 2160w, /static/60d4ac77bd07e6fa65d021649e97a070/aa276/flux.webp 2866w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></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>If you haven’t used <strong>Vue</strong> CLI to create your project, there are three steps you need to take:</p> <p>Install the library:</p> <div class="gatsby-code-button-container" data-toaster-id="63002601611888796000" data-toaster-class="gatsby-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 vuex --save`, `63002601611888796000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> vuex <span class="token parameter variable">--save</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Import and wire it up:</p> <div class="gatsby-code-button-container" data-toaster-id="41731264222615060000" data-toaster-class="gatsby-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 Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)`, `41731264222615060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> Vue <span class="token keyword">from</span> <span class="token string">'vue'</span> <span class="token keyword">import</span> Vuex <span class="token keyword">from</span> <span class="token string">'vuex'</span> Vue<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>Vuex<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And last, because <strong>Vuex</strong> requires <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises" target="_blank" rel="nofollow noopener noreferrer">Promise</a> you should include a package like <a href="https://github.com/stefanpenner/es6-promise" target="_blank" rel="nofollow noopener noreferrer"><code class="language-text">es6-promise</code></a> and import it before using <strong>Vuex</strong>:</p> <div class="gatsby-code-button-container" data-toaster-id="3788206082871092700" data-toaster-class="gatsby-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 es6-promise --save`, `3788206082871092700`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> es6-promise <span class="token parameter variable">--save</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="27389432744964040000" data-toaster-class="gatsby-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 'es6-promise/auto'`, `27389432744964040000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'es6-promise/auto'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"> 💡 This library will automatically use a polyfill if the browser doesn’t support ES6’s <code class="language-text">Promise</code>.</div></div> <h2 id="getting-started" style="position:relative;"><a href="#getting-started" aria-label="getting started permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 started</h2> <p>In its simplest form, you can use a centralised store as such:</p> <div class="gatsby-code-button-container" data-toaster-id="5189600721947252000" data-toaster-class="gatsby-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 store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++; } } })`, `5189600721947252000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vuex<span class="token punctuation">.</span>Store</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">state</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">mutations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">increment</span> <span class="token punctuation">(</span><span class="token parameter">state</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> state<span class="token punctuation">.</span>count<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now, you can access the state object as <code class="language-text">store.state</code>, and trigger a state change with the <code class="language-text">store.commit</code> function:</p> <div class="gatsby-code-button-container" data-toaster-id="51002857544131740000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`console.log(store.state.count) // -> 0 store.commit('increment') console.log(store.state.count) // -> 1`, `51002857544131740000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>state<span class="token punctuation">.</span>count<span class="token punctuation">)</span> <span class="token comment">// -> 0</span> store<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token string">'increment'</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>state<span class="token punctuation">.</span>count<span class="token punctuation">)</span> <span class="token comment">// -> 1</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="vuex-state" style="position:relative;"><a href="#vuex-state" aria-label="vuex state permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Vuex state</h2> <p>This library uses a single state tree which ensures that the source of truth is always the state. However, this doesn’t have any conflicts with the modularity. We will have a look at the <code class="language-text">sub-modules</code> later.</p> <p><strong>Vuex</strong>’s state consist of four objects, <code class="language-text">state</code>, <code class="language-text">mutations</code>, <code class="language-text">actions</code>, and <code class="language-text">getters</code>. So lets see what each of these are. But first, let’s see how we can use the store in our components. We use our previous students example from here on.</p> <h2 id="including-store-in-your-components" style="position:relative;"><a href="#including-store-in-your-components" aria-label="including store in your 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>Including store in your components</h2> <p><strong>Vuex</strong> provides a mechanism to <em>inject</em> the store into all child components from the root component with the store option which happens when you use <code class="language-text">Vue.use(Vuex)</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="23689612163670204000" data-toaster-class="gatsby-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 Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { students: [ { name: 'Yas', age: 25 } ] } }) const app = new Vue({ el: '#app', store })`, `23689612163670204000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> Vue <span class="token keyword">from</span> <span class="token string">'vue'</span> <span class="token keyword">import</span> Vuex <span class="token keyword">from</span> <span class="token string">'vuex'</span> Vue<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>Vuex<span class="token punctuation">)</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vuex<span class="token punctuation">.</span>Store</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">state</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">students</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">25</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#app'</span><span class="token punctuation">,</span> store <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This will allow you to access state using <code class="language-text">this.$store</code> in any child component.</p> <div class="gatsby-code-button-container" data-toaster-id="44695911387626430000" data-toaster-class="gatsby-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 Students = { template: \` <ul> <li v-for=&quot;student in students&quot;>{{ student.name }}</li> </ul>\`, computed: { students () { return this.\$store.state.students } } }`, `44695911387626430000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> Students <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> &lt;ul> &lt;li v-for="student in students">{{ student.name }}&lt;/li> &lt;/ul></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">students</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$store<span class="token punctuation">.</span>state<span class="token punctuation">.</span>students <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Note how I accessed the student in a computed property. This will ensure that we rerender the page whenever store changes.</p> <h3 id="how-to-use-multiple-properties-from-state" style="position:relative;"><a href="#how-to-use-multiple-properties-from-state" aria-label="how to use multiple properties from state permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 to use multiple properties from state</h3> <p>If you have to use multiple properties from store, <strong>Vuex</strong> offers the <code class="language-text">mapState</code> helper method. Using this method you have the ability to map multiple properties from state to your computed properties:</p> <div class="gatsby-code-button-container" data-toaster-id="26359677953203397000" data-toaster-class="gatsby-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 { mapState } from 'vuex'; export default { name: &quot;Students&quot;, computed: mapState({ students: state => state.students, teachers: state => state.teachers }) };`, `26359677953203397000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mapState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vuex'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"Students"</span><span class="token punctuation">,</span> <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token function">mapState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token function-variable function">students</span><span class="token operator">:</span> <span class="token parameter">state</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>students<span class="token punctuation">,</span> <span class="token function-variable function">teachers</span><span class="token operator">:</span> <span class="token parameter">state</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>teachers <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see, you can use an arrow function to retrieve the state and access it’s properties. You can also define aliases to keep your code cleaner and avoid repeating <code class="language-text">state.property</code> everywhere you want to use it.</p> <p>If the local and store property names matches, you can skip the arrow function and just pass an array of property names you want to have:</p> <div class="gatsby-code-button-container" data-toaster-id="37899152193395280000" data-toaster-class="gatsby-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 { mapState } from 'vuex'; export default { name: &quot;Students&quot;, computed: mapState([ 'students', 'teachers' ]) };`, `37899152193395280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mapState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vuex'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"Students"</span><span class="token punctuation">,</span> <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token function">mapState</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">'students'</span><span class="token punctuation">,</span> <span class="token string">'teachers'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you have some local computed properties, you could use the spear operator to mix them with <code class="language-text">mapState</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="11583080880795560000" data-toaster-class="gatsby-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 { mapState } from 'vuex' export default { // ... computed: { myLocalProp() { return { name: 'Yas' } }, ...mapState({ numOfStudents: state => state.students.length, students: state => state.students }) } }`, `11583080880795560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mapState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vuex'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">myLocalProp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</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 operator">...</span><span class="token function">mapState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token function-variable function">numOfStudents</span><span class="token operator">:</span> <span class="token parameter">state</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>students<span class="token punctuation">.</span>length<span class="token punctuation">,</span> <span class="token function-variable function">students</span><span class="token operator">:</span> <span class="token parameter">state</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>students <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="getters" style="position:relative;"><a href="#getters" aria-label="getters permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Getters</h3> <p>Sometimes you need to have derived properties based on store’s state. For example if you want to know how many students are older than 25. You can implement this in your component like so:</p> <div class="gatsby-code-button-container" data-toaster-id="27428868160762200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<template> <div>Total number of students aged 25 or older is {{numOfStudents}}</div> </template> <script> import { mapState } from 'vuex' export default { // ... computed: mapState({ numOfStudents: state => state.students .filter(s => s.age > 24).length; }) } </script>`, `27428868160762200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</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>Total number of students aged 25 or older is {{numOfStudents}}<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>template</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">import</span> <span class="token punctuation">{</span> mapState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vuex'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token function">mapState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token function-variable function">numOfStudents</span><span class="token operator">:</span> <span class="token parameter">state</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>students <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">s</span> <span class="token operator">=></span> s<span class="token punctuation">.</span>age <span class="token operator">></span> <span class="token number">24</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>But this means that if another component wants to have this logic, they need to duplicate the code. A better approach to these sorts of derived state is to use getters.</p> <div class="gatsby-code-button-container" data-toaster-id="84162217978972910000" data-toaster-class="gatsby-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 store = new Vuex.Store({ state: { students: [ { id: 1, name: 'Yas', age: 26 } ] }, getters: { numOf25OrOlderStudents: state => { return state.students .filter(s => s.age > 24).length; } } })`, `84162217978972910000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vuex<span class="token punctuation">.</span>Store</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">state</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">students</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">26</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">getters</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">numOf25OrOlderStudents</span><span class="token operator">:</span> <span class="token parameter">state</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> state<span class="token punctuation">.</span>students <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">s</span> <span class="token operator">=></span> s<span class="token punctuation">.</span>age <span class="token operator">></span> <span class="token number">24</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>These sort of properties appear under <code class="language-text">store.getters</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="69010795741979590000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`computed: { numOf25OrOlderStudents () { return this.\$store.getters.numOf25OrOlderStudents } }`, `69010795741979590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">numOf25OrOlderStudents</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$store<span class="token punctuation">.</span>getters<span class="token punctuation">.</span>numOf25OrOlderStudents <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Similar to <code class="language-text">mapState</code>, you have <code class="language-text">mapGetter</code> so you can get these properties easier:</p> <div class="gatsby-code-button-container" data-toaster-id="8181326984756132000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`computed: { ...mapGetters([ 'numOf25OrOlderStudents', ]) }`, `8181326984756132000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span><span class="token function">mapGetters</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">'numOf25OrOlderStudents'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="mutations" style="position:relative;"><a href="#mutations" aria-label="mutations permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Mutations</h3> <p>A mutation is the only way you can change the state in <strong>Vuex</strong>. These mutations are basically events which have two properties:</p> <ul> <li>A string type</li> <li>A handler</li> </ul> <p>You’ll perform the modifications inside the handler and it will receive the state as it’s first argument:</p> <div class="gatsby-code-button-container" data-toaster-id="78256790901162050000" data-toaster-class="gatsby-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 store = new Vuex.Store({ state: { students: [ { id: 1, name: 'Yas', age: 26 } ] }, mutations: { addStudent (state, student) { // mutate state state.students.push(student) } } })`, `78256790901162050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vuex<span class="token punctuation">.</span>Store</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">state</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">students</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">26</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">mutations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">addStudent</span> <span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> student</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// mutate state</span> state<span class="token punctuation">.</span>students<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>student<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <blockquote> <p>💡 You can’t call a mutation handler directly, instead, you will need to call <code class="language-text">store.commit</code> method.</p> </blockquote> <div class="gatsby-code-button-container" data-toaster-id="97510768707285010000" data-toaster-class="gatsby-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 student = { id: 2, name: 'Alex', age: 23 } store.commit('addStudent', student)`, `97510768707285010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> student <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Alex'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">23</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">'addStudent'</span><span class="token punctuation">,</span> student<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Like <a href="https://react-redux.js.org/using-react-redux/connect-mapdispatch" target="_blank" rel="nofollow noopener noreferrer">React Redux</a>’s actions, it’s best to use constants for these mutation types:</p> <div class="gatsby-code-button-container" data-toaster-id="37482171413056545000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// mutation-types.js export const ADD_STUDENT_MUTATION = 'ADD_STUDENT'`, `37482171413056545000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// mutation-types.js</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token constant">ADD_STUDENT_MUTATION</span> <span class="token operator">=</span> <span class="token string">'ADD_STUDENT'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <div class="gatsby-code-button-container" data-toaster-id="27124951926123520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// store.js import Vuex from 'vuex' import { ADD_STUDENT_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { [ADD_STUDENT_MUTATION] (state, student) { state.students.push(student) } } })`, `27124951926123520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// store.js</span> <span class="token keyword">import</span> Vuex <span class="token keyword">from</span> <span class="token string">'vuex'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">ADD_STUDENT_MUTATION</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./mutation-types'</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vuex<span class="token punctuation">.</span>Store</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">state</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> <span class="token literal-property property">mutations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token constant">ADD_STUDENT_MUTATION</span><span class="token punctuation">]</span> <span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> student</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> state<span class="token punctuation">.</span>students<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>student<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The mutations should be synchronous. This is an important rule which you should adhere to so that <strong>Vuex</strong> can capture before and after mutation states. We will see how to have async state mutations using actions.</p> <h3 id="actions" style="position:relative;"><a href="#actions" aria-label="actions permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Actions</h3> <p>Actions are very similar to mutations, but there are two differences between the two. The first one is that instead of mutating the state themselves, they will commit mutations. And the second one is that actions can have asynchronous operations.</p> <div class="gatsby-code-button-container" data-toaster-id="87268123306568940000" data-toaster-class="gatsby-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 store = new Vuex.Store({ state: { students: [ { id: 1, name: 'Yas', age: 26 } ] }, mutations: { addStudent (state, student) { // mutate state state.students.push(student) } }, actions: { addStudent (context, id) { const student = await apiService.get(id) context.commit('addStudent', student) } } })`, `87268123306568940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vuex<span class="token punctuation">.</span>Store</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">state</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">students</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">26</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">mutations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">addStudent</span> <span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> student</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// mutate state</span> state<span class="token punctuation">.</span>students<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>student<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">actions</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">addStudent</span> <span class="token punctuation">(</span><span class="token parameter">context<span class="token punctuation">,</span> id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> student <span class="token operator">=</span> <span class="token keyword">await</span> apiService<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span> context<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token string">'addStudent'</span><span class="token punctuation">,</span> student<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The first thing to note here is that actions won’t receive the store object, they will get a context object which exposes the same properties. We will see why when we review the modules. And the second one is that there is an asynchronous operation happening here.</p> <p>You can use <a href="https://github.com/lukehoban/es6features#destructuring" target="_blank" rel="nofollow noopener noreferrer">ES6 Object Destructuring</a> to get only commit passed down to the action. This is useful if you have multiple commits in your actions because it will keep the code way less.</p> <div class="gatsby-code-button-container" data-toaster-id="90223395092655260000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`actions: { async addStudent ({ commit }, id) { const student = await apiService.get(id) commit('addStudent', student) } }`, `90223395092655260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">actions</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token function">addStudent</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> commit <span class="token punctuation">}</span><span class="token punctuation">,</span> id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> student <span class="token operator">=</span> <span class="token keyword">await</span> apiService<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token function">commit</span><span class="token punctuation">(</span><span class="token string">'addStudent'</span><span class="token punctuation">,</span> student<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can trigger an actions using <code class="language-text">store.dispatch</code> method.</p> <div class="gatsby-code-button-container" data-toaster-id="71108218121568340000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`store.dispatch('addStudents', 2)`, `71108218121568340000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">store<span class="token punctuation">.</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token string">'addStudents'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Again, similar to <code class="language-text">mapState</code> you have <code class="language-text">mapActions</code> to be able to dispatch an action in your components instead of using <code class="language-text">this.$store.dispatch</code> method which is way much cleaner. The difference is, you will call this in your method objects:</p> <div class="gatsby-code-button-container" data-toaster-id="7402339671293423000" data-toaster-class="gatsby-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 { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'addStudent', // map \`this.addStudent()\` to \`this.\$store.dispatch('addStudent')\` // \`mapActions\` also supports payloads: 'addStudent' // map \`this.addStudent(id)\` to \`this.\$store.dispatch('addStudent', id)\` ]), ...mapActions({ add: 'addStudent' // map \`this.add()\` to \`this.\$store.dispatch('addStudent')\` }) } }`, `7402339671293423000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mapActions <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vuex'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span><span class="token function">mapActions</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">'addStudent'</span><span class="token punctuation">,</span> <span class="token comment">// map `this.addStudent()` to `this.$store.dispatch('addStudent')`</span> <span class="token comment">// `mapActions` also supports payloads:</span> <span class="token string">'addStudent'</span> <span class="token comment">// map `this.addStudent(id)` to `this.$store.dispatch('addStudent', id)`</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token operator">...</span><span class="token function">mapActions</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">add</span><span class="token operator">:</span> <span class="token string">'addStudent'</span> <span class="token comment">// map `this.add()` to `this.$store.dispatch('addStudent')`</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 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</h3> <p>As we’ve seen so far, the state can easily get super big as the project grows. This can lead to multiple issues, but we can use modules to break this single state into multiple modules which have their own <code class="language-text">state</code>, <code class="language-text">getters</code>, <code class="language-text">mutations</code>, <code class="language-text">actions</code>, and guess what, sub modules 😍.</p> <div class="gatsby-code-button-container" data-toaster-id="25618003561811810000" data-toaster-class="gatsby-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 studentStore = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const teachersStore = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: studentStore, b: teachersStore } }) store.state.studentStore // -> \`studentStore\`'s state store.state.teachersStore // -> \`teachersStore\`'s state`, `25618003561811810000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> studentStore <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">state</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> <span class="token literal-property property">mutations</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> <span class="token literal-property property">actions</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> <span class="token literal-property property">getters</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> <span class="token keyword">const</span> teachersStore <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">state</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> <span class="token literal-property property">mutations</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> <span class="token literal-property property">actions</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> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vuex<span class="token punctuation">.</span>Store</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">modules</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">a</span><span class="token operator">:</span> studentStore<span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> teachersStore <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> store<span class="token punctuation">.</span>state<span class="token punctuation">.</span>studentStore <span class="token comment">// -> `studentStore`'s state</span> store<span class="token punctuation">.</span>state<span class="token punctuation">.</span>teachersStore <span class="token comment">// -> `teachersStore`'s state</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Inside the <code class="language-text">state</code> and <code class="language-text">getters</code>, the module’s state is passed down.</p> <div class="gatsby-code-button-container" data-toaster-id="67189359637119890000" data-toaster-class="gatsby-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 studentStore = { state: { students: [] }, mutations: { addStudent (state, student) { // \`state\` is the local module state state.students.push(student) } }, getters: { count (state) { return state.students.length } } }`, `67189359637119890000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> studentStore <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">state</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">students</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">mutations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">addStudent</span> <span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> student</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// `state` is the local module state</span> state<span class="token punctuation">.</span>students<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>student<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">getters</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">count</span> <span class="token punctuation">(</span><span class="token parameter">state</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> state<span class="token punctuation">.</span>students<span class="token punctuation">.</span>length <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>However, inside the actions, you can access the global store from <code class="language-text">context</code> via <code class="language-text">context.rootStore</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="87611997773118440000" data-toaster-class="gatsby-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 moduleA = { // ... actions: { async addStudentIfRegistrationOpen ({ commit, rootState }, id) { if (rootState.registrationOpen) { const student = await apiService.get(id) commit('addStudent', student) } } } }`, `87611997773118440000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> moduleA <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token literal-property property">actions</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token function">addStudentIfRegistrationOpen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> commit<span class="token punctuation">,</span> rootState <span class="token punctuation">}</span><span class="token punctuation">,</span> id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>rootState<span class="token punctuation">.</span>registrationOpen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> student <span class="token operator">=</span> <span class="token keyword">await</span> apiService<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token function">commit</span><span class="token punctuation">(</span><span class="token string">'addStudent'</span><span class="token punctuation">,</span> student<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <blockquote> <p>💡 By default the <code class="language-text">getters</code>, <code class="language-text">mutations</code>, and <code class="language-text">actions</code> are registered on the global namespace. This will allow multiple modules to react to same mutation or action if they want to. You can use the <code class="language-text">namespaced: true</code> flag on the module to make it self contained.</p> </blockquote> <p>You can find out more about the modules in the <a href="https://vuex.vuejs.org/guide/modules.html" target="_blank" rel="nofollow noopener noreferrer">official documentation</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>Alrighty, you now know enough about state management in <strong>Vue</strong> using <strong>Vuex</strong> to start using it. But beware that there are many other little tips and tricks where I thought would fall outside of a single article which you should look into. For now enjoy playing with this amazing library and get your hands wet.</p> <p>PS: if you want a head start, use <a href="https://github.com/utahta/vue-vuex-typescript-sandbox" target="_blank" rel="nofollow noopener noreferrer">this GitHub repository</a> and create a code sandbox out of it. It contains basic setup and modules as well.</p><![CDATA[Network Information API, another step towards a better web 😍]]>https://yashints.dev/blog/2019/11/18/network-info-apihttps://yashints.dev/blog/2019/11/18/network-info-apiMon, 18 Nov 2019 00:00:00 GMT<p>This year has been full of articles around how the web is bloated with static assets and how this has impacted users to face a poor user experience when using not so good networks around the world. There are resources like <a href="https://web.dev/" target="_blank" rel="nofollow noopener noreferrer">web.dev</a> who are actively publishing content on how to make a better future for the web.</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’ve also published a few 😁 on how to improve web performance which you should totally check them out 👇🏼:</p> <ul> <li><a href="https://yashints.dev/blog/2018/09/29/web-perf-1" target="_blank" rel="nofollow noopener noreferrer">HTML and CSS</a></li> <li><a href="https://yashints.dev/blog/2018/10/06/web-perf-2" target="_blank" rel="nofollow noopener noreferrer">Preload/Prefetch to boost load time</a></li> <li><a href="https://yashints.dev/blog/2018/10/12/web-perf-3" target="_blank" rel="nofollow noopener noreferrer">JavaScript performance improvements</a></li> <li><a href="https://yashints.dev/blog/2018/11/12/web-perf-4" target="_blank" rel="nofollow noopener noreferrer">Image optimisations</a></li> <li><a href="https://yashints.dev/blog/2018/11/23/web-perf-5" target="_blank" rel="nofollow noopener noreferrer">Web font optimisations</a></li> </ul> <p>And other <a href="https://yashints.dev/blog/2019/05/11/offscreen-canvas" target="_blank" rel="nofollow noopener noreferrer">tips and tricks like how to use the <code class="language-text">OffscreenCanvas</code> to render your graphics off the main thread</a>.</p> <p>This article is around the same topic, but we’re gonna see how to inspect and react to connection aspects of a visiting user to deliver a better experience to them.</p> <p>There are some implementations of this in the wild such as BBC News showing a warning to users about being charged by operators if they’re on a cellular network:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 277px; " > <a class="gatsby-resp-image-link" href="/static/4ef71c4967a8a4629c2596863b261456/2a985/web_bbc_cellular.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 68.51851851851852%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAAsTAAALEwEAmpwYAAABvklEQVR42qWSR44iURBE61Ys8AhfwOBNYwSCDU5YAd14boMACVYIu2LLHWCOgNjPvKoaGNRoVhOL1P+RGZFZ+Uv49R8QTqdTs9n8euBTRrvdJirXJ6mcQa/Xa7Va5/NZmE6narU6Ho97PB632x0IBPx+fzKZJHq93mAwCA8ZCoWInH/IUKlU6/VamM/noihOJhMs8aNnt9sdjUbD4RCm0+kwFz0HgwE8WfhSqWQwGPb7vTCbzVwuF3X9fr9er5fLZWKhUECGV7VardVqxWKx0WhwxqhSqTAU4t1u90cMS1rxpghlPp/ngBFirspEDJjJZOx2u8lk2m63kpixmeq5KgRMQWnngfF4nMvl0ul0NpulLc2MRqMkXiwWZrM5kUikUqkPGZFIhAgTi8VYJDz7Y1sWi8VqtTqdTvb6V6zVah0Oh5IDNpvN+gKFZ1RRBmKiXq+XxKvVCmU4HA7+A+8pGCyOx6MkxlV5xm/wy+C1v/EU0+9wOEjvrNFocLI/wJA+n4/9szxei1fgI/mWZwHFOp1us9kIy+WSr1I6PIEY+4iMaDTK9TVLMQ2kn+R2u10ul59vuF6vlwfes5D3+/03EG2QmWe4x4QAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="BBC News warning users they might get charged by they network operator" title="" src="/static/4ef71c4967a8a4629c2596863b261456/2a985/web_bbc_cellular.png" srcset="/static/4ef71c4967a8a4629c2596863b261456/01bf6/web_bbc_cellular.png 270w, /static/4ef71c4967a8a4629c2596863b261456/2a985/web_bbc_cellular.png 277w" sizes="(max-width: 277px) 100vw, 277px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Or GMail showing a ‘load basic HTML (for slow connections)’ message:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 371px; " > <a class="gatsby-resp-image-link" href="/static/01f2130c77e4bb7385cf3a975b80829b/d4635/web_gmail.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 25.925925925925924%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsTAAALEwEAmpwYAAABK0lEQVR42o2PQU7CYBCFe0YMC7yBLPEAeAB0CUs3LF2IC0OBVJYmjShEhRZaQKEt1BaFtgSwfv6tF3CSlzdvZvIyTwrCkMMh4nsfYM9NJuaA4cig2+3Rbt+hKAqNhkytdkO1WqVer6ezVquFLMuoqkoURSlC4SWFQUBP81DubSqXTS4qt1xdNymXyxSLZxQKp+Ryx2QyRwIZstlsyvmTvNgVKJ2X8DwP3/cJhJe03Ubokw3qy5pnc8freM/XZgc/Mf+pOI5TowTJl5JjW+iaxvvUSOMawwGmYaKJmaY5InpA50Gk6AnuhDw9+hijEf2+jq7rDLRhepvo5XKJ5HkfzGYW87mT8kzwcuHi2DaW9Ylphn8Yh2IfMX1b47outu2wWCxwnKS3U71arfgF3D9c1miK0ckAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="GMail showing load basic HTML view for slow connections" title="" src="/static/01f2130c77e4bb7385cf3a975b80829b/d4635/web_gmail.png" srcset="/static/01f2130c77e4bb7385cf3a975b80829b/01bf6/web_gmail.png 270w, /static/01f2130c77e4bb7385cf3a975b80829b/d4635/web_gmail.png 371w" sizes="(max-width: 371px) 100vw, 371px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="network-information-api" style="position:relative;"><a href="#network-information-api" aria-label="network information 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>Network Information API</h2> <p>So far we have tried to improve the user experience by following one of the aforementioned techniques for everybody regardless of what network they are using. But what if we had a mean to inspect and detect their network connection properties and speed change while they’re browsing our applications.</p> <p>That’s when the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API" target="_blank" rel="nofollow noopener noreferrer">Network Information API</a> comes into play. This API provides information about the connection such as type (i.e. WiFi or Cellular, you could see the full list 👇🏼):</p> <div class="gatsby-code-button-container" data-toaster-id="14453914711934001000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`enum ConnectionType { &quot;bluetooth&quot;, &quot;cellular&quot;, &quot;ethernet&quot;, &quot;mixed&quot;, &quot;none&quot;, &quot;other&quot;, &quot;unknown&quot;, &quot;wifi&quot;, &quot;wimax&quot; };`, `14453914711934001000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">enum</span> ConnectionType <span class="token punctuation">{</span> <span class="token string">"bluetooth"</span><span class="token punctuation">,</span> <span class="token string">"cellular"</span><span class="token punctuation">,</span> <span class="token string">"ethernet"</span><span class="token punctuation">,</span> <span class="token string">"mixed"</span><span class="token punctuation">,</span> <span class="token string">"none"</span><span class="token punctuation">,</span> <span class="token string">"other"</span><span class="token punctuation">,</span> <span class="token string">"unknown"</span><span class="token punctuation">,</span> <span class="token string">"wifi"</span><span class="token punctuation">,</span> <span class="token string">"wimax"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Here is how to access this information:</p> <div class="gatsby-code-button-container" data-toaster-id="57734121912118130000" data-toaster-class="gatsby-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 connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;`, `57734121912118130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> connection <span class="token operator">=</span> navigator<span class="token punctuation">.</span>connection <span class="token operator">||</span> navigator<span class="token punctuation">.</span>mozConnection <span class="token operator">||</span> navigator<span class="token punctuation">.</span>webkitConnection<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Here is how the object you’ll get looks like:</p> <p><img src="/e4821b2148d757f6c7e5992e16e934f8/NetworkInformationObject.jpg" alt="Network Information object"></p> <h2 id="networkinformation-object" style="position:relative;"><a href="#networkinformation-object" aria-label="networkinformation 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>NetworkInformation object</h2> <p>So let’s see what are these properties one by one:</p> <h3 id="code-classlanguage-texteffectivetypecode" style="position:relative;"><a href="#code-classlanguage-texteffectivetypecode" aria-label="code classlanguage texteffectivetypecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">effectiveType</code></h3> <p>This property is showing the effective connection type. This is a bit different to the connection type we mentioned earlier. It changes based on a combination of recently observed <code class="language-text">ttl</code> and <code class="language-text">downlink</code>.</p> <p>The possible values for <code class="language-text">effectiveType</code> is an enum with these values:</p> <div class="gatsby-code-button-container" data-toaster-id="60150482467774100000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`enum EffectiveConnectionType { &quot;2g&quot;, &quot;3g&quot;, &quot;4g&quot;, &quot;slow-2g&quot; };`, `60150482467774100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">enum</span> EffectiveConnectionType <span class="token punctuation">{</span> <span class="token string">"2g"</span><span class="token punctuation">,</span> <span class="token string">"3g"</span><span class="token punctuation">,</span> <span class="token string">"4g"</span><span class="token punctuation">,</span> <span class="token string">"slow-2g"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In reality if this property has <code class="language-text">slow-2g</code> it means you should avoid sending images, videos, etc. It’s suitable for sending text only content. If the value is <code class="language-text">2g</code> it indicates that you could potentially send small low res images to user.</p> <p><code class="language-text">3g</code> means you can send larger assets such as high res images, SD videos, and audio. At last <code class="language-text">4g</code> means the network is suited for HD video, streaming and other data heavy resources.</p> <h3 id="code-classlanguage-textdownlinkcode" style="position:relative;"><a href="#code-classlanguage-textdownlinkcode" aria-label="code classlanguage textdownlinkcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">downlink</code></h3> <p>This shows the download speed of the connection. The unit uses is megabits per second.</p> <h3 id="code-classlanguage-textonchangecode" style="position:relative;"><a href="#code-classlanguage-textonchangecode" aria-label="code classlanguage textonchangecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">onchange</code></h3> <p>This property allows you to set an event handler for the <code class="language-text">change</code> event on <code class="language-text">NetworkInformation</code> object.</p> <h3 id="code-classlanguage-textrttcode" style="position:relative;"><a href="#code-classlanguage-textrttcode" aria-label="code classlanguage textrttcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">rtt</code></h3> <p>This attribute represents the round trip time estimate in milliseconds nearest to 25 milliseconds and is based on application layer RTT measurements.</p> <h3 id="code-classlanguage-textsavedatacode" style="position:relative;"><a href="#code-classlanguage-textsavedatacode" aria-label="code classlanguage textsavedatacode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">saveData</code></h3> <p>This property when getting returns <code class="language-text">true</code> if the user has requested to reduce data usage mode from the user agent. Otherwise it returns <code class="language-text">false</code>.</p> <p>If you are wondering what happened to <code class="language-text">type</code> property, it is not currently supported by the browsers and no one knows if that will be because the spec is in a draft mode and might get changed. You can find more information on the browser support page at the end of this article.</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="prevent-from-preloading-videos" style="position:relative;"><a href="#prevent-from-preloading-videos" aria-label="prevent from preloading videos permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prevent from preloading videos</h3> <p>Now that we know what to expect from this API, lets see what we can do with it. Imagine we’re preloading videos in our page. We can hook up to the <code class="language-text">change</code> event and stop preloading if the user is on a slower network:</p> <div class="gatsby-code-button-container" data-toaster-id="29837599691155760000" data-toaster-class="gatsby-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 preloadVideo = true; const slowConnections = ['2g', '2g-slow']; var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; let type = connection.effectiveType; function updateVideoPreloadingStrategy() { console.log(&quot;Connection type changed from &quot; + type + &quot; to &quot; + connection.effectiveType); type = connection.effectiveType; if (slowConnections.containes(type)) { preloadVideo = false; } } connection.addEventListener('change', updateVideoPreloadingStrategy);`, `29837599691155760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> preloadVideo <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token keyword">const</span> slowConnections <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'2g'</span><span class="token punctuation">,</span> <span class="token string">'2g-slow'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">var</span> connection <span class="token operator">=</span> navigator<span class="token punctuation">.</span>connection <span class="token operator">||</span> navigator<span class="token punctuation">.</span>mozConnection <span class="token operator">||</span> navigator<span class="token punctuation">.</span>webkitConnection<span class="token punctuation">;</span> <span class="token keyword">let</span> type <span class="token operator">=</span> connection<span class="token punctuation">.</span>effectiveType<span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">updateVideoPreloadingStrategy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Connection type changed from "</span> <span class="token operator">+</span> type <span class="token operator">+</span> <span class="token string">" to "</span> <span class="token operator">+</span> connection<span class="token punctuation">.</span>effectiveType<span class="token punctuation">)</span><span class="token punctuation">;</span> type <span class="token operator">=</span> connection<span class="token punctuation">.</span>effectiveType<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>slowConnections<span class="token punctuation">.</span><span class="token function">containes</span><span class="token punctuation">(</span>type<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> preloadVideo <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> connection<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> updateVideoPreloadingStrategy<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="load-low-res-images" style="position:relative;"><a href="#load-low-res-images" aria-label="load low res images permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Load low res images</h3> <p>You could potentially set a class to your elements and based on that load a different image:</p> <div class="gatsby-code-button-container" data-toaster-id="65444188662431840000" data-toaster-class="gatsby-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 updateImageLoadingStrategy() { console.log(&quot;Connection type changed from &quot; + type + &quot; to &quot; + connection.effectiveType); type = connection.effectiveType; const myEl = document.querySelector('#id'); if (slowConnections.containes(type)) { myEl.classList.add(&quot;low-res&quot;); } else { myEl.classList.remove(&quot;low-res&quot;); } }`, `65444188662431840000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">updateImageLoadingStrategy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Connection type changed from "</span> <span class="token operator">+</span> type <span class="token operator">+</span> <span class="token string">" to "</span> <span class="token operator">+</span> connection<span class="token punctuation">.</span>effectiveType<span class="token punctuation">)</span><span class="token punctuation">;</span> type <span class="token operator">=</span> connection<span class="token punctuation">.</span>effectiveType<span class="token punctuation">;</span> <span class="token keyword">const</span> myEl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>slowConnections<span class="token punctuation">.</span><span class="token function">containes</span><span class="token punctuation">(</span>type<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myEl<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"low-res"</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> myEl<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"low-res"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="77032104639140900" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`#id { background: url(high-res.jpg) 0 0 no-repeat; } #id.low-res { background: url(low-res.jpg) 0 0 no-repeat; }`, `77032104639140900`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">#id</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span>high-res.jpg<span class="token punctuation">)</span></span> 0 0 no-repeat<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">#id.low-res</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span>low-res.jpg<span class="token punctuation">)</span></span> 0 0 no-repeat<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw how useful can <strong>Network Information API</strong> be in most of our use cases where we want to address performance issue or even deliver a better user experience. Some other applicable use cases are:</p> <ul> <li>Not load high res images</li> <li>Prevent loading web fonts</li> <li>HTTP calls are changed to fetch less data using summary instead of full page load</li> <li>Timeout values for HTTP calls are increased</li> <li>Showing warning and other informative messages to users to let them know they might get charged</li> </ul> <blockquote> <p>💡 This API is in a <strong>draft</strong> state and might change in the future. But it doesn’t hurt to be proactive and update the implementation later rather than waiting for the full spec.</p> </blockquote> <p>You can find more about this on <a href="https://wicg.github.io/netinfo/" target="_blank" rel="nofollow noopener noreferrer">the specification</a>.</p> <h2 id="browser-support" style="position:relative;"><a href="#browser-support" aria-label="browser support permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Browser support</h2> <p>So Network Information API is good and everything, but how about the browser support. Currently it is supported in Chrome and MS Edge only.</p> <p>You can see <a href="https://caniuse.com/#feat=netinfo" target="_blank" rel="nofollow noopener noreferrer">the full list here</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/3132da2caceacc942c5104290a181b4a/e4894/caniusenetinfo.jpg" style="display: block" target="_blank" rel="noopener" > <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/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAAB1LAUiz//xAAXEAADAQAAAAAAAAAAAAAAAAAAARIC/9oACAEBAAEFAp0SyWf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAEBAQEAAAAAAAAAAAAAAAAAMjGh/9oACAEBAAY/Ar4pr//EABoQAAICAwAAAAAAAAAAAAAAAAABESExgeH/2gAIAQEAAT8huBZ3LQkcn//aAAwDAQACAAMAAAAQg/8A/8QAFREBAQAAAAAAAAAAAAAAAAAAEQD/2gAIAQMBAT8QWb//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPxACf//EABkQAQEBAQEBAAAAAAAAAAAAAAERACFR4f/aAAgBAQABPxB5FTwBjNKSJM1blre/e//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Browser support" title="" src="/static/3132da2caceacc942c5104290a181b4a/47311/caniusenetinfo.jpg" srcset="/static/3132da2caceacc942c5104290a181b4a/6f81f/caniusenetinfo.jpg 270w, /static/3132da2caceacc942c5104290a181b4a/09d21/caniusenetinfo.jpg 540w, /static/3132da2caceacc942c5104290a181b4a/47311/caniusenetinfo.jpg 1080w, /static/3132da2caceacc942c5104290a181b4a/e4894/caniusenetinfo.jpg 1513w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Now go have fun with this API and save your users some money 😁.</p><![CDATA[Handling forms with Vue.js 🧾]]>https://yashints.dev/blog/2019/11/10/vue-form-handlinghttps://yashints.dev/blog/2019/11/10/vue-form-handlingSun, 10 Nov 2019 00:00:00 GMT<p><a href="https://vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue.js</a> is an approachable, versatile, performant, and progressive framework to build user interfaces with. I’ve written two separate articles on it so far:</p> <ul> <li><a href="https://yashints.dev/blog/2019/10/18/vue-intro" target="_blank" rel="nofollow noopener noreferrer">A comprehensive intro to Vue.js</a></li> <li><a href="https://yashints.dev/blog/2019/10/30/vue-router" target="_blank" rel="nofollow noopener noreferrer">Deliver a better user experience using Vue Router</a></li> </ul> <p>This time we will have a look at handling form with <strong>Vue.js</strong>, something which is almost inevitable in enterprise applications.</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>When it comes to working with forms, it’s always good to know the in and out of how to handle them in your choice of framework. Of course there are some common knowledge around forms, but dealing with one can be tough at times especially if you care about the user experience.</p> <h2 id="scenario" style="position:relative;"><a href="#scenario" aria-label="scenario permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Scenario</h2> <p>Assume we have a sign up form for new users on our product. We want to build this sign up form, from scratch, and step by step together.</p> <h2 id="start" style="position:relative;"><a href="#start" aria-label="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>Start</h2> <p>Let’s start a new application and create a component first:</p> <div class="gatsby-code-button-container" data-toaster-id="79747942157771570000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE html> <html> <head> <title>Handling Forms with Vue.js</title> <link rel=&quot;stylesheet&quot; href=&quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&quot; integrity=&quot;sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T&quot; crossorigin=&quot;anonymous&quot;> </head> <body> <div class=&quot;container&quot; id=&quot;app&quot;> <div class=&quot;&quot;> <section class=&quot;mt-md&quot;> <h1 class=&quot;title&quot;>Form handling with Vue.js</h1> <p class=&quot;text-muted&quot;> Learn how to work with forms, including <strong>validation</strong>! </p> <hr> <section class=&quot;form&quot;> <!--Our form will be here--> </section> </section> </div> </div> <script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;></script> <script> new Vue({ el: '#app' }) </script> </body> </html>`, `79747942157771570000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Handling Forms with Vue.js<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></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://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<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>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</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>container<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>app<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><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>section</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-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>h1</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>title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Form handling with Vue.js<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Learn how to work with forms, including <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>strong</span><span class="token punctuation">></span></span>validation<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</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>hr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</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>form<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token comment">&lt;!--Our form will be here--></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</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>script</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://cdn.jsdelivr.net/npm/vue/dist/vue.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#app'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="text-inputs" style="position:relative;"><a href="#text-inputs" aria-label="text inputs permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Text inputs</h2> <p>As I mentioned in my intro, you can bind form input values to <strong>Vue</strong>’s data object using <code class="language-text">v-model</code>. So let’s add a few text inputs for name and last name.</p> <div class="gatsby-code-button-container" data-toaster-id="25738944793204023000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<form> <div class=&quot;form-group&quot;> <label for=&quot;firstName&quot;>First name</label> <input type=&quot;text&quot; v-model=&quot;form.firstName&quot; class=&quot;form-control&quot; id=&quot;firstName&quot; placeholder=&quot;Enter your name&quot;> </div> <div class=&quot;form-group&quot;> <label for=&quot;lastName&quot;>Last name</label> <input type=&quot;text&quot; v-model=&quot;form.lastName&quot; class=&quot;form-control&quot; id=&quot;lastName&quot; placeholder=&quot;Enter your last name&quot;> </div> </form>`, `25738944793204023000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>firstName<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>First name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.firstName<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>form-control<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>firstName<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Enter your name<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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lastName<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.lastName<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>form-control<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>lastName<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Enter your last name<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>form</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In the code snippet we just defined, we’re using two text inputs and binding them to first name and last name of the form property in the data object. The <code class="language-text">v-model</code> creates a two way binding between our input and its corresponding property. To be sure that we’ve got everything right, you can use the code snippet below and see the values as you’re typing:</p> <div class="gatsby-code-button-container" data-toaster-id="39799045404868120000" data-toaster-class="gatsby-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;shadow&quot;> <div v-for=&quot;(item, k) in form&quot;> <strong>{{ deCamelCase(k) }}</strong> {{item}} </div> </div>`, `39799045404868120000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>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>div</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>(item, k) in form<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>strong</span><span class="token punctuation">></span></span>{{ deCamelCase(k) }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</span><span class="token punctuation">></span></span> {{item}} <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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And in your JavaScript code:</p> <div class="gatsby-code-button-container" data-toaster-id="15705037684997714000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// the rest <script> new Vue({ el: '#app', data: { form: { firstName: '', lastName: '' } }, methods: { deCamelCase: function(str) { const result = str.replace(/([A-Z]+)/g, &quot; \$1&quot;); return result.charAt(0).toUpperCase() + result.slice(1) + ':' } } }) </script>`, `15705037684997714000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// the rest</span> <span class="token operator">&lt;</span>script<span class="token operator">></span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#app'</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</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 literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">deCamelCase</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">str</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> result <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">([A-Z]+)</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">" $1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> result<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</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 operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you start typing into any of those text boxes, you should see the result in the bottom <code class="language-text">div</code>.</p> <h2 id="setting-default-value" style="position:relative;"><a href="#setting-default-value" aria-label="setting default 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>Setting default value</h2> <p><strong>Vue</strong> will ignore the <code class="language-text">value</code>, <code class="language-text">checked</code>, or <code class="language-text">selected</code> attributes of the inputs you use and uses the data object as source of truth. This means you can set default values for your form fields:</p> <div class="gatsby-code-button-container" data-toaster-id="54387054169996410000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`data: { form: { firstName: 'Yas', lastName: '' } }`, `54387054169996410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token string">''</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can see the value of the input get set to <code class="language-text">Yas</code> when the page renders.</p> <h2 id="textarea" style="position:relative;"><a href="#textarea" aria-label="textarea permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Textarea</h2> <p>Adding a <code class="language-text">textarea</code> is exactly like adding a normal text input:</p> <div class="gatsby-code-button-container" data-toaster-id="67053556845169830000" data-toaster-class="gatsby-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;form-group&quot;> <label for=&quot;notes&quot;>Additional information</label> <textarea v-model=&quot;form.additionalInfo&quot; class=&quot;form-control&quot; id=&quot;notes&quot; rows=&quot;3&quot;></textarea> </div>`, `67053556845169830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>notes<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Additional information<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.additionalInfo<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>form-control<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>notes<span class="token punctuation">"</span></span> <span class="token attr-name">rows</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>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>textarea</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Don’t forget to add the <code class="language-text">additionalInfo</code> to your data object.</p> <h2 id="select-element" style="position:relative;"><a href="#select-element" aria-label="select 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>Select element</h2> <p>Adding</p> <div class="gatsby-code-button-container" data-toaster-id="87509092715984930000" data-toaster-class="gatsby-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;form-group&quot;> <label for=&quot;ageGroup&quot;>Select your age group</label> <select v-model=&quot;form.ageGroup&quot; class=&quot;form-control&quot; id=&quot;ageGroup&quot;> <option value=&quot;1&quot;>18-22</option> <option value=&quot;2&quot;>22-25</option> <option value=&quot;3&quot;>25-27</option> <option value=&quot;4&quot;>27-30</option> <option value=&quot;5&quot;>30-33</option> </select> </div>`, `87509092715984930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ageGroup<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Select your age group<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.ageGroup<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>form-control<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>ageGroup<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>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>18-22<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</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 punctuation">></span></span>22-25<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>25-27<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>27-30<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>30-33<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And in your data object:</p> <div class="gatsby-code-button-container" data-toaster-id="32789146987260030000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`form: { firstName: 'Yas', lastName: '', additionalInfo: '', ageGroup: '' }`, `32789146987260030000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">additionalInfo</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">ageGroup</span><span class="token operator">:</span> <span class="token string">''</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you want to add <code class="language-text">multiselect</code> to your element, all you need to do is to add the attribute and change the type of the <code class="language-text">ageGroup</code> property from string to array. If you want a default selection, simply set the value of the <code class="language-text">ageGroup</code> in the data object and <strong>Vue</strong> will take of the rest.</p> <p>If you want to populate the options dynamically, simply use a <code class="language-text">v-for</code> directive:</p> <div class="gatsby-code-button-container" data-toaster-id="92618448975513620000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<option v-for=&quot;option in options&quot; v-bind:value=&quot;option.value&quot;> {{ option.text }} </option>`, `92618448975513620000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>option in options<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">v-bind:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>option.value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{ option.text }} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="checkbox--radio-buttons" style="position:relative;"><a href="#checkbox--radio-buttons" aria-label="checkbox radio buttons permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checkbox &#x26; Radio buttons</h2> <p>A single checkbox is very straightforward to use, the value of it will be a <code class="language-text">boolean</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="11175783093251246000" data-toaster-class="gatsby-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;card&quot;> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Terms and Conditions</h5> <h6 class=&quot;card-subtitle mb-2 text-muted&quot;>Read and agree</h6> <p class=&quot;card-text&quot;>Doggo ipsum clouds what a nice floof long water shoob doggo extremely cuuuuuute, heckin good boys long water shoob.</p> <div class=&quot;form-check&quot;> <input class=&quot;form-check-input&quot; type=&quot;checkbox&quot; v-model=&quot;form.agreeToTsCs&quot; value=&quot;&quot; id=&quot;termsAndConditions&quot;> <label class=&quot;form-check-label&quot; for=&quot;termsAndConditions&quot;> Agree with terms and conditions </label> </div> </div> </div>`, `11175783093251246000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>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>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>Terms and Conditions<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>h6</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-subtitle mb-2 text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Read and agree<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h6</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>Doggo ipsum clouds what a nice floof long water shoob doggo extremely cuuuuuute, heckin good boys long water shoob.<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>form-check<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>input</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>form-check-input<span class="token punctuation">"</span></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>checkbox<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.agreeToTsCs<span class="token punctuation">"</span></span> <span class="token attr-name">value</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termsAndConditions<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>label</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>form-check-label<span class="token punctuation">"</span></span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termsAndConditions<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Agree with terms and conditions <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And don’t forget to add the property:</p> <div class="gatsby-code-button-container" data-toaster-id="48220402513019890000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`form: { firstName: 'Yas', lastName: '', additionalInfo: '', ageGroup: '', agreeToTsCs: false }`, `48220402513019890000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">additionalInfo</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">ageGroup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">agreeToTsCs</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For multiple checkboxes, they all use the same property, but the type would be array.</p> <p>A single radio button by itself is normally useless, so you’d want to use a radio button group. The value of the property would be the value of the selected radio input:</p> <div class="gatsby-code-button-container" data-toaster-id="27342356837964110000" data-toaster-class="gatsby-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;form-check&quot;> <input class=&quot;form-check-input&quot; type=&quot;radio&quot; name=&quot;termSelection&quot; v-model=&quot;form.enrollingTerm&quot; id=&quot;termSelection1&quot; value=&quot;1&quot;> <label class=&quot;form-check-label&quot; for=&quot;termSelection1&quot;> Term 1 </label> </div> <div class=&quot;form-check&quot;> <input class=&quot;form-check-input&quot; type=&quot;radio&quot; name=&quot;termSelection&quot; v-model=&quot;form.enrollingTerm&quot; id=&quot;termSelection2&quot; value=&quot;2&quot;> <label class=&quot;form-check-label&quot; for=&quot;termSelection2&quot;> Term 2 </label> </div> <div class=&quot;form-check&quot;> <input class=&quot;form-check-input&quot; type=&quot;radio&quot; name=&quot;termSelection&quot; v-model=&quot;form.enrollingTerm&quot; id=&quot;termSelection3&quot; value=&quot;3&quot;> <label class=&quot;form-check-label&quot; for=&quot;termSelection3&quot;> Term 3 </label> </div>`, `27342356837964110000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>form-check<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>input</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>form-check-input<span class="token punctuation">"</span></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>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termSelection<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.enrollingTerm<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>termSelection1<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<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>label</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>form-check-label<span class="token punctuation">"</span></span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termSelection1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Term 1 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</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>form-check<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>input</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>form-check-input<span class="token punctuation">"</span></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>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termSelection<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.enrollingTerm<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>termSelection2<span class="token punctuation">"</span></span> <span class="token attr-name">value</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 punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</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>form-check-label<span class="token punctuation">"</span></span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termSelection2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Term 2 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</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>form-check<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>input</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>form-check-input<span class="token punctuation">"</span></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>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termSelection<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.enrollingTerm<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>termSelection3<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>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>label</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>form-check-label<span class="token punctuation">"</span></span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>termSelection3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Term 3 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And add the property:</p> <div class="gatsby-code-button-container" data-toaster-id="55569287427229155000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`form: { firstName: 'Yas', lastName: '', additionalInfo: '', ageGroup: '1', agreeToTsCs: false, enrollingTerm: '' }`, `55569287427229155000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">additionalInfo</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">ageGroup</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span> <span class="token literal-property property">agreeToTsCs</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">enrollingTerm</span><span class="token operator">:</span> <span class="token string">''</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="modifiers" style="position:relative;"><a href="#modifiers" aria-label="modifiers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Modifiers</h2> <p>There are a few modifiers which will be helpful for different scenarios and are provided out of the box. Let’s review them one by one:</p> <h3 id="lazy" style="position:relative;"><a href="#lazy" aria-label="lazy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>.lazy</h3> <p>By default <code class="language-text">v-model</code> will update the value of the input with your property on every <code class="language-text">input</code> event. If you don’t want that to happen, you can add <code class="language-text">.lazy</code> and it will happen after <code class="language-text">change</code> event:</p> <div class="gatsby-code-button-container" data-toaster-id="94045236497172380000" data-toaster-class="gatsby-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;form-group&quot;> <label for=&quot;lazilyUpdated&quot;>This input will update after <code>change</code> event</label> <input type=&quot;text&quot; class=&quot;form-control&quot; v-model.lazy=&quot;form.lazilyUpdated&quot; id=&quot;lazilyUpdated&quot; placeholder=&quot;&quot;> </div>`, `94045236497172380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lazilyUpdated<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>This input will update after <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>code</span><span class="token punctuation">></span></span>change<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>code</span><span class="token punctuation">></span></span> event<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<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>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">v-model.lazy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.lazilyUpdated<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>lazilyUpdated<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>If you start typing on this text box, it will not get updated until you move away (blur happens).</p> <h3 id="number" style="position:relative;"><a href="#number" aria-label="number permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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</h3> <p>This one will cast the value to be always a number:</p> <div class="gatsby-code-button-container" data-toaster-id="3410213730656508400" data-toaster-class="gatsby-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;form-group&quot;> <label for=&quot;alwaysNumber&quot;>This property will always be number</code> event</label> <input type=&quot;number&quot; class=&quot;form-control&quot; v-model.number=&quot;form.alwaysNumber&quot; id=&quot;alwaysNumber&quot; placeholder=&quot;&quot;> </div>`, `3410213730656508400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alwaysNumber<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>This property will always be number<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>code</span><span class="token punctuation">></span></span> event<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>number<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>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">v-model.number</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.alwaysNumber<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>alwaysNumber<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>For the property you can use:</p> <div class="gatsby-code-button-container" data-toaster-id="72834351754740200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`form: { firstName: 'Yas', lastName: '', additionalInfo: '', ageGroup: '1', agreeToTsCs: false, enrollingTerm: '', lazilyUpdated: '', alwaysNumber: null }`, `72834351754740200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">additionalInfo</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">ageGroup</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span> <span class="token literal-property property">agreeToTsCs</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">enrollingTerm</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">lazilyUpdated</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">alwaysNumber</span><span class="token operator">:</span> <span class="token keyword">null</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And just to make sure it works, you can add this to your value area:</p> <div class="gatsby-code-button-container" data-toaster-id="77823715934306240000" data-toaster-class="gatsby-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>{{ typeof(form.alwaysNumber) }}</div>`, `77823715934306240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span>{{ typeof(form.alwaysNumber) }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This is useful because <code class="language-text">input type=number</code> will give you a string value and you have to use <code class="language-text">parseInt</code> or <code class="language-text">parseFloat</code> to get the correct type.</p> <h3 id="trim" style="position:relative;"><a href="#trim" aria-label="trim permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>.trim</h3> <p>This one is very obvious, it scrapes the whitespace from typed text:</p> <div class="gatsby-code-button-container" data-toaster-id="11442475021790855000" data-toaster-class="gatsby-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;form-group&quot;> <label for=&quot;alwaysTrimmed&quot;>Trimmed text</code> event</label> <input type=&quot;text&quot; class=&quot;form-control&quot; v-model.number=&quot;form.alwaysTrimmed&quot; id=&quot;alwaysTrimmed&quot; placeholder=&quot;&quot;> </div>`, `11442475021790855000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alwaysTrimmed<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Trimmed text<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>code</span><span class="token punctuation">></span></span> event<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<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>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">v-model.number</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.alwaysTrimmed<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>alwaysTrimmed<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="19878338676681118000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`form: { firstName: 'Yas', lastName: '', additionalInfo: '', ageGroup: '1', agreeToTsCs: false, enrollingTerm: '', lazilyUpdated: '', alwaysNumber: null, alwaysTrimmed: '' }`, `19878338676681118000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">additionalInfo</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">ageGroup</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span> <span class="token literal-property property">agreeToTsCs</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">enrollingTerm</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">lazilyUpdated</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">alwaysNumber</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token literal-property property">alwaysTrimmed</span><span class="token operator">:</span> <span class="token string">''</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now copy paste this string into the input and watch what happens 👉🏼 <code class="language-text"> test test</code>.</p> <h2 id="validation" style="position:relative;"><a href="#validation" aria-label="validation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Validation</h2> <p>You wouldn’t want to send data invalidated to your server, right? Form validation is a key to handling any form data entered by users. In its simplest form, you could implement all your validation rules in a method and check them as the user continues or even before submitting.</p> <p>However, we all know how much boiler plate code you have to write for that. So the most logical option is to find out what are our options out there. The open source community is very active and for most of what you need, there is already a matured library for it. We will review the most popular choice here, <a href="https://github.com/vuelidate/vuelidate" target="_blank" rel="nofollow noopener noreferrer">vuelidate</a>.</p> <p>First you will need to install it:</p> <div class="gatsby-code-button-container" data-toaster-id="38941673007730280000" data-toaster-class="gatsby-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 vuelidate --save`, `38941673007730280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> vuelidate <span class="token parameter variable">--save</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>If you want to have validation enabled globally, you just need to import the library and use a plugin:</p> <div class="gatsby-code-button-container" data-toaster-id="91124423969587940000" data-toaster-class="gatsby-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 Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate)`, `91124423969587940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> Vue <span class="token keyword">from</span> <span class="token string">'vue'</span> <span class="token keyword">import</span> Vuelidate <span class="token keyword">from</span> <span class="token string">'vuelidate'</span> Vue<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>Vuelidate<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>If you just want this on a single component, you could import a mixin directly:</p> <div class="gatsby-code-button-container" data-toaster-id="31756363610475870000" data-toaster-class="gatsby-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 { validationMixin } from 'vuelidate' var Component = Vue.extend({ mixins: [validationMixin], validations: { ... } })`, `31756363610475870000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> validationMixin <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vuelidate'</span> <span class="token keyword">var</span> Component <span class="token operator">=</span> Vue<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mixins</span><span class="token operator">:</span> <span class="token punctuation">[</span>validationMixin<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">validations</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><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="basic-usage" style="position:relative;"><a href="#basic-usage" aria-label="basic 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>Basic usage</h3> <p>Let’s add some validation to our form. Say we want to make the first and last name mandatory, and set a minimum length for last name.</p> <div class="gatsby-code-button-container" data-toaster-id="18090469681747812000" data-toaster-class="gatsby-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 { required, minLength } from 'vuelidate/lib/validators' new Vue({ el: '#app', data: { form: { firstName: 'Yas', lastName: '', additionalInfo: '', ageGroup: '1', agreeToTsCs: false, enrollingTerm: '', lazilyUpdated: '', alwaysNumber: null, alwaysTrimmed: '' } }, validations: { form: { firstName: { required }, lastName: { required, minLength: minLength(4) } } }, methods: { deCamelCase: function(str) { const result = str.replace(/([A-Z]+)/g, &quot; \$1&quot;); return result.charAt(0).toUpperCase() + result.slice(1) + ':' } } })`, `18090469681747812000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> required<span class="token punctuation">,</span> minLength <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vuelidate/lib/validators'</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#app'</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Yas'</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">additionalInfo</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">ageGroup</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span> <span class="token literal-property property">agreeToTsCs</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">enrollingTerm</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">lazilyUpdated</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">alwaysNumber</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token literal-property property">alwaysTrimmed</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 literal-property property">validations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">form</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token punctuation">{</span> required <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">lastName</span><span class="token operator">:</span> <span class="token punctuation">{</span> required<span class="token punctuation">,</span> <span class="token literal-property property">minLength</span><span class="token operator">:</span> <span class="token function">minLength</span><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 punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">deCamelCase</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">str</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> result <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">([A-Z]+)</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">" $1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> result<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now in our template we need to add the validation error message:</p> <div class="gatsby-code-button-container" data-toaster-id="59719203780276216000" data-toaster-class="gatsby-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;form-group&quot;> <label for=&quot;firstName&quot;>First name</label> <input type=&quot;text&quot; v-model=&quot;form.firstName&quot; class=&quot;form-control&quot; id=&quot;firstName&quot; placeholder=&quot;Enter your name&quot; /> <div v-if=&quot;!\$v.form.firstName.required&quot; class=&quot;text-danger&quot;> First name is required</div> </div> <div class=&quot;form-group&quot;> <label for=&quot;lastName&quot;>Last name</label> <input type=&quot;text&quot; v-model=&quot;form.lastName&quot; class=&quot;form-control&quot; id=&quot;lastName&quot; placeholder=&quot;Enter your last name&quot; /> <div v-if=&quot;!\$v.form.lastName.required&quot; class=&quot;text-danger&quot;> Last name is required</div> <div v-if=&quot;!\$v.form.lastName.minLength&quot; class=&quot;text-danger&quot;> Last name should be minimum 4 character</div> </div>`, `59719203780276216000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>firstName<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>First name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.firstName<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>form-control<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>firstName<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Enter your name<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">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!$v.form.firstName.required<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>text-danger<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> First name is required<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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lastName<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form.lastName<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>form-control<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>lastName<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Enter your last name<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">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!$v.form.lastName.required<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>text-danger<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Last name is required<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">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!$v.form.lastName.minLength<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>text-danger<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Last name should be minimum 4 character<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now you will have error messages shown when any of those rules are not met. Note that for first name I’ve used <code class="language-text">$error</code>, which gives us ability to hide the error until the form is submitted or the status of the form property becomes <code class="language-text">dirty</code>. For last name, I’ve used individual error fields, but that means that the error is visible on page load. A simple fix would be:</p> <div class="gatsby-code-button-container" data-toaster-id="62198867349920130000" data-toaster-class="gatsby-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;\$v.form.lastName.\$error&quot;> <div v-if=&quot;!\$v.form.lastName.required&quot; :class=&quot;{ 'text-danger': !\$v.form.lastName.required }&quot;> Last name is required</div> <div v-if=&quot;!\$v.form.lastName.minLength&quot; :class=&quot;{ 'text-danger': !\$v.form.lastName.minLength }&quot;> Last name should be minimum 4 character</div> </div>`, `62198867349920130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>$v.form.lastName.$error<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">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!$v.form.lastName.required<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>{ 'text-danger': !$v.form.lastName.required }<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Last name is required<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">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!$v.form.lastName.minLength<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>{ 'text-danger': !$v.form.lastName.minLength }<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Last name should be minimum 4 character<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="all-the-code-together-in-action" style="position:relative;"><a href="#all-the-code-together-in-action" aria-label="all the code together in action permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>All the code together in action</h2> <p>You can find the complete code on <a href="https://stackblitz.com/edit/vue-formhandling" target="_blank" rel="nofollow noopener noreferrer">StackBlitz</a> and play with it to explore more scenarios.</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 form handling is very straight forward in <strong>Vue</strong>, and learnt a few tricks like <code class="language-text">lazy</code>, and <code class="language-text">trim</code> on <code class="language-text">v-model</code> directive. We saw how error handling would be simple using a validation library instead of doing it from scratch and reinvent the wheel. And last but not least, we saw how to use <code class="language-text">vuelidate</code> library to handle our form’s errors.</p> <p>Hope this has been helpful for you and stay tuned for the next article about state management in <strong>Vue.js</strong>.</p><![CDATA[Infrastructure as code, Azure app service using a wildcard certificate from KeyVault]]>https://yashints.dev/blog/2019/10/31/azure-webapp-wildcardcert-keyvaulthttps://yashints.dev/blog/2019/10/31/azure-webapp-wildcardcert-keyvaultThu, 31 Oct 2019 00:00:00 GMT<p>This post is one of those posts which is related to my consulting side. I was involved in a project where infrastructure as code was the approach from get go and since we had everything on Azure, we chose a mix of ARM templates and PowerShell. I hit a few issues along the way which I think it’s very valuable to be aware of for many people and especially myself in future on a similar project 😊.</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 don’t want to go through the whole architecture, suffice to know we have a few <a href="https://azure.microsoft.com/en-us/services/app-service/web/" target="_blank" rel="nofollow noopener noreferrer">App Services</a> and <a href="https://azure.microsoft.com/en-us/services/functions/" target="_blank" rel="nofollow noopener noreferrer">Azure Functions</a> which need SSL binding and custom host name only in <em>production</em>. Since we’re managing the DNS records with <a href="https://www.cloudflare.com/" target="_blank" rel="nofollow noopener noreferrer">Cloudflare</a>, we got a wildcard cert for our domain and we imported the <a href="https://en.wikipedia.org/wiki/PKCS_12" target="_blank" rel="nofollow noopener noreferrer">PFX file</a> into a <a href="https://azure.microsoft.com/en-us/services/key-vault/" target="_blank" rel="nofollow noopener noreferrer">Key Vault</a> in a separate resource group to be used in our release.</p> <h2 id="first-try" style="position:relative;"><a href="#first-try" aria-label="first try permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>First try</h2> <p>So the ARM template we had looked like this initially:</p> <div class="gatsby-code-button-container" data-toaster-id="10788586608816253000" data-toaster-class="gatsby-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;parameters&quot;: { //... }, &quot;variables&quot;: { //... }, &quot;resources&quot;: [ { &quot;type&quot;: &quot;microsoft.insights/components&quot;, &quot;apiVersion&quot;: &quot;2015-05-01&quot;, &quot;name&quot;: &quot;[variables('appInsightsName')]&quot;, &quot;location&quot;: &quot;[variables('appInsightsLocation')]&quot;, &quot;tags&quot;: { &quot;displayName&quot;: &quot;app-insights&quot;, &quot;project&quot;: &quot;[variables('projectName')]&quot;, &quot;environment&quot;: &quot;[parameters('environment')]&quot; }, &quot;kind&quot;: &quot;web&quot;, &quot;properties&quot;: { &quot;Application_Type&quot;: &quot;web&quot;, &quot;Request_Source&quot;: &quot;IbizaWebAppExtensionCreate&quot; } }, { &quot;apiVersion&quot;: &quot;2016-09-01&quot;, &quot;type&quot;: &quot;Microsoft.Web/serverfarms&quot;, &quot;kind&quot;: &quot;app&quot;, &quot;name&quot;: &quot;[variables('appServicePlanName')]&quot;, &quot;tags&quot;: { &quot;displayName&quot;: &quot;app-service-plan&quot;, &quot;project&quot;: &quot;[variables('projectName')]&quot;, &quot;environment&quot;: &quot;[parameters('environment')]&quot; }, &quot;location&quot;: &quot;[parameters('deploymentLocation')]&quot;, &quot;properties&quot;: { &quot;name&quot;: &quot;[variables('appServicePlanName')]&quot;, &quot;perSiteScaling&quot;: false, &quot;reserved&quot;: false, &quot;targetWorkerCount&quot;: 0, &quot;targetWorkerSizeId&quot;: 0 }, &quot;dependsOn&quot;: [], &quot;sku&quot;: { &quot;name&quot;: &quot;[parameters('appServicePlanSku')]&quot;, &quot;tier&quot;: &quot;[parameters('appServicePlanTier')]&quot;, &quot;size&quot;: &quot;[parameters('appServicePlanSize')]&quot;, &quot;family&quot;: &quot;[parameters('appServicePlanFamily')]&quot;, &quot;capacity&quot;: &quot;[parameters('appServicePlanCapacity')]&quot; } }, { &quot;apiVersion&quot;: &quot;2016-08-01&quot;, &quot;type&quot;: &quot;Microsoft.Web/sites&quot;, &quot;kind&quot;: &quot;app&quot;, &quot;name&quot;: &quot;[variables('appServiceName')]&quot;, &quot;tags&quot;: { &quot;displayName&quot;: &quot;app-service&quot;, &quot;project&quot;: &quot;[variables('projectName')]&quot;, &quot;environment&quot;: &quot;[parameters('environment')]&quot; }, &quot;location&quot;: &quot;[parameters('deploymentLocation')]&quot;, &quot;properties&quot;: { &quot;name&quot;: &quot;[variables('appServiceName')]&quot;, &quot;serverFarmId&quot;: &quot;[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]&quot;, &quot;siteConfig&quot;: { &quot;appSettings&quot;: [ { &quot;name&quot;: &quot;WEBSITE_RUN_FROM_PACKAGE&quot;, &quot;value&quot;: &quot;1&quot; } ] }, &quot;httpsOnly&quot;: &quot;[parameters('appServiceHttpsOnly')]&quot; }, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]&quot;, &quot;[resourceId('microsoft.insights/components', variables('appInsightsName'))]&quot; ], &quot;resources&quot;: [ { &quot;apiVersion&quot;: &quot;2015-08-01&quot;, &quot;name&quot;: &quot;Microsoft.ApplicationInsights.AzureWebSites&quot;, &quot;type&quot;: &quot;siteextensions&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/Sites', variables('appServiceName'))]&quot; ], &quot;properties&quot;: {} }, { &quot;name&quot;: &quot;appsettings&quot;, &quot;type&quot;: &quot;config&quot;, &quot;apiVersion&quot;: &quot;2015-08-01&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/sites', variables('appServiceName'))]&quot;, &quot;Microsoft.ApplicationInsights.AzureWebSites&quot; ], &quot;properties&quot;: { &quot;APPINSIGHTS_INSTRUMENTATIONKEY&quot;: &quot;[reference(variables('appInsightsName'), '2015-05-01').InstrumentationKey]&quot; } } ] }, { &quot;type&quot;: &quot;Microsoft.Web/sites/config&quot;, &quot;apiVersion&quot;: &quot;2016-08-01&quot;, &quot;name&quot;: &quot;[concat(variables('appServiceName'), '/web')]&quot;, &quot;location&quot;: &quot;[parameters('deploymentLocation')]&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/sites', variables('appServiceName'))]&quot; ], &quot;tags&quot;: { &quot;displayName&quot;: &quot;app-service&quot;, &quot;project&quot;: &quot;[variables('projectName')]&quot;, &quot;environment&quot;: &quot;[parameters('environment')]&quot; }, &quot;properties&quot;: { &quot;alwaysOn&quot;: &quot;[parameters('appServiceAlwaysOn')]&quot; } }, { &quot;type&quot;: &quot;Microsoft.Web/certificates&quot;, &quot;name&quot;: &quot;[variables('certificateName')]&quot;, &quot;apiVersion&quot;: &quot;2016-03-01&quot;, &quot;location&quot;: &quot;[resourceGroup().location]&quot;, &quot;condition&quot;: &quot;[equals(parameters('environment'), 'prod')]&quot;, &quot;properties&quot;: { &quot;keyVaultId&quot;: &quot;[parameters('prodKeyVaultId')]&quot;, &quot;keyVaultSecretName&quot;: &quot;[parameters('prodKeyVaultSecretName')]&quot;, &quot;serverFarmId&quot;: &quot;[resourceId('Microsoft.Web/serverFarms', variables('appServicePlanName'))]&quot; }, &quot;dependsOn&quot;: [&quot;[concat('Microsoft.Web/sites/', variables('appServiceName')]&quot;] }, { &quot;type&quot;: &quot;Microsoft.Web/sites/hostnameBindings&quot;, &quot;name&quot;: &quot;[concat(variables('appServiceName'), '/', parameters('customHostname'))]&quot;, &quot;apiVersion&quot;: &quot;2016-03-01&quot;, &quot;location&quot;: &quot;[resourceGroup().location]&quot;, &quot;condition&quot;: &quot;[equals(parameters('environment'), 'prod')]&quot;, &quot;properties&quot;: { &quot;sslState&quot;: &quot;SniEnabled&quot;, &quot;thumbprint&quot;: &quot;[reference(resourceId('Microsoft.Web/certificates', variables('certificateName'))).Thumbprint]&quot; }, &quot;dependsOn&quot;: [ &quot;[concat('Microsoft.Web/certificates/', variables('certificateName'))]&quot; ] } ], &quot;outputs: { //... } }`, `10788586608816253000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"parameters"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">//...</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 comment">//...</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.insights/components"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2015-05-01"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[variables('appInsightsName')]"</span><span class="token punctuation">,</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"[variables('appInsightsLocation')]"</span><span class="token punctuation">,</span> <span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"displayName"</span><span class="token operator">:</span> <span class="token string">"app-insights"</span><span class="token punctuation">,</span> <span class="token property">"project"</span><span class="token operator">:</span> <span class="token string">"[variables('projectName')]"</span><span class="token punctuation">,</span> <span class="token property">"environment"</span><span class="token operator">:</span> <span class="token string">"[parameters('environment')]"</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">"web"</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"Application_Type"</span><span class="token operator">:</span> <span class="token string">"web"</span><span class="token punctuation">,</span> <span class="token property">"Request_Source"</span><span class="token operator">:</span> <span class="token string">"IbizaWebAppExtensionCreate"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-09-01"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Web/serverfarms"</span><span class="token punctuation">,</span> <span class="token property">"kind"</span><span class="token operator">:</span> <span class="token string">"app"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[variables('appServicePlanName')]"</span><span class="token punctuation">,</span> <span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"displayName"</span><span class="token operator">:</span> <span class="token string">"app-service-plan"</span><span class="token punctuation">,</span> <span class="token property">"project"</span><span class="token operator">:</span> <span class="token string">"[variables('projectName')]"</span><span class="token punctuation">,</span> <span class="token property">"environment"</span><span class="token operator">:</span> <span class="token string">"[parameters('environment')]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"[parameters('deploymentLocation')]"</span><span class="token punctuation">,</span> <span class="token property">"properties"</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">"[variables('appServicePlanName')]"</span><span class="token punctuation">,</span> <span class="token property">"perSiteScaling"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"reserved"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"targetWorkerCount"</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token property">"targetWorkerSizeId"</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</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">"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('appServicePlanSku')]"</span><span class="token punctuation">,</span> <span class="token property">"tier"</span><span class="token operator">:</span> <span class="token string">"[parameters('appServicePlanTier')]"</span><span class="token punctuation">,</span> <span class="token property">"size"</span><span class="token operator">:</span> <span class="token string">"[parameters('appServicePlanSize')]"</span><span class="token punctuation">,</span> <span class="token property">"family"</span><span class="token operator">:</span> <span class="token string">"[parameters('appServicePlanFamily')]"</span><span class="token punctuation">,</span> <span class="token property">"capacity"</span><span class="token operator">:</span> <span class="token string">"[parameters('appServicePlanCapacity')]"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-08-01"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Web/sites"</span><span class="token punctuation">,</span> <span class="token property">"kind"</span><span class="token operator">:</span> <span class="token string">"app"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[variables('appServiceName')]"</span><span class="token punctuation">,</span> <span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"displayName"</span><span class="token operator">:</span> <span class="token string">"app-service"</span><span class="token punctuation">,</span> <span class="token property">"project"</span><span class="token operator">:</span> <span class="token string">"[variables('projectName')]"</span><span class="token punctuation">,</span> <span class="token property">"environment"</span><span class="token operator">:</span> <span class="token string">"[parameters('environment')]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"[parameters('deploymentLocation')]"</span><span class="token punctuation">,</span> <span class="token property">"properties"</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">"[variables('appServiceName')]"</span><span class="token punctuation">,</span> <span class="token property">"serverFarmId"</span><span class="token operator">:</span> <span class="token string">"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"</span><span class="token punctuation">,</span> <span class="token property">"siteConfig"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"appSettings"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"WEBSITE_RUN_FROM_PACKAGE"</span><span class="token punctuation">,</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"1"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"httpsOnly"</span><span class="token operator">:</span> <span class="token string">"[parameters('appServiceHttpsOnly')]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"</span><span class="token punctuation">,</span> <span class="token string">"[resourceId('microsoft.insights/components', variables('appInsightsName'))]"</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">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2015-08-01"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Microsoft.ApplicationInsights.AzureWebSites"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"siteextensions"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/Sites', variables('appServiceName'))]"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"appsettings"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"config"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2015-08-01"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/sites', variables('appServiceName'))]"</span><span class="token punctuation">,</span> <span class="token string">"Microsoft.ApplicationInsights.AzureWebSites"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"APPINSIGHTS_INSTRUMENTATIONKEY"</span><span class="token operator">:</span> <span class="token string">"[reference(variables('appInsightsName'), '2015-05-01').InstrumentationKey]"</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 property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Web/sites/config"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-08-01"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[concat(variables('appServiceName'), '/web')]"</span><span class="token punctuation">,</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"[parameters('deploymentLocation')]"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/sites', variables('appServiceName'))]"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"displayName"</span><span class="token operator">:</span> <span class="token string">"app-service"</span><span class="token punctuation">,</span> <span class="token property">"project"</span><span class="token operator">:</span> <span class="token string">"[variables('projectName')]"</span><span class="token punctuation">,</span> <span class="token property">"environment"</span><span class="token operator">:</span> <span class="token string">"[parameters('environment')]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"alwaysOn"</span><span class="token operator">:</span> <span class="token string">"[parameters('appServiceAlwaysOn')]"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Web/certificates"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[variables('certificateName')]"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-03-01"</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">"condition"</span><span class="token operator">:</span> <span class="token string">"[equals(parameters('environment'), 'prod')]"</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"keyVaultId"</span><span class="token operator">:</span> <span class="token string">"[parameters('prodKeyVaultId')]"</span><span class="token punctuation">,</span> <span class="token property">"keyVaultSecretName"</span><span class="token operator">:</span> <span class="token string">"[parameters('prodKeyVaultSecretName')]"</span><span class="token punctuation">,</span> <span class="token property">"serverFarmId"</span><span class="token operator">:</span> <span class="token string">"[resourceId('Microsoft.Web/serverFarms', variables('appServicePlanName'))]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"[concat('Microsoft.Web/sites/', variables('appServiceName')]"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Web/sites/hostnameBindings"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[concat(variables('appServiceName'), '/', parameters('customHostname'))]"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-03-01"</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">"condition"</span><span class="token operator">:</span> <span class="token string">"[equals(parameters('environment'), 'prod')]"</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"sslState"</span><span class="token operator">:</span> <span class="token string">"SniEnabled"</span><span class="token punctuation">,</span> <span class="token property">"thumbprint"</span><span class="token operator">:</span> <span class="token string">"[reference(resourceId('Microsoft.Web/certificates', variables('certificateName'))).Thumbprint]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[concat('Microsoft.Web/certificates/', variables('certificateName'))]"</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> "outputs<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">//...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>There are a few important things here you need to pay attention to. First, we have the <code class="language-text">Microsoft/certificate</code> conditionally deployed, same as <code class="language-text">sites/hostnameBindings</code> if we’re deploying to production. Second, note how we have a reference to the certificate in Key Vault in the certificate properties. And last, we have a reference to the certificate in the <code class="language-text">hostNameBinding</code> in the same template.</p> <h2 id="first-try-1" style="position:relative;"><a href="#first-try-1" aria-label="first try 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>First try</h2> <p>When we first tried this, we hit a permission error on the Key Vault the template was referencing. I had made sure that the Azure DevOps service principal is added into the access policy of the Key Vault and also the tick the <code class="language-text">Azure Resource Manager for template deployment </code> checkbox to allow referencing the secret from within ARM template.</p> <div class="custom-block danger"><div class="custom-block-body"> <strong>Error</strong> Failed to add App Service certificate to the app, Check error for more details. Error Details: The service does not have access to ‘/subscriptions/XXXebXXX-XXX-XXXX-XXX-XXXXX/resourcegroups/XXXXX/providers/microsoft.keyvault/vaults/xxxxxxxxvault’ Key Vault. Please make sure that you have granted necessary permissions to the service to perform the request operation.</div></div> <p>This was really strange to me and I had no clue as to what’s missing. However, after a bit of Googling, I found out there are two service principals which belong to Microsoft and you have to add those to your Key Vault’s access policy in order to be able to link a certificate to your App Services.</p> <p><a href="https://github.com/Azure/azure-quickstart-templates/blob/master/101-app-service-certificate-wildcard/README.md" target="_blank" rel="nofollow noopener noreferrer">Here is the kick starter template repository on GitHub</a> which explains what needs to be done. But in short, you need to run these commands:</p> <div class="gatsby-code-button-container" data-toaster-id="92962212802711300000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`Login-AzureRmAccount Set-AzureRmContext -SubscriptionId AZURE_SUBSCRIPTION_ID Set-AzureRmKeyVaultAccessPolicy -VaultName KEY_VAULT_NAME -ServicePrincipalName f3c21649-0979-4721-ac85-b0216b2cf413 -PermissionsToSecrets get,set,delete Set-AzureRmKeyVaultAccessPolicy -VaultName KEY_VAULT_NAME -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets get`, `92962212802711300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">Login-AzureRmAccount <span class="token function">Set-AzureRmContext</span> <span class="token operator">-</span>SubscriptionId AZURE_SUBSCRIPTION_ID <span class="token function">Set-AzureRmKeyVaultAccessPolicy</span> <span class="token operator">-</span>VaultName KEY_VAULT_NAME <span class="token operator">-</span>ServicePrincipalName f3c21649-0979-4721-ac85-b0216b2cf413 <span class="token operator">-</span>PermissionsToSecrets get<span class="token punctuation">,</span><span class="token function">set</span><span class="token punctuation">,</span>delete <span class="token function">Set-AzureRmKeyVaultAccessPolicy</span> <span class="token operator">-</span>VaultName KEY_VAULT_NAME <span class="token operator">-</span>ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd <span class="token operator">-</span>PermissionsToSecrets get</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>After running these commands, the error was gone and we could progress further. Note that the application ids are fixed.</p> <h2 id="second-try" style="position:relative;"><a href="#second-try" aria-label="second try permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Second try</h2> <p>Once the necessary permissions was granted, we run the deployment again to be hit with the second issue, this time I was so baffled by this error:</p> <div class="custom-block danger"><div class="custom-block-body"> <strong>Error</strong> Another certificate exists with same thumbprint XXXXXXXXXXXXXXXXXXXX at location xxxx in the Resource Group xxxxxx.</div></div> <p>I wasn’t sure what’s causing the issue since I thought that since we’re reusing the same certificate, linking them wouldn’t be a problem. But when I looked at the deployments on the resource group, I found out Azure is trying to create multiple <code class="language-text">Microsoft•Web/certificates</code> resources which will have the same thumbprint and so it fails. As Aussies say it, fair dinkum.</p> <p>So I extracted the certificate resource to the parent ARM template and passed a reference of it down to linked templates:</p> <div class="gatsby-code-button-container" data-toaster-id="36308439569027297000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ //parent ARM template &quot;resources&quot;: [ { &quot;type&quot;: &quot;Microsoft.Web/certificates&quot;, &quot;name&quot;: &quot;[parameters('prodKeyVaultSecretName')]&quot;, &quot;condition&quot;: &quot;[equals(parameters('environment'), 'prod')]&quot;, &quot;apiVersion&quot;: &quot;2016-03-01&quot;, &quot;location&quot;: &quot;[parameters('deploymentLocation')]&quot;, &quot;properties&quot;: { &quot;keyVaultId&quot;: &quot;[parameters('prodKeyVaultId')]&quot;, &quot;keyVaultSecretName&quot;: &quot;[parameters('prodKeyVaultSecretName')]&quot; } }, //... { &quot;apiVersion&quot;: &quot;2017-05-10&quot;, &quot;name&quot;: &quot;web-client-app-service-linked-template&quot;, &quot;type&quot;: &quot;Microsoft.Resources/deployments&quot;, &quot;metadata&quot;: { &quot;comments&quot;: &quot;Linked ARM template deploys web client app service&quot; }, &quot;properties&quot;: { &quot;mode&quot;: &quot;Incremental&quot;, &quot;templateLink&quot;: { &quot;uri&quot;: &quot;[concat('https://', parameters('artefactsStorageAccountName'),'.blob.core.windows.net/',parameters('artefactsStorageAccountContainerName'),'/client-web-app/azuredeploy.json',parameters('artefactsStorageAccountSasToken'))]&quot;, &quot;contentVersion&quot;: &quot;1.0.0.0&quot; }, &quot;parametersLink&quot;: { &quot;uri&quot;: &quot;[concat('https://', parameters('artefactsStorageAccountName'), '.blob.core.windows.net/', parameters('artefactsStorageAccountContainerName'),'/client-web-app/azuredeploy.parameters-', parameters('environment'), '.json', parameters('artefactsStorageAccountSasToken'))]&quot;, &quot;contentVersion&quot;: &quot;1.0.0.0&quot; } }, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/certificates', parameters('prodKeyVaultSecretName'))]&quot; ] }, ] }`, `36308439569027297000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token comment">//parent ARM template</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.Web/certificates"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[parameters('prodKeyVaultSecretName')]"</span><span class="token punctuation">,</span> <span class="token property">"condition"</span><span class="token operator">:</span> <span class="token string">"[equals(parameters('environment'), 'prod')]"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-03-01"</span><span class="token punctuation">,</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"[parameters('deploymentLocation')]"</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"keyVaultId"</span><span class="token operator">:</span> <span class="token string">"[parameters('prodKeyVaultId')]"</span><span class="token punctuation">,</span> <span class="token property">"keyVaultSecretName"</span><span class="token operator">:</span> <span class="token string">"[parameters('prodKeyVaultSecretName')]"</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> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2017-05-10"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"web-client-app-service-linked-template"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Resources/deployments"</span><span class="token punctuation">,</span> <span class="token property">"metadata"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"comments"</span><span class="token operator">:</span> <span class="token string">"Linked ARM template deploys web client app service"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"mode"</span><span class="token operator">:</span> <span class="token string">"Incremental"</span><span class="token punctuation">,</span> <span class="token property">"templateLink"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"[concat('https://', parameters('artefactsStorageAccountName'),'.blob.core.windows.net/',parameters('artefactsStorageAccountContainerName'),'/client-web-app/azuredeploy.json',parameters('artefactsStorageAccountSasToken'))]"</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 punctuation">,</span> <span class="token property">"parametersLink"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"[concat('https://', parameters('artefactsStorageAccountName'), '.blob.core.windows.net/', parameters('artefactsStorageAccountContainerName'),'/client-web-app/azuredeploy.parameters-', parameters('environment'), '.json', parameters('artefactsStorageAccountSasToken'))]"</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 punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/certificates', parameters('prodKeyVaultSecretName'))]"</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And in the linked template:</p> <div class="gatsby-code-button-container" data-toaster-id="12974173586957138000" data-toaster-class="gatsby-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;resources&quot;: [ { &quot;apiVersion&quot;: &quot;2016-08-01&quot;, &quot;type&quot;: &quot;Microsoft.Web/sites&quot;, &quot;kind&quot;: &quot;app&quot;, &quot;name&quot;: &quot;[variables('appServiceName')]&quot;, &quot;tags&quot;: { &quot;displayName&quot;: &quot;app-service&quot;, &quot;project&quot;: &quot;[variables('projectName')]&quot;, &quot;environment&quot;: &quot;[parameters('environment')]&quot; }, &quot;location&quot;: &quot;[parameters('deploymentLocation')]&quot;, &quot;properties&quot;: { &quot;name&quot;: &quot;[variables('appServiceName')]&quot;, &quot;serverFarmId&quot;: &quot;[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]&quot;, &quot;siteConfig&quot;: { &quot;appSettings&quot;: [ { &quot;name&quot;: &quot;WEBSITE_RUN_FROM_PACKAGE&quot;, &quot;value&quot;: &quot;1&quot; } ] }, &quot;httpsOnly&quot;: &quot;[parameters('appServiceHttpsOnly')]&quot;, &quot;hostNameSslStates&quot;: [ { &quot;name&quot;: &quot;[parameters('customHostname')]&quot;, &quot;sslState&quot;: &quot;SniEnabled&quot;, &quot;thumbprint&quot;: &quot;[reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint]&quot;, &quot;toUpdate&quot;: true } ] }, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]&quot;, &quot;[resourceId('microsoft.insights/components', variables('appInsightsName'))]&quot; ], &quot;resources&quot;: [ { &quot;apiVersion&quot;: &quot;2015-08-01&quot;, &quot;name&quot;: &quot;Microsoft.ApplicationInsights.AzureWebSites&quot;, &quot;type&quot;: &quot;siteextensions&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/Sites', variables('appServiceName'))]&quot; ], &quot;properties&quot;: {} }, { &quot;name&quot;: &quot;appsettings&quot;, &quot;type&quot;: &quot;config&quot;, &quot;apiVersion&quot;: &quot;2015-08-01&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/sites', variables('appServiceName'))]&quot;, &quot;Microsoft.ApplicationInsights.AzureWebSites&quot; ], &quot;properties&quot;: { &quot;APPINSIGHTS_INSTRUMENTATIONKEY&quot;: &quot;[reference(variables('appInsightsName'), '2015-05-01').InstrumentationKey]&quot; } }, { &quot;type&quot;: &quot;hostNameBindings&quot;, &quot;name&quot;: &quot;[parameters('customHostname')]&quot;, &quot;condition&quot;: &quot;[equals(parameters('environment'), 'prod')]&quot;, &quot;apiVersion&quot;: &quot;2016-08-01&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/sites', variables('appServiceName'))]&quot; ], &quot;properties&quot;: { &quot;siteName&quot;: &quot;[variables('appServiceName')]&quot;, &quot;domainId&quot;: null, &quot;hostNameType&quot;: &quot;Verified&quot; } } ] }, ] }`, `12974173586957138000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><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">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-08-01"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Web/sites"</span><span class="token punctuation">,</span> <span class="token property">"kind"</span><span class="token operator">:</span> <span class="token string">"app"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[variables('appServiceName')]"</span><span class="token punctuation">,</span> <span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"displayName"</span><span class="token operator">:</span> <span class="token string">"app-service"</span><span class="token punctuation">,</span> <span class="token property">"project"</span><span class="token operator">:</span> <span class="token string">"[variables('projectName')]"</span><span class="token punctuation">,</span> <span class="token property">"environment"</span><span class="token operator">:</span> <span class="token string">"[parameters('environment')]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"[parameters('deploymentLocation')]"</span><span class="token punctuation">,</span> <span class="token property">"properties"</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">"[variables('appServiceName')]"</span><span class="token punctuation">,</span> <span class="token property">"serverFarmId"</span><span class="token operator">:</span> <span class="token string">"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"</span><span class="token punctuation">,</span> <span class="token property">"siteConfig"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"appSettings"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"WEBSITE_RUN_FROM_PACKAGE"</span><span class="token punctuation">,</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"1"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"httpsOnly"</span><span class="token operator">:</span> <span class="token string">"[parameters('appServiceHttpsOnly')]"</span><span class="token punctuation">,</span> <span class="token property">"hostNameSslStates"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[parameters('customHostname')]"</span><span class="token punctuation">,</span> <span class="token property">"sslState"</span><span class="token operator">:</span> <span class="token string">"SniEnabled"</span><span class="token punctuation">,</span> <span class="token property">"thumbprint"</span><span class="token operator">:</span> <span class="token string">"[reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint]"</span><span class="token punctuation">,</span> <span class="token property">"toUpdate"</span><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 property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"</span><span class="token punctuation">,</span> <span class="token string">"[resourceId('microsoft.insights/components', variables('appInsightsName'))]"</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">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2015-08-01"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Microsoft.ApplicationInsights.AzureWebSites"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"siteextensions"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/Sites', variables('appServiceName'))]"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"appsettings"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"config"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2015-08-01"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/sites', variables('appServiceName'))]"</span><span class="token punctuation">,</span> <span class="token string">"Microsoft.ApplicationInsights.AzureWebSites"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"APPINSIGHTS_INSTRUMENTATIONKEY"</span><span class="token operator">:</span> <span class="token string">"[reference(variables('appInsightsName'), '2015-05-01').InstrumentationKey]"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"hostNameBindings"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[parameters('customHostname')]"</span><span class="token punctuation">,</span> <span class="token property">"condition"</span><span class="token operator">:</span> <span class="token string">"[equals(parameters('environment'), 'prod')]"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-08-01"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/sites', variables('appServiceName'))]"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"siteName"</span><span class="token operator">:</span> <span class="token string">"[variables('appServiceName')]"</span><span class="token punctuation">,</span> <span class="token property">"domainId"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span> <span class="token property">"hostNameType"</span><span class="token operator">:</span> <span class="token string">"Verified"</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Notice the reference to the certificate resource in the <code class="language-text">hostNameSslStates</code> property. And again we kicked off a new release to be hit with another problem.</p> <p>This time it complained about a missing resource for non prod environments which was fair, as I forgot to apply the condition to the thumbprint reference.</p> <h2 id="third-try" style="position:relative;"><a href="#third-try" aria-label="third try permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Third try</h2> <p>So I applied an if condition to the thumbprint thinking it would work:</p> <div class="gatsby-code-button-container" data-toaster-id="74129220843443800000" data-toaster-class="gatsby-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;hostNameSslStates&quot;: [ { &quot;name&quot;: &quot;[parameters('customHostname')]&quot;, &quot;sslState&quot;: &quot;SniEnabled&quot;, &quot;thumbprint&quot;: &quot;[if(equals(parameters('environment'), 'prod'), reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint, '')]&quot;, &quot;toUpdate&quot;: true } ] }`, `74129220843443800000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"hostNameSslStates"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[parameters('customHostname')]"</span><span class="token punctuation">,</span> <span class="token property">"sslState"</span><span class="token operator">:</span> <span class="token string">"SniEnabled"</span><span class="token punctuation">,</span> <span class="token property">"thumbprint"</span><span class="token operator">:</span> <span class="token string">"[if(equals(parameters('environment'), 'prod'), reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint, '')]"</span><span class="token punctuation">,</span> <span class="token property">"toUpdate"</span><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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Which failed again. This time I found out that the reference evaluation happens regardless of if statement. So I removed the <code class="language-text">hostNameSslStates</code> altogether and used the full resource:</p> <div class="gatsby-code-button-container" data-toaster-id="38272535662978430000" data-toaster-class="gatsby-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;resources&quot;: [ { &quot;type&quot;: &quot;hostNameBindings&quot;, &quot;name&quot;: &quot;[parameters('customHostname')]&quot;, &quot;condition&quot;: &quot;[variables('isProd')]&quot;, &quot;apiVersion&quot;: &quot;2016-08-01&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/sites', variables('appServiceName'))]&quot; ], &quot;properties&quot;: { &quot;siteName&quot;: &quot;[variables('appServiceName')]&quot;, &quot;domainId&quot;: null, &quot;hostNameType&quot;: &quot;Verified&quot;, &quot;sslState&quot;: &quot;SniEnabled&quot;, &quot;thumbprint&quot;: &quot;[reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint]&quot; } } ] }`, `38272535662978430000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><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">"hostNameBindings"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[parameters('customHostname')]"</span><span class="token punctuation">,</span> <span class="token property">"condition"</span><span class="token operator">:</span> <span class="token string">"[variables('isProd')]"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-08-01"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/sites', variables('appServiceName'))]"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"siteName"</span><span class="token operator">:</span> <span class="token string">"[variables('appServiceName')]"</span><span class="token punctuation">,</span> <span class="token property">"domainId"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span> <span class="token property">"hostNameType"</span><span class="token operator">:</span> <span class="token string">"Verified"</span><span class="token punctuation">,</span> <span class="token property">"sslState"</span><span class="token operator">:</span> <span class="token string">"SniEnabled"</span><span class="token punctuation">,</span> <span class="token property">"thumbprint"</span><span class="token operator">:</span> <span class="token string">"[reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint]"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Which failed again 😭😭😭. For the same reason as before, which was the reference to the missing resource.</p> <h2 id="forth-try" style="position:relative;"><a href="#forth-try" aria-label="forth try permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Forth try</h2> <p>So I tried the if condition trick again this time on the <code class="language-text">thumbprint</code> property of the <code class="language-text">hostNameBindings</code> resource:</p> <div class="gatsby-code-button-container" data-toaster-id="80528653510593770000" data-toaster-class="gatsby-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;type&quot;: &quot;hostNameBindings&quot;, &quot;name&quot;: &quot;[parameters('customHostname')]&quot;, &quot;condition&quot;: &quot;[variables('isProd')]&quot;, &quot;apiVersion&quot;: &quot;2016-08-01&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Web/sites', variables('appServiceName'))]&quot; ], &quot;properties&quot;: { &quot;siteName&quot;: &quot;[variables('appServiceName')]&quot;, &quot;domainId&quot;: null, &quot;hostNameType&quot;: &quot;Verified&quot;, &quot;sslState&quot;: &quot;SniEnabled&quot;, &quot;thumbprint&quot;: &quot;[if(variables('isProd'), reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint, '')]&quot; } }`, `80528653510593770000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"hostNameBindings"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[parameters('customHostname')]"</span><span class="token punctuation">,</span> <span class="token property">"condition"</span><span class="token operator">:</span> <span class="token string">"[variables('isProd')]"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2016-08-01"</span><span class="token punctuation">,</span> <span class="token property">"dependsOn"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"[resourceId('Microsoft.Web/sites', variables('appServiceName'))]"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"siteName"</span><span class="token operator">:</span> <span class="token string">"[variables('appServiceName')]"</span><span class="token punctuation">,</span> <span class="token property">"domainId"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span> <span class="token property">"hostNameType"</span><span class="token operator">:</span> <span class="token string">"Verified"</span><span class="token punctuation">,</span> <span class="token property">"sslState"</span><span class="token operator">:</span> <span class="token string">"SniEnabled"</span><span class="token punctuation">,</span> <span class="token property">"thumbprint"</span><span class="token operator">:</span> <span class="token string">"[if(variables('isProd'), reference(concat('Microsoft.Web/certificates/', parameters('certificateName')), '2016-03-01').Thumbprint, '')]"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And guess what, it was successful. OMG, I was so happy that this was working.</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 if you have a wildcard certificate and you want to reuse it in multiple App Services, DO NOT create the certificate for one of those, simply create one and share it with all of them.</p> <p>Here are some points which might be helpful to know:</p> <ul> <li>The ARM deployment respects the conditional resource in the <code class="language-text">dependsOn</code> section. Meaning if the resource is conditionally created, it doesn’t have any effect in the order of deployment and it won’t fail it either.</li> <li>You can’t use a <code class="language-text">reference</code> function in the variable section. Otherwise my life would’ve been much easier 😁.</li> <li>When using a <code class="language-text">reference</code> on a property, the function is evaluated regardless of the fact that you have an if condition or not (happy to be proven wrong with this one).</li> <li>And last, you need to be patient when working with ARM templates 😂.</li> </ul> <p>Hope this article helps someone else and saves their time. I am planning to create a template set and create a PR into kick starter repo. But don’t have any timeline as of now.</p><![CDATA[Deliver a better user experience using Vue.js Router 🛣️]]>https://yashints.dev/blog/2019/10/30/vue-routerhttps://yashints.dev/blog/2019/10/30/vue-routerWed, 30 Oct 2019 00:00:00 GMT<p><a href="https://vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue.js</a> is an approachable, versatile, performant, and progressive framework to build user interfaces with. I wrote a <a href="https://yashints.dev/blog/2019/10/18/vue-intro" target="_blank" rel="nofollow noopener noreferrer">comprehensive intro</a> a week or so ago and promised to continue adding more each week. This week is about <strong>Vue</strong> router and how it helps deliver a better user experience.</p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p>When it comes to navigation between pages, we’ve gone through a really interesting journey. Not sure if you remember or not, every click on a link required a back and forth between client and server and that meant most times you’d lose your current state if you accidentally clicked on a link.</p> <p>When people started using dynamic pages where only part of the page was loaded and not the whole page, user experience was much better and soon many websites had that by default. With this came the challenge of how to handle navigation on the browser side. Many approaches was used, but using the browser history API seems to be the winner.</p> <p><strong>Vue</strong> has its own Router which uses the same API and deeply integrates with the <strong>Vue</strong>’s core library to deliver a smooth experience for those developing Single Page Applications.</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> <p><strong>Vue</strong> Router has many great features, so let’s review them:</p> <ul> <li>Nested route/view mapping</li> <li>Modular, component-based router configuration</li> <li>Route params, query, wildcards</li> <li>View transition effects powered by <strong>Vue</strong>’s transition system</li> <li>Fine-grained navigation control</li> <li>Links with automatic active CSS classes</li> <li>HTML5 history mode or hash mode, with auto-fallback in IE9</li> <li>Customizable Scroll Behaviour</li> </ul> <p>We will go through each of these in details later.</p> <h2 id="getting-cstarted" style="position:relative;"><a href="#getting-cstarted" aria-label="getting cstarted permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 cstarted</h2> <p>Creating an application which leverages <strong>Vue</strong> Router is very easy with <a href="https://github.com/vuejs/vue-cli" target="_blank" rel="nofollow noopener noreferrer">vue-cli</a>.</p> <div class="gatsby-code-button-container" data-toaster-id="51278188418556250000" data-toaster-class="gatsby-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 vrouter`, `51278188418556250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">vue create vrouter</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>At this point you’ll be asked to choose a preset, make sure to select the second option which says manually select features. You can press down arrow key and enter to move to the next screen.</p> <p><img src="/4e02b0ee8042c117612a34aecb6883c5/cli-create.jpg" alt="Vue cli initial prompt"></p> <p>Next you are asked to select which features you want to have for this project:</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/adea396c8ec5e407e74e13c1ff857a8f/4b190/cli-preset.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 23.333333333333332%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAByZAD/8QAFRABAQAAAAAAAAAAAAAAAAAAARD/2gAIAQEAAQUCb//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABYQAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAQABPyFO3//aAAwDAQACAAMAAAAQAA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAXEAADAQAAAAAAAAAAAAAAAAAAARFB/9oACAEBAAE/ENwrKz//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Choosing presets for the new Vue project" title="" src="/static/adea396c8ec5e407e74e13c1ff857a8f/4b190/cli-preset.jpg" srcset="/static/adea396c8ec5e407e74e13c1ff857a8f/6f81f/cli-preset.jpg 270w, /static/adea396c8ec5e407e74e13c1ff857a8f/09d21/cli-preset.jpg 540w, /static/adea396c8ec5e407e74e13c1ff857a8f/4b190/cli-preset.jpg 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" decoding="async" /> </a> </span></p> <p>We’ll choose <code class="language-text">babel</code>, <code class="language-text">TypeScript</code>, <code class="language-text">Router</code>, <code class="language-text">CSS Pre-processor</code>, and <code class="language-text">Linter</code>.</p> <p>The next question is asking whether you want to have class style components. I just press enter since it’s not the focus of this article. Do the same for the next prompt too. Next question is asking you whether you want history mode for the router. Select yes, this will get rid of the <code class="language-text">#</code> symbol at the end of URL and uses <code class="language-text">history.pushState</code> to navigate without a page reload.</p> <p>For the remaining questions select whatever you like 😉. Now type <code class="language-text">cd vrouter &amp;&amp; npm run serve</code>, you should be able to see the application compiling and once finished you can view the app at <code class="language-text">http://localhost:8080/</code>.</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/b69d28f0bb4ffa4ff5c19a357b575452/4b190/vrouter-landing.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 68.14814814814815%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMCBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB36z4owBf/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAIBAxAh/9oACAEBAAEFAipnbJO5/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAAREAEiD/2gAIAQEABj8ChsEs/wD/xAAcEAACAgIDAAAAAAAAAAAAAAABEQAhEDFBcYH/2gAIAQEAAT8hLRW4dXCnuG4M7Qauf//aAAwDAQACAAMAAAAQEw//xAAWEQEBAQAAAAAAAAAAAAAAAAABECH/2gAIAQMBAT8QTZ//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAEBAAIDAQEAAAAAAAAAAAABEQAxIUFREGH/2gAIAQEAAT8Q6rw4urjUmaqqN76+AtieTDlCb+GUCq+5/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Landing page of the default Vue router project" title="" src="/static/b69d28f0bb4ffa4ff5c19a357b575452/4b190/vrouter-landing.jpg" srcset="/static/b69d28f0bb4ffa4ff5c19a357b575452/6f81f/vrouter-landing.jpg 270w, /static/b69d28f0bb4ffa4ff5c19a357b575452/09d21/vrouter-landing.jpg 540w, /static/b69d28f0bb4ffa4ff5c19a357b575452/4b190/vrouter-landing.jpg 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" decoding="async" /> </a> </span></p> <p>Note that you have <em>Home</em> and <em>About</em> menu items at the top, click on <em>About</em> and you’ll be redirected to the about page.</p> <h2 id="default-config" style="position:relative;"><a href="#default-config" aria-label="default 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>Default config</h2> <p>If you open the <code class="language-text">index.ts</code> file in the <code class="language-text">src/router</code> folder, you will see the default configuration:</p> <div class="gatsby-code-button-container" data-toaster-id="82632511947156370000" data-toaster-class="gatsby-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 Vue from &quot;vue&quot;; import VueRouter from &quot;vue-router&quot;; import Home from &quot;../views/Home.vue&quot;; Vue.use(VueRouter); const routes = [ { path: &quot;/&quot;, name: &quot;home&quot;, component: Home }, { path: &quot;/about&quot;, name: &quot;about&quot;, // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: &quot;about&quot; */ &quot;../views/About.vue&quot;) } ]; const router = new VueRouter({ mode: &quot;history&quot;, base: process.env.BASE_URL, routes }); export default router;`, `82632511947156370000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">import</span> Vue <span class="token keyword">from</span> <span class="token string">"vue"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> VueRouter <span class="token keyword">from</span> <span class="token string">"vue-router"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Home <span class="token keyword">from</span> <span class="token string">"../views/Home.vue"</span><span class="token punctuation">;</span> Vue<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>VueRouter<span class="token punctuation">)</span><span class="token punctuation">;</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> name<span class="token operator">:</span> <span class="token string">"home"</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> path<span class="token operator">:</span> <span class="token string">"/about"</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">"about"</span><span class="token punctuation">,</span> <span class="token comment">// route level code-splitting</span> <span class="token comment">// this generates a separate chunk (about.[hash].js) for this route</span> <span class="token comment">// which is lazy-loaded when the route is visited.</span> <span class="token function-variable function">component</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token comment">/* webpackChunkName: "about" */</span> <span class="token string">"../views/About.vue"</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 keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span> mode<span class="token operator">:</span> <span class="token string">"history"</span><span class="token punctuation">,</span> base<span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">BASE_URL</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 keyword">export</span> <span class="token keyword">default</span> router<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It’s very straight forward, but I want you to pay attention to two things here. First look at the way the about component is loaded. This is how <strong>Vue</strong> lazy loads the child routes. Second, check how the mode is set to <code class="language-text">history</code> in the <code class="language-text">VueRouter</code> constructor options. This is what you chose during setup.</p> <h2 id="nested-routes" style="position:relative;"><a href="#nested-routes" aria-label="nested routes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Nested routes</h2> <p>Real life applications often have nested structure, such as all students having a profile. If you imagine a route like <code class="language-text">/student/1/profile</code> and <code class="language-text">/student/2/profile</code>, the profile is a nested route of the student route.</p> <p>OK, now let’s add a nested route to our app. We want to add two nested routes to our about page. Assume we would have a contact page form and a find us page which will contains our address.</p> <p>In order to do this, we need to:</p> <ul> <li>Add a <code class="language-text">router-view</code> tag inside our about page</li> <li>Include the links which navigate to sub routes using <code class="language-text">router-link</code></li> </ul> <div class="gatsby-code-button-container" data-toaster-id="79326660738304640000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<template> <div class=&quot;about&quot;> <h1>This is an about page</h1> <div> <router-link to=&quot;/about/contact&quot;>Contact us</router-link>| <router-link to=&quot;/about/location&quot;>Our location</router-link> </div> <br/> <router-view></router-view> </div> </template>`, `79326660738304640000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</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>about<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>h1</span><span class="token punctuation">></span></span>This is an about page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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>router-link</span> <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about/contact<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Contact us<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">></span></span>| <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span> <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about/location<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Our location<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</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>br</span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-view</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>template</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Note that we have nested routes here such as <code class="language-text">/about/contact</code>. Then let’s add two components inside <code class="language-text">src/components</code> folder, <code class="language-text">ContactForm.vue</code> and <code class="language-text">FindUs.vue</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="24018635130295250000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!--ContactForm.vue--> <template> <div> <form> <label>Name</label> <input type=&quot;text&quot; name=&quot;name&quot;> <label>Last name</label> <input type=&quot;text&quot; name=&quot;lastname&quot;> </form> </div> </template>`, `24018635130295250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token comment">&lt;!--ContactForm.vue--></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</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>form</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">></span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<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>label</span><span class="token punctuation">></span></span>Last name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lastname<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>form</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>template</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="88782096894118760000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!--FindUs.vue--> <template> <div> 📍 You can find us at Collins Squre, Melbourne, Australia </div> </template>`, `88782096894118760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token comment">&lt;!--FindUs.vue--></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</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> 📍 You can find us at Collins Squre, Melbourne, Australia <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>template</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>At the end we need to let the router know that the about page has nested routes. This can be done using the children property of the about route. At this point feels like you’re writing Angular right 😉?</p> <div class="gatsby-code-button-container" data-toaster-id="90968122651309470000" data-toaster-class="gatsby-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 Contact from &quot;../components/ContactForm.vue&quot;; import Location from &quot;../components/Location.vue&quot;; //... const routes = [ { path: &quot;/&quot;, name: &quot;home&quot;, component: Home }, { path: &quot;/about&quot;, name: &quot;about&quot;, component: About, children: [ { // UserProfile will be rendered inside User's <router-view> // when /user/:id/profile is matched path: &quot;contact&quot;, component: Contact }, { // UserPosts will be rendered inside User's <router-view> // when /user/:id/posts is matched path: &quot;location&quot;, component: Location } ] } ];`, `90968122651309470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token comment">//...</span> <span class="token keyword">import</span> Contact <span class="token keyword">from</span> <span class="token string">"../components/ContactForm.vue"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Location <span class="token keyword">from</span> <span class="token string">"../components/Location.vue"</span><span class="token punctuation">;</span> <span class="token comment">//...</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> name<span class="token operator">:</span> <span class="token string">"home"</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> path<span class="token operator">:</span> <span class="token string">"/about"</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">"about"</span><span class="token punctuation">,</span> component<span class="token operator">:</span> About<span class="token punctuation">,</span> children<span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token comment">// UserProfile will be rendered inside User's &lt;router-view></span> <span class="token comment">// when /user/:id/profile is matched</span> path<span class="token operator">:</span> <span class="token string">"contact"</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Contact <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token comment">// UserPosts will be rendered inside User's &lt;router-view></span> <span class="token comment">// when /user/:id/posts is matched</span> path<span class="token operator">:</span> <span class="token string">"location"</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Location <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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I’ve removed the extra code for brevity.</p> <p>And that’s all you need to get your nested routes working. If you run the app now, you should see two links in the about page which then load the content below to one of those child components.</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/43f37e0a70834930584c8d24f3649546/4b190/nested-routes.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 47.03703703703703%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3ooUD//EABUQAQEAAAAAAAAAAAAAAAAAAAEg/9oACAEBAAEFAmv/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAaEAEAAgMBAAAAAAAAAAAAAAABADEQEUGR/9oACAEBAAE/IUlagvA9YVG8FT//2gAMAwEAAgADAAAAECMP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBABAAEEAwAAAAAAAAAAAAAAAQARITFBEGHR/9oACAEBAAE/EFMpureDW/TfhFUNq9Myc3//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Nested routes" title="" src="/static/43f37e0a70834930584c8d24f3649546/4b190/nested-routes.jpg" srcset="/static/43f37e0a70834930584c8d24f3649546/6f81f/nested-routes.jpg 270w, /static/43f37e0a70834930584c8d24f3649546/09d21/nested-routes.jpg 540w, /static/43f37e0a70834930584c8d24f3649546/4b190/nested-routes.jpg 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" decoding="async" /> </a> </span></p> <h2 id="dynamic-routes" style="position:relative;"><a href="#dynamic-routes" aria-label="dynamic routes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Dynamic routes</h2> <p>Often you have to map the same route with a different patterns to the same components. This can be a user profile page where you have the user id as variable such as <code class="language-text">/user/1</code>.</p> <p>This is also very easy to achieve, all you need is to change your route path from static <code class="language-text">'/user'</code> to dynamic <code class="language-text">'/user/:id'</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="67258985690977280000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`//... routes: [ { path: '/user/:id', component: User } ]`, `67258985690977280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token comment">//...</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">'/user/:id'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> User <span class="token punctuation">}</span> <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>You can access the id parameter via route params like <code class="language-text">$route.params.id</code>. This can be used to fetch the user profile for example and show it in the page.</p> <h2 id="not-found" style="position:relative;"><a href="#not-found" aria-label="not found permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Not found</h2> <p>Most often you will need a fall back route to show a user friendly page not found page. This is again similar to what you had in Angular:</p> <div class="gatsby-code-button-container" data-toaster-id="33141399179596420000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ // will match everything path: '*', component: PageNotFound }`, `33141399179596420000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token punctuation">{</span> <span class="token comment">// will match everything</span> path<span class="token operator">:</span> <span class="token string">'*'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> PageNotFound <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <blockquote> <p>💡 Remember to put this at the end of all routes, otherwise anything below this will not work!</p> </blockquote> <h2 id="navigation-by-code" style="position:relative;"><a href="#navigation-by-code" aria-label="navigation by 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>Navigation by code</h2> <p>If you want to navigate within your code, you can use the push method of router which has the below syntax:</p> <div class="gatsby-code-button-container" data-toaster-id="74382105775685780000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`router.push(location, onComplete?, onAbort?)`, `74382105775685780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts">router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>location<span class="token punctuation">,</span> onComplete<span class="token operator">?</span><span class="token punctuation">,</span> onAbort<span class="token operator">?</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And because you have access to router via <code class="language-text">this.$router</code>, you can simply use it like so:</p> <div class="gatsby-code-button-container" data-toaster-id="6362819436816492000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`this.\$router.push('about'); this.\$router.push({ name: 'home' }); this.\$router.push({ name: 'user', params: { userId: '123' } });`, `6362819436816492000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'about'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'home'</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>$router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span> params<span class="token operator">:</span> <span class="token punctuation">{</span> userId<span class="token operator">:</span> <span class="token string">'123'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For now ignore the ones getting an object, I will explain that in a buzz.</p> <h2 id="named-routes" style="position:relative;"><a href="#named-routes" aria-label="named routes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Named routes</h2> <p>You can assign a name to your route, if you do this you can pass an object to <code class="language-text">router-link</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="2360435210057132500" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// router/index.ts { path: '/student/:id', name: 'student', component: Student }`, `2360435210057132500`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token comment">// router/index.ts</span> <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">'/student/:id'</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">'student'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Student <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="11038911808553253000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<router-link :to=&quot;{ name: 'student', params: { id: 123 }}&quot;>Student</router-link>`, `11038911808553253000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span> <span class="token attr-name">:to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{ name: 'student', params: { id: 123 }}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Student<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Note that <code class="language-text">:to</code> is shorthand for <code class="language-text">v-bind:to</code>, and you need this since you’re passing an object instead of string.</p> <p>And programmatically:</p> <div class="gatsby-code-button-container" data-toaster-id="99860237814746460000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`this.\$router.push({ name: 'student', params: { id: '123' } })`, `99860237814746460000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'student'</span><span class="token punctuation">,</span> params<span class="token operator">:</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token string">'123'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h2 id="redirects" style="position:relative;"><a href="#redirects" aria-label="redirects permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Redirects</h2> <p>If you want a particular route to be redirected elsewhere, simply add a redirect property to your route:</p> <div class="gatsby-code-button-container" data-toaster-id="90692747188226980000" data-toaster-class="gatsby-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 router = new VueRouter({ routes: [ { path: '/userList', redirect: '/users' } ] }) // or for a named route const router = new VueRouter({ routes: [ { path: '/userList', redirect: { name: 'users' }} ] })`, `90692747188226980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</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">'/userList'</span><span class="token punctuation">,</span> redirect<span class="token operator">:</span> <span class="token string">'/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 comment">// or for a named route</span> <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</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">'/userList'</span><span class="token punctuation">,</span> redirect<span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="passing-props" style="position:relative;"><a href="#passing-props" aria-label="passing props permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Passing props</h2> <p>Coupling your component to <code class="language-text">$router.params</code> is not a good idea. Instead of that you can set the props flag to true and you’ll have route params passed down to your component as props:</p> <p>⛔ Don’t do this:</p> <div class="gatsby-code-button-container" data-toaster-id="98265813851220660000" data-toaster-class="gatsby-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 User = { template: '<div>User {{ \$route.params.id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User } ] })`, `98265813851220660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> User <span class="token operator">=</span> <span class="token punctuation">{</span> template<span class="token operator">:</span> <span class="token string">'&lt;div>User {{ $route.params.id }}&lt;/div>'</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</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">'/user/:id'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> User <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>✅ Instead do:</p> <div class="gatsby-code-button-container" data-toaster-id="37237194783086180000" data-toaster-class="gatsby-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 User = { props: ['id'], template: '<div>User {{ id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true } ] })`, `37237194783086180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> User <span class="token operator">=</span> <span class="token punctuation">{</span> props<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> template<span class="token operator">:</span> <span class="token string">'&lt;div>User {{ id }}&lt;/div>'</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</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">'/user/:id'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> User<span class="token punctuation">,</span> props<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you have an object as props, then use the object as-is instead of setting it to <code class="language-text">true</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="84934204709605690000" data-toaster-class="gatsby-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 router = new VueRouter({ routes: [ { path: '/shop', component: Shop, props: { items: [{ id: 1, name: 'Fancy pants' }] } } ] })`, `84934204709605690000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</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">'/shop'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Shop<span class="token punctuation">,</span> props<span class="token operator">:</span> <span class="token punctuation">{</span> items<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">'Fancy pants'</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can use a function as well:</p> <div class="gatsby-code-button-container" data-toaster-id="45972680465884720000" data-toaster-class="gatsby-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 router = new VueRouter({ routes: [ { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) } ] })`, `45972680465884720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</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">'/search'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> SearchUser<span class="token punctuation">,</span> <span class="token function-variable function">props</span><span class="token operator">:</span> <span class="token punctuation">(</span>route<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span> query<span class="token operator">:</span> route<span class="token punctuation">.</span>query<span class="token punctuation">.</span>q <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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In this case <code class="language-text">/search?q=yas</code> will be passed as <code class="language-text">{ query: 'yas' }</code> to your component props.</p> <h2 id="securing-your-app-using-guards" style="position:relative;"><a href="#securing-your-app-using-guards" aria-label="securing your app using guards permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Securing your app using guards</h2> <p>When you have an application which requires your users to login before performing certain operations, you would like to protect those pages from being seen by unauthenticated users. In this case you could use the <code class="language-text">beforeRouteUpdate</code> lifecylce in your component:</p> <div class="gatsby-code-button-container" data-toaster-id="9492548768231756000" data-toaster-class="gatsby-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 SecuredComponent = { template: \`...\`, beforeRouteEnter (to, from, next) { // check for logged in user }, beforeRouteUpdate (to, from, next) { // check for logged in user }, beforeRouteLeave (to, from, next) { // do something here } }`, `9492548768231756000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> SecuredComponent <span class="token operator">=</span> <span class="token punctuation">{</span> template<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token function">beforeRouteEnter</span> <span class="token punctuation">(</span>to<span class="token punctuation">,</span> from<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// check for logged in user</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function">beforeRouteUpdate</span> <span class="token punctuation">(</span>to<span class="token punctuation">,</span> from<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// check for logged in user</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function">beforeRouteLeave</span> <span class="token punctuation">(</span>to<span class="token punctuation">,</span> from<span class="token punctuation">,</span> next<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// do something here</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The difference between <code class="language-text">beforeRouteEnter</code> and <code class="language-text">beforeRouteUpdate</code> is that you don’t have access to <code class="language-text">this</code> in the former since the component is not initialised yet.</p> <p>In terms of <code class="language-text">beforeRouteUpdate</code>, if you have dynamic route or nested routes, the same component instance will be used when the route is updated.</p> <p>And <code class="language-text">beforeRouteLeave</code> is good if you want to clean up something or clear user sessions and cookies. You still have access to <code class="language-text">this</code> in this method.</p> <p>Apart from lifecycle methods, you can use a global route guard by using <code class="language-text">router.beforeEach</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="28666283405462577000" data-toaster-class="gatsby-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 router = new VueRouter({ ... }) router.beforeEach((to: Route, from: Route, next: Function) => { // implement your logic here })`, `28666283405462577000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</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> router<span class="token punctuation">.</span><span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span>to<span class="token operator">:</span> Route<span class="token punctuation">,</span> from<span class="token operator">:</span> Route<span class="token punctuation">,</span> next<span class="token operator">:</span> <span class="token builtin">Function</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// implement your logic here</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Just note that this will be called for all routes regardless of whether they’re public or not. You can have multiple guards and they will be called in order. As for parameters to these:</p> <ul> <li><code class="language-text">to</code>: is the target route.</li> <li><code class="language-text">from</code>: is the origin route.</li> <li><code class="language-text">next</code>: is a function which should be called to resolve the hook which keeps the navigation in pending state. If you forget to call this function, your route never resoles although your user is authenticated.</li> </ul> <p>For the <code class="language-text">next</code> function you can have no parameters which means go to next hook, or pass false to it like <code class="language-text">next(false)</code> which means abort the current operation. If you want to direct the user to a completely different route, you can add the route as parameter like <code class="language-text">next('/')</code> or <code class="language-text">next({ path: '/' })</code>.</p> <h2 id="meta-fields" style="position:relative;"><a href="#meta-fields" aria-label="meta fields permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Meta fields</h2> <p>You can add meta fields to your route. If you’re wondering why you need meta fields, they’re good for a couple of reasons, but the most obvious one is to tag secure routes to be able to protect then by your global guards:</p> <div class="gatsby-code-button-container" data-toaster-id="91716036009274280000" data-toaster-class="gatsby-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 router = new VueRoute({ routes: [ { path: 'profile', component: Profile, // a meta field meta: { requiresAuth: true } } ] })`, `91716036009274280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRoute</span><span class="token punctuation">(</span><span class="token punctuation">{</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">'profile'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Profile<span class="token punctuation">,</span> <span class="token comment">// a meta field</span> meta<span class="token operator">:</span> <span class="token punctuation">{</span> requiresAuth<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And in your guard:</p> <div class="gatsby-code-button-container" data-toaster-id="98624806097933810000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { // this route requires auth, check if logged in // if not, redirect to login page. if (!auth.loggedIn()) { next({ path: '/login', query: { redirect: to.fullPath } }) } else { next() } } else { next() // make sure to always call next()! } })`, `98624806097933810000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts">router<span class="token punctuation">.</span><span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span>to<span class="token punctuation">,</span> from<span class="token punctuation">,</span> next<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>to<span class="token punctuation">.</span>matched<span class="token punctuation">.</span><span class="token function">some</span><span class="token punctuation">(</span>record <span class="token operator">=></span> record<span class="token punctuation">.</span>meta<span class="token punctuation">.</span>requiresAuth<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// this route requires auth, check if logged in</span> <span class="token comment">// if not, redirect to login page.</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>auth<span class="token punctuation">.</span><span class="token function">loggedIn</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">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> redirect<span class="token operator">:</span> to<span class="token punctuation">.</span>fullPath <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 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 function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// make sure to always call next()!</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="named-views" style="position:relative;"><a href="#named-views" aria-label="named views permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Named views</h2> <p>Sometimes you might want to load multiple views in the same page, such as a navbar, a sidebar, main section, etc. In this case you can use <code class="language-text">router-view</code> to load multiple views instead of nesting them:</p> <div class="gatsby-code-button-container" data-toaster-id="10978114257673499000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<router-view class=&quot;view sidebar&quot;></router-view> <router-view class=&quot;view main&quot; name=&quot;m&quot;></router-view> <router-view class=&quot;view article&quot; name=&quot;a&quot;></router-view>`, `10978114257673499000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</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>view sidebar<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>router-view</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</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>view main<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>m<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>router-view</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</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>view article<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a<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>router-view</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>And in your router:</p> <div class="gatsby-code-button-container" data-toaster-id="97014315644108110000" data-toaster-class="gatsby-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 router = new VueRouter({ routes: [ { path: '/', components: { default: Sidebar, a: Article, m: Main } } ] })`, `97014315644108110000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</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> components<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">default</span><span class="token operator">:</span> Sidebar<span class="token punctuation">,</span> a<span class="token operator">:</span> Article<span class="token punctuation">,</span> m<span class="token operator">:</span> Main <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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Note that we used compoentn(s) instead of component, which is critical in order to load multiple components.</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 so much more you could learn around <strong>Vue</strong> router, and I highly suggest you check <a href="https://router.vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">their official documentation</a> if you’re keen to learn more.</p> <p>I will be doing more articles around <strong>Vue.js</strong> as I explore different areas, so watch this space. Next articles would be state management and form handling which are necessary in most enterprise applications.</p> <p>Hope you’ve enjoyed the read, and if so please spread the word.</p><![CDATA[A comprehensive intro to Vue.js 🔥🚀]]>https://yashints.dev/blog/2019/10/18/vue-introhttps://yashints.dev/blog/2019/10/18/vue-introFri, 18 Oct 2019 00:00:00 GMT<p><a href="https://vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue.js</a> is an approachable, versatile, performant, and progressive framework to build user interfaces with. This core library is focused on building the view layer only. It uses the goodies of <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular</a> (such as template syntax) and <a href="https://reactjs.org/" target="_blank" rel="nofollow noopener noreferrer">React</a> (such as Virtual DOM) and adds a few more enhancements on top.</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>There are many articles out there, but I thought to write this up since it follows my logic of around learning a new framework/library. <strong>Vue</strong> got popular very quick because it adapts to the needs of developers. Another bonus point of it is that migrating to it is really easy. You just need to add a script tag to your page and you’re good to go.</p> <p>You don’t even need to know what is a bundler like <a href="https://webpack.js.org/" target="_blank" rel="nofollow noopener noreferrer">webpack</a>, or an advanced compiler like <a href="https://babeljs.io/" target="_blank" rel="nofollow noopener noreferrer">babel</a> or use a package manager like <code class="language-text">npm</code> to get started with Vue.</p> <p>It does have a <a href="https://cli.vuejs.org" target="_blank" rel="nofollow noopener noreferrer">CLI</a> though which can help you build a fully fledged SPA with a variety of configuration options, including Babel, TypeScript, ESLint, PostCSS, PWA, Unit testing and end-to-end testing.</p> <p>The best thing about its CLI is that you don’t need to eject like <code class="language-text">create-react-app</code> to be able to customise your configuration.</p> <h2 id="get-started" style="position:relative;"><a href="#get-started" aria-label="get started permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Get started</h2> <p>OK, enough talking, let’s get started on our first <strong>Vue</strong> application. I will start with a simplest approach. Let’s create a simple HTML page:</p> <div class="gatsby-code-button-container" data-toaster-id="27351521414001790000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<html> <body> <div id=&quot;my-vue-app&quot;> <p>{{ hello }}</p> </div> <script src=&quot;https://unpkg.com/vue&quot;></script> <script> new Vue({ el: '#my-vue-app', data: { hello: 'Hello World!' } }) </script> </body> </html>`, `27351521414001790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-vue-app<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>p</span><span class="token punctuation">></span></span>{{ hello }}<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>script</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://unpkg.com/vue<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#my-vue-app'</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">hello</span><span class="token operator">:</span> <span class="token string">'Hello World!'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And believe it or not, that’s all you need to have your first <strong>Vue</strong> app up and running. Now let’s break this down and see what’s happening.</p> <p>The first thing you see is a paragraph which has a template reference to a variable called <code class="language-text">hello</code>, like Angular. This means that the value gets replaced by <strong>Vue</strong>. Then we import the script from <code class="language-text">UNPKG</code> which is a CDN (content delivery network) on top of <code class="language-text">npm</code>.</p> <p>Then we in the second script tag, we create a new instance of <strong>Vue</strong> and tell it to use a DOM element with id of <code class="language-text">#my-vue-app</code>. <strong>Vue</strong> will have control over this element and its children. Last we specify a data object with a <code class="language-text">hello</code> property. <strong>Vue</strong> will replace this variable in the template for us. So you should see a page with <code class="language-text">Hello World!</code> when you open this file in a browser.</p> <p>Notice we didn’t use <code class="language-text">this.data.hello</code> to access the variable, that’s because <strong>Vue</strong> will automatically make every property of data accessible like a high level variable.</p> <p>You can see this example live in this CodePen 👇🏼:</p> <iframe height="265" style="width: 100%;" scrolling="no" title="vue-hello-world" src="https://codepen.io/yashints/embed/WNNGYXB?height=265&theme-id=0&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/WNNGYXB'>vue-hello-world</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h2 id="using-cli" style="position:relative;"><a href="#using-cli" aria-label="using 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>Using CLI</h2> <p>Now not all the applications are as simple as our hello world, so we need to get to know the <strong>Vue CLI</strong> which helps up build a complete application from scratch. Open the terminal in your <a href="https://code.visualstudio.com/" target="_blank" rel="nofollow noopener noreferrer">VS Code</a>, navigate to a folder of your choice and run this command:</p> <div class="gatsby-code-button-container" data-toaster-id="16840286703952280000" data-toaster-class="gatsby-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 @vue/cli create my-cli-app`, `16840286703952280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">npx @vue/cli create my-cli-app</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Alternatively you can install it globally:</p> <div class="gatsby-code-button-container" data-toaster-id="57824241794676740000" data-toaster-class="gatsby-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 i -g @vue/cli vue create create my-cli-app`, `57824241794676740000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i <span class="token parameter variable">-g</span> @vue/cli vue create create my-cli-app</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>When you run the command, you will be prompted to choose a preset. You can choose default which is based on <code class="language-text">Babel</code> and <code class="language-text">ESList</code>, or go custom in which case you have more freedom to choose from, like TypeScript, CSS pre-processor, etc.</p> <p>Since the point of this intro is on Vue itself, I won’t delve into details of CLI, please visit <a href="https://cli.vuejs.org" target="_blank" rel="nofollow noopener noreferrer">their official website</a> for more info on how to use CLI.</p> <p>When the creation of the new application is finished, you will end up with a folder structure like this:</p> <p><img src="/29c67a8c97876d5df1cfe7e169b70569/vue-cli-folder-structure.jpg" alt="Vue CLI project folder structure"></p> <p>You don’t need to pay attention to all those files, suffice to know that <code class="language-text">index.html</code> contains the <code class="language-text">div</code> for <strong>Vue</strong> to handle, <code class="language-text">src/main.ts</code> is where <strong>Vue</strong> is instantiated, and <code class="language-text">src/App.vue</code> is a single file components (I will explain this later) which contains our default components.</p> <blockquote> <p><strong>Single File Component:</strong> Single File Component is a file which contains everything a <strong>Vue</strong> component needs, HTML, CSS and JavaScript. You can even scope the style to the component to prevent any unwanted styling clash with other components. In a way it’s similar to what you’ll have with <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" target="_blank" rel="nofollow noopener noreferrer">Shadow DOM</a>.</p> </blockquote> <p>If you have a look at the script tag in the <code class="language-text">App.vue</code> file, you’ll it’s just defining a component which contains another component, <code class="language-text">HelloWorld</code> referenced from another file. Hello world component is another single file component which has one props passed on to it which gets displayed in the template.</p> <p>I will not go any further than this at this point, but you get the idea.</p> <p>To run the app, simply open the type <code class="language-text">npm run serve</code>. You should see a page 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: 93.7037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOElEQVR42pVTzWvUQBTPf+LZk4L/gRf/AxFEVDwIHjxWLyII3gV7KnutRxH0oFKKRXErtks/tvvZbbYmm2w22WSSzPdMsr7NQlhLSu1LeJmZ9/u993szE2O2ZDk8sxlVYrX79cVard092djcfvau9t7ZKaPLZpyZZ/kc8eb485WXD2/fX7l598nV2tNvfqsIZReQF+ljQe7UV6/fe3Dt+eNXvQ+VZSvIYLqo8HHUuLG+cuvT6xPslYouJpeoR/W1t50vlYLPJc/5RZ1+7PosWUzzysqEUsa4kIoLoZQSQlLGpVLgldJgQhYrhecAlBK+Uqosy4y9Znvzx6/9Zvf3XrN7bLZ6g8NOv9np9wbm7sFR47BtjcbmH3vr58737cbu/lHjoAV+Y6s+nvgGJMizHLKiJA1RHCdphJIwmg9gJQgjFKeYsskUgklcYEAOSINGjEUzkALEE8qgCdv1JsHUDyMrDYbxxEReP3LtOBBCAAYAZf9G5W4RQpMUY0IxpQnGlPP/3W040lPH7Zunlju2XA8G42B6CbIvU5rJqcJI0VTzSJJLnDOc3GJ7QDy8lYf8DxluJdeSa5XNckSwaY8Gtm06ztBxZKaYljLT4PNKMtXCIeGExYlkPo95rkJNY80iRRJJXRrFkjo00ktXtVo2GCEsQSlCCVy78zBG+ScSxVPFRCZBAii0Aq81NAeW7acIaw7tQH0AMC3OkmGHA56CZqw4EgQr5osk0oRlMhCpxxCk9igCAERL8l+R1zhMLLYV5AAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Default page of a Vue CLI project" title="" src="/static/a5b4c3acff1270e7dcf508d4aa8d87cf/302a4/vue-default.png" srcset="/static/a5b4c3acff1270e7dcf508d4aa8d87cf/01bf6/vue-default.png 270w, /static/a5b4c3acff1270e7dcf508d4aa8d87cf/07484/vue-default.png 540w, /static/a5b4c3acff1270e7dcf508d4aa8d87cf/302a4/vue-default.png 1080w, /static/a5b4c3acff1270e7dcf508d4aa8d87cf/0d292/vue-default.png 1620w, /static/a5b4c3acff1270e7dcf508d4aa8d87cf/38116/vue-default.png 2086w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <h2 id="vue-root-component" style="position:relative;"><a href="#vue-root-component" aria-label="vue root 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>Vue root component</h2> <p>For now it’s enough about how to get started, let’s deep dive into <strong>Vue</strong>’s building blocks. We should start with its root instance.</p> <div class="gatsby-code-button-container" data-toaster-id="9287150617081096000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`new Vue({ el: '#vue-app', data: { name: 'Yaser' }, computed: { fullName: function() { return this.name + 'Adel'; } }, watch: { name: function(oldVal, newVal) { console.log(\`Name changed from \${oldVal} to \${newVal}\`) } }, methods: { nickName: function() { return this.name === 'Yaser' ? 'Yashints' : 'NA'; } }, created: function() { console.log(\`\${this.name}\`); } ... })`, `9287150617081096000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#vue-app'</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Yaser'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">fullName</span><span class="token operator">:</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">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">+</span> <span class="token string">'Adel'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">watch</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">name</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">oldVal<span class="token punctuation">,</span> newVal</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">Name changed from </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>oldVal<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newVal<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 punctuation">,</span> <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">nickName</span><span class="token operator">:</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">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'Yaser'</span> <span class="token operator">?</span> <span class="token string">'Yashints'</span> <span class="token operator">:</span> <span class="token string">'NA'</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-variable function">created</span><span class="token operator">:</span> <span class="token keyword">function</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 interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>OK, there is a lot going on here, so let’s break them down one by one.</p> <h3 id="el" style="position:relative;"><a href="#el" aria-label="el permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>el</h3> <p>This is the id selector of the element we want <strong>Vue</strong> to use.</p> <h3 id="data" style="position:relative;"><a href="#data" aria-label="data permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>data</h3> <p>This object contains any property you want to maintain in your application. You can get their values in the template, by just using the property name. This just works because <strong>Vue</strong> will automatically make all of the properties accessible at high level <code class="language-text">this</code> context.</p> <h3 id="computed" style="position:relative;"><a href="#computed" aria-label="computed permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>computed</h3> <p>Sometimes you end up having too much logic in your template, take this fictional example:</p> <div class="gatsby-code-button-container" data-toaster-id="95679205246017080000" data-toaster-class="gatsby-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 id=&quot;my-component&quot;> {{ name.split('').reverse().join('') }} </div>`, `95679205246017080000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-component<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{ name.split('').reverse().join('') }} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>In this case when you run the app you will see <code class="language-text">resaY</code>, but having those function calls in the template is not a good practice. You can create a computed property to handle all these logics elsewhere outside of your templates.</p> <div class="gatsby-code-button-container" data-toaster-id="4557405813275595000" data-toaster-class="gatsby-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 vm = new Vue({ el: '#my-component', data: { name: 'Yaser' }, computed: { // a computed getter reversedName: function () { // \`this\` points to the vm instance return this.name.split('').reverse().join('') } } })`, `4557405813275595000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#my-component'</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Yaser'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// a computed getter</span> <span class="token function-variable function">reversedName</span><span class="token operator">:</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 comment">// `this` points to the vm instance</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name<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 function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</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 punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>and in your template, you would just have:</p> <div class="gatsby-code-button-container" data-toaster-id="27036472895281260000" data-toaster-class="gatsby-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 id=&quot;my-component&quot;> {{ reversedName }} </div>`, `27036472895281260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-component<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{ reversedName }} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <blockquote> <p>Be careful with computed properties, these are cached based on the value of the their dependency, which means it will only gets re-evaluated if the value is changed.</p> </blockquote> <p>This means the following code will not return what you think:</p> <div class="gatsby-code-button-container" data-toaster-id="2831390948916668000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`computed: { now: function () { return Date.now() } }`, `2831390948916668000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html">computed: { now: function () { return Date.now() } }</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>That’s because <code class="language-text">Date.now()</code> is not a reactive dependency.</p> <h3 id="methods" style="position:relative;"><a href="#methods" aria-label="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>methods</h3> <p>Methods are simple functions which give you ability to handle events like clicks and input changes. In addition to those, you can use them for many other purposes as well, but the main use case is event handling.</p> <p>You might say we could implement the previous computed property using a method:</p> <div class="gatsby-code-button-container" data-toaster-id="39084233624285970000" data-toaster-class="gatsby-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 id=&quot;my-component&quot;> {{ reversedName() }} </div>`, `39084233624285970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-component<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{ reversedName() }} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <div class="gatsby-code-button-container" data-toaster-id="10849851042273184000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`methods: { reverseName: function () { return this.name.split('').reverse().join('') } }`, `10849851042273184000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">reverseName</span><span class="token operator">:</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">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name<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 function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The end result would be exactly the same, however, the difference is that computed properties are cached based on their corresponding dependency. It means that a computed property only gets re-evaluated when the dependency changes, whereas the method will be called regardless.</p> <p>Methods are ideal to handle events:</p> <div class="gatsby-code-button-container" data-toaster-id="33370639879517962000" data-toaster-class="gatsby-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 id=&quot;app&quot;> <button @click=&quot;sayhi&quot;>Hi</button> <p>{{ message }}</p> </div>`, `33370639879517962000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>app<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">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sayhi<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hi<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>p</span><span class="token punctuation">></span></span>{{ message }}<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And your component will have:</p> <div class="gatsby-code-button-container" data-toaster-id="88486023814279740000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`new Vue({ el: '#app', data() { return { message: null } }, methods: { sayhi() { this.message = 'Hey you!' } } })`, `88486023814279740000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#app'</span><span class="token punctuation">,</span> <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token keyword">null</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">sayhi</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>message <span class="token operator">=</span> <span class="token string">'Hey you!'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>What you haven’t seen so far is the <code class="language-text">@click</code> directive. I will go through directives later in this article, but this is a shorthand for <code class="language-text">v-on:click</code>.</p> <h3 id="lifecycle-hooks" style="position:relative;"><a href="#lifecycle-hooks" aria-label="lifecycle hooks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Lifecycle hooks</h3> <p>The <code class="language-text">created</code> function I defined in the above snippet is just one of many lifecycle hooks you can have access to when working with <strong>Vue</strong>. Think of these as steps each component has to go through when it’s instantiated. Things like data observation, compiling the template, mount the instance to the DOM, update the DOM when data changes, and more.</p> <p>For example, the <code class="language-text">created</code> hook can be used to run a piece of code when the instance is created.</p> <div class="custom-block warning"><div class="custom-block-body">💡 Notice I haven’t used arrow functions with any of my examples so far. That’s because if you use them you lose your access to the component’s context, or <code class="language-text">this</code>. If you happened to face an error like <code class="language-text">Uncaught TypeError: Cannot read property of undefined</code>, or <code class="language-text">Uncaught TypeError: this.myMethod is not a function</code>, it’s because you’ve used an arrow function.</div></div> <p>You can see the full list of available hooks in <a href="https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram" target="_blank" rel="nofollow noopener noreferrer">the official documentation</a>.</p> <h2 id="vue-components" style="position:relative;"><a href="#vue-components" aria-label="vue 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>Vue components</h2> <p>As you saw earlier, <strong>Vue</strong> lets you define components and reuse them much like React does. However, you should know that all of those are reusable instances of the <strong>Vue</strong> itself.</p> <p>You can use the <code class="language-text">component</code> method of <strong>Vue</strong> to define a component:</p> <div class="gatsby-code-button-container" data-toaster-id="20853442071736873000" data-toaster-class="gatsby-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.component('my-name', { /* options */ })`, `20853442071736873000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">Vue<span class="token punctuation">.</span><span class="token function">component</span><span class="token punctuation">(</span><span class="token string">'my-name'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token comment">/* options */</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Since every component is an instance of <strong>Vue</strong>, you can use all of the above properties except for <code class="language-text">el</code>.</p> <p>The first argument is the name of the component, which you will use in your template to add this component to your page.</p> <p>Refer to the <a href="https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name" target="_blank" rel="nofollow noopener noreferrer">W3C rules</a> to find out what naming structure you should use to prevent conflicts with current and future HTML elements.</p> <p>When you use <code class="language-text">Vue.component</code> method, you’re creating global components, which can be used in the template of any root <strong>Vue</strong> instance.</p> <h3 id="local-components" style="position:relative;"><a href="#local-components" aria-label="local 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>Local components</h3> <p>Sometimes you want to have a component which is only accessible within a certain area of your application (for isolation purposes). In this case you could use a local component:</p> <div class="gatsby-code-button-container" data-toaster-id="40681941080181326000" data-toaster-class="gatsby-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 ComponentA = { /* \`... */ }\``, `40681941080181326000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> ComponentA <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">/* `... */</span> <span class="token punctuation">}</span>`</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And then:</p> <div class="gatsby-code-button-container" data-toaster-id="5396599127176760000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`new Vue({ el: '#app', components: { 'component-a': ComponentA } })`, `5396599127176760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#app'</span><span class="token punctuation">,</span> <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'component-a'</span><span class="token operator">:</span> ComponentA <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can have as many local components as you want. The key of each property is the component’s name, and the value will be the options object for that component.</p> <blockquote> <p>💡 Local components are not available in sub-components. But you can make them available by adding them to sub-components explicitly.</p> </blockquote> <p>If you want to make a local component available in a sub-component, just add them explicitly:</p> <div class="gatsby-code-button-container" data-toaster-id="46566546836412860000" data-toaster-class="gatsby-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 ComponentA = { /* \`... */ }\` var ComponentB = { components: { 'component-a': ComponentA }, // ... }`, `46566546836412860000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> ComponentA <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">/* `... */</span> <span class="token punctuation">}</span>` <span class="token keyword">var</span> ComponentB <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'component-a'</span><span class="token operator">:</span> ComponentA <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="props" style="position:relative;"><a href="#props" aria-label="props permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Props</h3> <p>Like other frameworks, <strong>Vue</strong> supports passing props to a component to enable a one way communication from parent to child.</p> <div class="gatsby-code-button-container" data-toaster-id="24131492112701956000" data-toaster-class="gatsby-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.component('search', { // camelCase in JavaScript props: ['searchTerm'], template: \` <span>{{ searchTerm }}</span> <div> ... </div> \` })`, `24131492112701956000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">Vue<span class="token punctuation">.</span><span class="token function">component</span><span class="token punctuation">(</span><span class="token string">'search'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token comment">// camelCase in JavaScript</span> <span class="token literal-property property">props</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'searchTerm'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> &lt;span>{{ searchTerm }}&lt;/span> &lt;div> ... &lt;/div> </span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="gatsby-code-button-container" data-toaster-id="8038024528812126000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<search search-term=&quot;javascript&quot;></search>`, `8038024528812126000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>search</span> <span class="token attr-name">search-term</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>javascript<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>search</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Note that HTML attributes are case-insensitive, this browsers will treat any upper case character as lowercase. So if you’re using camelCased prop names, you need to use their kebab-cased equivalents like above.</p> <p>You can also pass multiple props:</p> <div class="gatsby-code-button-container" data-toaster-id="81899964482907290000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`props: ['searchTerm', 'filter', 'sortOrder']`, `81899964482907290000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">props</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'searchTerm'</span><span class="token punctuation">,</span> <span class="token string">'filter'</span><span class="token punctuation">,</span> <span class="token string">'sortOrder'</span><span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>If you’re using TypeScript, you may want to define the type of each prop, in which case you can use an object instead of an array, where the key is the prop name and the value would be the type:</p> <div class="gatsby-code-button-container" data-toaster-id="88067259094095820000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`props: { searchTerm: String, filter: Number, sortOrder: Boolean, }`, `88067259094095820000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">props</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">searchTerm</span><span class="token operator">:</span> String<span class="token punctuation">,</span> <span class="token literal-property property">filter</span><span class="token operator">:</span> Number<span class="token punctuation">,</span> <span class="token literal-property property">sortOrder</span><span class="token operator">:</span> Boolean<span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can use non primitive types such as <code class="language-text">Array</code>, <code class="language-text">Object</code>, <code class="language-text">Function</code>, <code class="language-text">Promise</code>, etc.</p> <h3 id="single-file-component" style="position:relative;"><a href="#single-file-component" aria-label="single file 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>Single file component</h3> <p>Alright, it’s time to see what are single file components. As I mentioned earlier, they contain everything a component needs:</p> <div class="gatsby-code-button-container" data-toaster-id="2495625183228966400" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// component.vue <template> <p>{{ greeting }} World!</p> </template> <script> module.exports = { data: function () { return { greeting: 'Hello' } } } </script> <style scoped> p { font-size: 2em; text-align: center; } </style>`, `2495625183228966400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html">// component.vue <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</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>{{ greeting }} World!<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>template</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token function-variable function">data</span><span class="token operator">:</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">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">greeting</span><span class="token operator">:</span> <span class="token string">'Hello'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span> <span class="token attr-name">scoped</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"> <span class="token selector">p</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The most important benefits of using single file components are:</p> <ul> <li>Complete syntax highlighting (you will need an extension like <code class="language-text">Vetur</code> for VS Code)</li> <li>CommonJS modules, which means you can import your components into other components using <code class="language-text">require</code></li> <li>Component scoped CSS</li> </ul> <p>You can also use ES6 modules with <code class="language-text">Bug</code>, and <code class="language-text">Babel</code> which you can get setup using the CLI:</p> <div class="gatsby-code-button-container" data-toaster-id="17827019593667770000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<template> <p>{{ greeting }} World!</p> </template> <script> import OtherComponent from './OtherComponent.vue' export default { components: { OtherComponent }, data () { return { greeting: 'Hello' } } } </script> <style scoped> p { font-size: 2em; text-align: center; } </style>`, `17827019593667770000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</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>{{ greeting }} World!<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>template</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">import</span> OtherComponent <span class="token keyword">from</span> <span class="token string">'./OtherComponent.vue'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">{</span> OtherComponent <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function">data</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">greeting</span><span class="token operator">:</span> <span class="token string">'Hello'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span> <span class="token attr-name">scoped</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"> <span class="token selector">p</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="templates" style="position:relative;"><a href="#templates" aria-label="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>Templates</h2> <p>So far we’ve just gone through the <strong>Vue</strong> instance and components. But one of the most important parts of any component is its template. <strong>Vue</strong> uses interpolations for data binding similar to Angular syntax.</p> <div class="gatsby-code-button-container" data-toaster-id="25234060518031320000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<p>Message: {{ msg }}</p>`, `25234060518031320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Message: {{ msg }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The value of the <code class="language-text">msg</code> variable from the <code class="language-text">data</code> object gets replaced at run time.</p> <p>If you want the perform the interpolation just once, use <code class="language-text">v-once</code> directive (we will review the directives shortly):</p> <div class="gatsby-code-button-container" data-toaster-id="39054203720456690000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<p v-once>Message: {{ msg }}</p>`, `39054203720456690000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">v-once</span><span class="token punctuation">></span></span>Message: {{ msg }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>In this case if you change the value of the <code class="language-text">msg</code> later, the template won’t change.</p> <h3 id="raw-html" style="position:relative;"><a href="#raw-html" aria-label="raw html permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Raw HTML</h3> <p>If you want to render raw HTML, you might know that using it in normal interpolation is not recommended mostly because of security reasons. In Angular you would use <code class="language-text">innerHTML</code> attribute and secure it with a pipe with <code class="language-text">DomSanitizer</code>. In React you would use <code class="language-text">&lt;div dangerouslySetInnerHTML={createMarkup()} /></code>. In <strong>Vue</strong> it’s really simple using <code class="language-text">v-html</code> directive:</p> <div class="gatsby-code-button-container" data-toaster-id="37117510866427210000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<p>Using v-html directive: <span v-html=&quot;rawHtml&quot;></span></p>`, `37117510866427210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Using v-html directive: <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">v-html</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rawHtml<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 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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h3 id="attributes" style="position:relative;"><a href="#attributes" aria-label="attributes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Attributes</h3> <p>You can’t use interpolation inside HTML attributes, instead you need to use the <code class="language-text">v-bind</code> directive:</p> <div class="gatsby-code-button-container" data-toaster-id="73843365999010430000" data-toaster-class="gatsby-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-bind:name=&quot;dynamicName&quot;></div>`, `73843365999010430000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-bind:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dynamicName<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <blockquote> <p>💡 If you’re using <code class="language-text">v-bind</code> with boolean attributes like <code class="language-text">disabled</code>, <code class="language-text">v-bind</code> will not include the attribute if the value is <code class="language-text">null</code>, <code class="language-text">undefined</code>, or <code class="language-text">false</code>.</p> </blockquote> <h3 id="js-expressions" style="position:relative;"><a href="#js-expressions" aria-label="js 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>JS expressions</h3> <p>You can use expressions inside data bindings:</p> <div class="gatsby-code-button-container" data-toaster-id="6611668452726738000" data-toaster-class="gatsby-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>{{ number + 1 }}</div> <div>{{ ok ? 'YES' : 'NO' }}</div> <div>{{ message.split('').reverse().join('') }}</div> <div v-bind:id=&quot;'list-' + id&quot;></div>`, `6611668452726738000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span>{{ number + 1 }}<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>{{ ok ? 'YES' : 'NO' }}<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>{{ message.split('').reverse().join('') }}<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"><span class="token namespace">v-bind:</span>id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">'</span>list-' + id<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As I mentioned earlier, don’t use too much logic in your templates, instead use methods or computed properties.</p> <h3 id="directives" style="position:relative;"><a href="#directives" aria-label="directives permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Directives</h3> <p>We saw a couple of directives so far, but <strong>Vue</strong> offers way more. Directives start with <code class="language-text">v-</code>, but some of the most used ones have short hands like <code class="language-text">@click</code> which we saw earlier. Almost all directives’ values are expected to be a <em>single JavaScript expression</em> except <code class="language-text">v-for</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="68479824190284020000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<p v-if=&quot;error&quot;>📛 Something horrible happened!</p>`, `68479824190284020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</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>error<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>📛 Something horrible happened!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h4 id="arguments" style="position:relative;"><a href="#arguments" aria-label="arguments permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Arguments</h4> <p>Some directives take arguments, these are used with a colon after the name:</p> <div class="gatsby-code-button-container" data-toaster-id="44490346977292110000" data-toaster-class="gatsby-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 v-bind:href=&quot;url&quot;> ... </a>`, `44490346977292110000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-bind:</span>href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can even use a dynamic expression as an argument to a directive. But this was only introduced in <strong>v2.6.0</strong>.</p> <div class="gatsby-code-button-container" data-toaster-id="40687140380594910000" data-toaster-class="gatsby-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 v-bind:[attributeName]=&quot;url&quot;> ... </a>`, `40687140380594910000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-bind:</span>[attributeName]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h4 id="modifiers" style="position:relative;"><a href="#modifiers" aria-label="modifiers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Modifiers</h4> <p>Modifiers are postfixes which come after a directive name separated by a <em>dot</em>.</p> <div class="gatsby-code-button-container" data-toaster-id="23603607976355260000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<form v-on:submit.prevent=&quot;onSubmit&quot;> ... </form>`, `23603607976355260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name"><span class="token namespace">v-on:</span>submit.prevent</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>onSubmit<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>form</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>In above code snippet, <code class="language-text">.prevent</code> is a modifier and will cause <code class="language-text">preventDefault()</code> to be called on submit event.</p> <h3 id="css-class-and-style-binding" style="position:relative;"><a href="#css-class-and-style-binding" aria-label="css class and style binding permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CSS class and style binding</h3> <p>In some scenarios, you want to manipulate the class list of an HTML element, or add some inline style to them. You can use <code class="language-text">v-bind</code> to do so.</p> <div class="gatsby-code-button-container" data-toaster-id="53103409135217320000" data-toaster-class="gatsby-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-bind:class=&quot;{ active: isActive }&quot;></div>`, `53103409135217320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-bind:</span>class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{ active: isActive }<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can also add multiple classes at the same time:</p> <div class="gatsby-code-button-container" data-toaster-id="22807580325471834000" data-toaster-class="gatsby-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;message&quot; v-bind:class=&quot;{ active: isActive, 'text-danger': hasError }&quot;> </div>`, `22807580325471834000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>message<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">v-bind:</span>class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{ active: isActive, 'text-danger': hasError }<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>You can use an object instead of using inline expressions:</p> <div class="gatsby-code-button-container" data-toaster-id="87910394213098780000" data-toaster-class="gatsby-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-bind:class=&quot;classObject&quot;></div>`, `87910394213098780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-bind:</span>class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>classObject<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="79710460797781540000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`data: { classObject: { active: true, 'text-danger': false } }`, `79710460797781540000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">classObject</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">active</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string-property property">'text-danger'</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For inline styles, a similar approach can be used, but instead of class, you will use style:</p> <div class="gatsby-code-button-container" data-toaster-id="23717690338581578000" data-toaster-class="gatsby-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-bind:style=&quot;{ color: activeColor, fontSize: fontSize + 'px' }&quot;></div>`, `23717690338581578000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-bind:</span>style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{ color: activeColor, fontSize: fontSize + 'px' }<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can use object as well same as the previous example.</p> <h3 id="conditional-rendering" style="position:relative;"><a href="#conditional-rendering" aria-label="conditional rendering permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conditional rendering</h3> <p>We used <code class="language-text">v-if</code> in one of the previous examples. The HTML block will only get rendered if the expression returns truthy:</p> <div class="gatsby-code-button-container" data-toaster-id="5762875008819624000" data-toaster-class="gatsby-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 v-if=&quot;awesome&quot;>Vue is awesome!</h1>`, `5762875008819624000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</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>awesome<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Vue is awesome!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>But more importantly you can use an else block using <code class="language-text">v-else</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="49541107408773020000" data-toaster-class="gatsby-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 v-if=&quot;awesome&quot;>Vue is awesome!</h1> <h1 v-else>Oh no 😢</h1>`, `49541107408773020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</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>awesome<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Vue is awesome!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">v-else</span><span class="token punctuation">></span></span>Oh no 😢<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>If you want to use v-if on multiple elements which are not nested, you can use <code class="language-text">template</code> element:</p> <div class="gatsby-code-button-container" data-toaster-id="45373726088220300000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<template v-if=&quot;ok&quot;> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>`, `45373726088220300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</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>ok<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>h1</span><span class="token punctuation">></span></span>Title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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>Paragraph 1<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 punctuation">></span></span>Paragraph 2<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>template</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>From version 2.1.0+ you can use a <code class="language-text">v-else-if</code> directive to change a couple of conditions:</p> <div class="gatsby-code-button-container" data-toaster-id="25324240801109975000" data-toaster-class="gatsby-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;type === 'A'&quot;> A </div> <div v-else-if=&quot;type === 'B'&quot;> B </div> <div v-else-if=&quot;type === 'C'&quot;> C </div> <div v-else> Not A/B/C </div>`, `25324240801109975000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>type === 'A'<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> A <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">v-else-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>type === 'B'<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> B <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">v-else-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>type === 'C'<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> C <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">v-else</span><span class="token punctuation">></span></span> Not A/B/C <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><code class="language-text">v-if</code> is not the only conditional directive in <strong>Vue</strong>, you can use a <code class="language-text">v-show</code> as well:</p> <div class="gatsby-code-button-container" data-toaster-id="92318282679833350000" data-toaster-class="gatsby-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 v-show=&quot;ok&quot;>Hello!</h1>`, `92318282679833350000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">v-show</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ok<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The difference is exactly like their Angular counterpart, <code class="language-text">v-show</code> will always render the element and plays with the <code class="language-text">display</code> property.</p> <h3 id="input-binding" style="position:relative;"><a href="#input-binding" aria-label="input binding permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Input binding</h3> <p>You can use <code class="language-text">v-model</code> to create a two way data biding with an input, textarea, or select element:</p> <div class="gatsby-code-button-container" data-toaster-id="56798294088873380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<input v-model=&quot;message&quot; placeholder=&quot;edit me&quot;>`, `56798294088873380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>edit me<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>For <code class="language-text">textarea</code> you can use normal interpolation, you have to use <code class="language-text">v-model</code> instead:</p> <p>❌ This won’t work:</p> <div class="gatsby-code-button-container" data-toaster-id="27885153624821866000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<textarea>{{text}}</textarea>`, `27885153624821866000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span><span class="token punctuation">></span></span>{{text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>textarea</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>✔️ Instead:</p> <div class="gatsby-code-button-container" data-toaster-id="76638341797726080000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<textarea v-model=&quot;message&quot; placeholder=&quot;add multiple lines&quot;></textarea>`, `76638341797726080000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>add multiple lines<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>textarea</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Note that <code class="language-text">v-model</code> will ignore the initial <code class="language-text">value</code>, <code class="language-text">checked</code>, and <code class="language-text">selected</code> attributes you may put on your elements. So use the properties on data object to initialise those.</p> <div class="gatsby-code-button-container" data-toaster-id="19695600179068617000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<input type=&quot;checkbox&quot; id=&quot;checkbox&quot; v-model=&quot;checked&quot;>`, `19695600179068617000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>checkbox<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>checkbox<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>checked<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="67745773271534530000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`//... data: { checked: true }`, `67745773271534530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">//...</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">checked</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>For multiple check boxes you can use an array:</p> <div class="gatsby-code-button-container" data-toaster-id="98956994820458070000" data-toaster-class="gatsby-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 id='example-3'> <input type=&quot;checkbox&quot; id=&quot;jack&quot; value=&quot;Jack&quot; v-model=&quot;checkedNames&quot;> <label for=&quot;jack&quot;>Jack</label> <input type=&quot;checkbox&quot; id=&quot;john&quot; value=&quot;John&quot; v-model=&quot;checkedNames&quot;> <label for=&quot;john&quot;>John</label> <input type=&quot;checkbox&quot; id=&quot;mike&quot; value=&quot;Mike&quot; v-model=&quot;checkedNames&quot;> <label for=&quot;mike&quot;>Mike</label> <br> <span>Checked names: {{ checkedNames }}</span> </div>`, `98956994820458070000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>example-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>input</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>checkbox<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>jack<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Jack<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>checkedNames<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jack<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jack<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>checkbox<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>john<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>John<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>checkedNames<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>john<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>John<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>checkbox<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>mike<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Mike<span class="token punctuation">"</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>checkedNames<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mike<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Mike<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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 punctuation">></span></span>Checked names: {{ checkedNames }}<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>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="17075997384278186000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`new Vue({ el: '#example-3', data: { checkedNames: [] } })`, `17075997384278186000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#example-3'</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">checkedNames</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For select, you can either use a single property (single select), or an array (multi select).</p> <div class="gatsby-code-button-container" data-toaster-id="71510331423622750000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<select v-model=&quot;selected&quot;> <option disabled value=&quot;&quot;>Please select one</option> <option>A</option> <option>B</option> <option>C</option> </select>`, `71510331423622750000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selected<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>option</span> <span class="token attr-name">disabled</span> <span class="token attr-name">value</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>Please select one<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span><span class="token punctuation">></span></span>B<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span><span class="token punctuation">></span></span>C<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For array:</p> <div class="gatsby-code-button-container" data-toaster-id="36914524536392280000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<select v-model=&quot;selected&quot; multiple> <option>A</option> <option>B</option> <option>C</option> </select>`, `36914524536392280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selected<span class="token punctuation">"</span></span> <span class="token attr-name">multiple</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span><span class="token punctuation">></span></span>B<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span><span class="token punctuation">></span></span>C<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="80307437667116100000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`//... data: { selected: [] }`, `80307437667116100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">//...</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">selected</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And lastly, you can use <code class="language-text">v-for</code> if you want to render custom options.</p> <div class="gatsby-code-button-container" data-toaster-id="63613166744433205000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<select v-model=&quot;selected&quot;> <option v-for=&quot;option in options&quot; v-bind:value=&quot;option.value&quot;> {{ option.text }} </option> </select>`, `63613166744433205000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selected<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>option</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>option in options<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">v-bind:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>option.value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{ option.text }} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="rendering-lists" style="position:relative;"><a href="#rendering-lists" aria-label="rendering lists permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Rendering lists</h3> <p>You can use <code class="language-text">v-for</code> directive to render a list of elements. The syntax is <code class="language-text">item in items</code> where items is an array and item is the alias for each entry in the array:</p> <div class="gatsby-code-button-container" data-toaster-id="64014968866672615000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<ul class=&quot;navbar&quot;> <li v-for=&quot;item in items&quot;> <a v-bind:href=&quot;item.href&quot; >{{item.title}}</a> </li> </ul>`, `64014968866672615000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</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>navbar<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>li</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>item in items<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"><span class="token namespace">v-bind:</span>href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>item.href<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span>{{item.title}}<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>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can event loop through an objects properties using <code class="language-text">v-for</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="96929156459034070000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<ul id=&quot;v-for-object&quot; class=&quot;demo&quot;> <li v-for=&quot;value in object&quot;> {{ value }} </li> </ul>`, `96929156459034070000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</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>v-for-object<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>demo<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>li</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>value in object<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{ value }} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And in your component:</p> <div class="gatsby-code-button-container" data-toaster-id="54248104297494180000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`new Vue({ el: '#v-for-object', data: { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } })`, `54248104297494180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#v-for-object'</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">object</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'How to do lists in Vue'</span><span class="token punctuation">,</span> <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">'Jane Doe'</span><span class="token punctuation">,</span> <span class="token literal-property property">publishedAt</span><span class="token operator">:</span> <span class="token string">'2016-04-10'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <blockquote> <p>💡 <strong>Vue</strong> has a different way of handling updates in lists, when the array gets updated, <strong>Vue</strong> uses an in-place patch approach. This means instead of moving DOM nodes, <strong>Vue</strong> will update the items to reflects what should be rendered in place. Because of this, if you’re relying on form input values, or child component state, you need to provide a unique key using <code class="language-text">v-bind:key</code> similar to <code class="language-text">trackBy</code> in Angular.</p> </blockquote> <h2 id="event-handling" style="position:relative;"><a href="#event-handling" aria-label="event handling permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Event handling</h2> <p>Now that we’ve seen the use of directives, it’s time to talk about event handling. This is the last section of this intro 😉.</p> <p>You can use <code class="language-text">v-on</code> to handle events that are happening on your elements.</p> <div class="gatsby-code-button-container" data-toaster-id="35073341943444270000" data-toaster-class="gatsby-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 v-on:click=&quot;counter += 1&quot;>Add 1</button>`, `35073341943444270000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-on:</span>click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>counter += 1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Add 1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can also use methods for handling events:</p> <div class="gatsby-code-button-container" data-toaster-id="23567234700896944000" data-toaster-class="gatsby-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 v-on:click=&quot;greet&quot;>Greet</button>`, `23567234700896944000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-on:</span>click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>greet<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Greet<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="86322447349239600000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`methods: { greet: function (event) { // \`this\` inside methods points to the Vue instance alert('Hello ' + this.name + '!') // \`event\` is the native DOM event if (event) { alert(event.target.tagName) } } }`, `86322447349239600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">greet</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// `this` inside methods points to the Vue instance</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Hello '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">+</span> <span class="token string">'!'</span><span class="token punctuation">)</span> <span class="token comment">// `event` is the native DOM event</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>tagName<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you need to access the original event, simply use <code class="language-text">$event</code> and pass it to the method:</p> <div class="gatsby-code-button-container" data-toaster-id="78962113454632710000" data-toaster-class="gatsby-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 v-on:click=&quot;warn('Form cannot be submitted yet.', \$event)&quot;> Submit </button>`, `78962113454632710000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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"><span class="token namespace">v-on:</span>click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>warn('Form cannot be submitted yet.', $event)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Submit <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="59599930713688830000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// ... methods: { warn: function (message, event) { // now we have access to the native event if (event) event.preventDefault() alert(message) } }`, `59599930713688830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// ...</span> <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">warn</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// now we have access to the native event</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">)</span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token function">alert</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I mentioned modifiers briefly before. Below is the list of modifiers you can use:</p> <ul> <li><code class="language-text">.stop</code></li> <li><code class="language-text">.prevent</code></li> <li><code class="language-text">.capture</code></li> <li><code class="language-text">.self</code></li> <li><code class="language-text">.once</code></li> <li><code class="language-text">.passive</code></li> </ul> <p>But this is outside of scope of this intro. You can <a href="https://vuejs.org/v2/guide/events.html#Event-Modifiers" target="_blank" rel="nofollow noopener noreferrer">find our more 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 all you need to know to get started with <strong>Vue</strong>. There are way more topics than I mentioned here, but I believe you need to start small and as you go on, move towards more advanced scenarios. I will promise I will go through some of those advanced topics like Router, state management, form handling, animation, etc later, so stay tuned.</p><![CDATA[React hooks you should know about 🔥]]>https://yashints.dev/blog/2019/10/06/react-hooks-should-knowhttps://yashints.dev/blog/2019/10/06/react-hooks-should-knowSun, 06 Oct 2019 00:00:00 GMT<p><a href="https://reactjs.org/docs/hooks-overview.html" target="_blank" rel="nofollow noopener noreferrer">React Hooks</a> are somewhat a new addition to React. They allow you to use React features without the need to use a class. But I am not going to go through an introduction in this post, there are many great into posts out there. This post shows you eight hooks and what you can achieve with them.</p> <!--more--> <h2 id="code-classlanguage-textreact-use-form-statecode-hook" style="position:relative;"><a href="#code-classlanguage-textreact-use-form-statecode-hook" aria-label="code classlanguage textreact use form statecode hook permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">react-use-form-state</code> hook</h2> <p>Forms are a very common pattern when it comes to getting information from users. From small to large forms, they all have their own state we have to manage, whether it’s for validation or to populate another input based on previous selection.</p> <p>This hook is a handy tool which allows you simplify managing form’s state using the native HTML input fields.</p> <p>You can install it with:</p> <div class="gatsby-code-button-container" data-toaster-id="22384531289606110000" data-toaster-class="gatsby-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 i react-use-form-state`, `22384531289606110000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i react-use-form-state</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And a simple usage:</p> <div class="gatsby-code-button-container" data-toaster-id="60176824645096730000" data-toaster-class="gatsby-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 { useFormState } from 'react-use-form-state'; export default function SignUpForm({ onSubmit }) { const [formState, { text, email, password, radio }] = useFormState(); function handleSubmit(e) { // ... } return ( <form onSubmit={handleSubmit}> <input {...text('name')} /> <input {...email('email')} required /> <input {...password('password')} required minLength=&quot;8&quot; /> <input {...radio('plan', 'free')} /> <input {...radio('plan', 'premium')} /> </form> ); }`, `60176824645096730000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useFormState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-use-form-state'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SignUpForm</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> onSubmit <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>formState<span class="token punctuation">,</span> <span class="token punctuation">{</span> text<span class="token punctuation">,</span> email<span class="token punctuation">,</span> password<span class="token punctuation">,</span> radio <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useFormState</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">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator">&lt;</span>input <span class="token punctuation">{</span><span class="token operator">...</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>input <span class="token punctuation">{</span><span class="token operator">...</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token string">'email'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> required <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>input <span class="token punctuation">{</span><span class="token operator">...</span><span class="token function">password</span><span class="token punctuation">(</span><span class="token string">'password'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> required minLength<span class="token operator">=</span><span class="token string">"8"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>input <span class="token punctuation">{</span><span class="token operator">...</span><span class="token function">radio</span><span class="token punctuation">(</span><span class="token string">'plan'</span><span class="token punctuation">,</span> <span class="token string">'free'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>input <span class="token punctuation">{</span><span class="token operator">...</span><span class="token function">radio</span><span class="token punctuation">(</span><span class="token string">'plan'</span><span class="token punctuation">,</span> <span class="token string">'premium'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>With this you get a <code class="language-text">json</code> structure like this:</p> <div class="gatsby-code-button-container" data-toaster-id="97128097521836130000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ values: { name: 'Mary Poppins', email: 'mary@example.com', password: '1234', plan: 'free', }, touched: { name: true, email: true, password: true, plan: true, }, validity: { name: true, email: true, password: false, plan: true, }, errors: { password: 'Please lengthen this text to 8 characters or more', }, clear: Function, clearField: Function, reset: Function, resetField: Function, setField: Function, }`, `97128097521836130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">{</span> <span class="token literal-property property">values</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Mary Poppins'</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">'mary@example.com'</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token string">'1234'</span><span class="token punctuation">,</span> <span class="token literal-property property">plan</span><span class="token operator">:</span> <span class="token string">'free'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">touched</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">plan</span><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 literal-property property">validity</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">plan</span><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 literal-property property">errors</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token string">'Please lengthen this text to 8 characters or more'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">clear</span><span class="token operator">:</span> Function<span class="token punctuation">,</span> <span class="token literal-property property">clearField</span><span class="token operator">:</span> Function<span class="token punctuation">,</span> <span class="token literal-property property">reset</span><span class="token operator">:</span> Function<span class="token punctuation">,</span> <span class="token literal-property property">resetField</span><span class="token operator">:</span> Function<span class="token punctuation">,</span> <span class="token literal-property property">setField</span><span class="token operator">:</span> Function<span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It also allow you to initialise it via <code class="language-text">initialState</code> object, a wide variety of on form event handlers, advanced input options, custom input validation, custom controls and much more. Definitely check their <a href="https://github.com/wsmd/react-use-form-state" target="_blank" rel="nofollow noopener noreferrer">GitHub Repo</a> for more information.</p> <h2 id="code-classlanguage-textuse-mediacode" style="position:relative;"><a href="#code-classlanguage-textuse-mediacode" aria-label="code classlanguage textuse mediacode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">use-media</code></h2> <p>This tiny hook is really handy if you’re trying to deliver a responsive user experience. It tracks the state of a CSS media query and lets you act on that.</p> <p>With <code class="language-text">useEffect</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="1379279847509984300" data-toaster-class="gatsby-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 useMedia from 'use-media'; // Alternatively, you can import as: // import {useMedia} from 'use-media'; const Demo = () => { // Accepts an object of features to test const isWide = useMedia({minWidth: 1000}); // Or a regular media query string const reduceMotion = useMedia('(prefers-reduced-motion: reduce)'); return ( <div> Screen is wide: {isWide ? '😃' : '😢'} </div> ); };`, `1379279847509984300`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> useMedia <span class="token keyword">from</span> <span class="token string">'use-media'</span><span class="token punctuation">;</span> <span class="token comment">// Alternatively, you can import as:</span> <span class="token comment">// import {useMedia} from 'use-media';</span> <span class="token keyword">const</span> <span class="token function-variable function">Demo</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 comment">// Accepts an object of features to test</span> <span class="token keyword">const</span> isWide <span class="token operator">=</span> <span class="token function">useMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">minWidth</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Or a regular media query string</span> <span class="token keyword">const</span> reduceMotion <span class="token operator">=</span> <span class="token function">useMedia</span><span class="token punctuation">(</span><span class="token string">'(prefers-reduced-motion: reduce)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> Screen is wide<span class="token operator">:</span> <span class="token punctuation">{</span>isWide <span class="token operator">?</span> <span class="token string">'😃'</span> <span class="token operator">:</span> <span class="token string">'😢'</span><span class="token punctuation">}</span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>With <code class="language-text">useLayoutEffect</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="80165352956718680000" data-toaster-class="gatsby-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 {useMediaLayout} from 'use-media'; const Demo = () => { // Accepts an object of features to test const isWide = useMediaLayout({minWidth: 1000}); // Or a regular media query string const reduceMotion = useMediaLayout('(prefers-reduced-motion: reduce)'); return ( <div> Screen is wide: {isWide ? '😃' : '😢'} </div> ); };`, `80165352956718680000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span>useMediaLayout<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'use-media'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">Demo</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 comment">// Accepts an object of features to test</span> <span class="token keyword">const</span> isWide <span class="token operator">=</span> <span class="token function">useMediaLayout</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">minWidth</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Or a regular media query string</span> <span class="token keyword">const</span> reduceMotion <span class="token operator">=</span> <span class="token function">useMediaLayout</span><span class="token punctuation">(</span><span class="token string">'(prefers-reduced-motion: reduce)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> Screen is wide<span class="token operator">:</span> <span class="token punctuation">{</span>isWide <span class="token operator">?</span> <span class="token string">'😃'</span> <span class="token operator">:</span> <span class="token string">'😢'</span><span class="token punctuation">}</span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For more information about this nifty little hook, visit <a href="https://github.com/streamich/use-media" target="_blank" rel="nofollow noopener noreferrer">this GitHub repo</a>.</p> <h2 id="code-classlanguage-textreact-firebase-hookscode" style="position:relative;"><a href="#code-classlanguage-textreact-firebase-hookscode" aria-label="code classlanguage textreact firebase hookscode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">react-firebase-hooks</code></h2> <p>I don’t have to tell you how great firebase is, but what if you could use a set of hooks to easily integrate with it? It’s got 4 set of hooks for you to use:</p> <ul> <li><a href="https://github.com/CSFrequency/react-firebase-hooks/tree/master/auth" target="_blank" rel="nofollow noopener noreferrer">Auth Hooks</a></li> <li><a href="https://github.com/CSFrequency/react-firebase-hooks/tree/master/firestore" target="_blank" rel="nofollow noopener noreferrer">Cloud Firestore Hooks</a></li> <li><a href="https://github.com/CSFrequency/react-firebase-hooks/tree/master/storage" target="_blank" rel="nofollow noopener noreferrer">Cloud Storage Hooks</a></li> <li><a href="https://github.com/CSFrequency/react-firebase-hooks/tree/master/database" target="_blank" rel="nofollow noopener noreferrer">Realtime Database Hooks</a></li> </ul> <p>Usage:</p> <div class="gatsby-code-button-container" data-toaster-id="38084276753995000000" data-toaster-class="gatsby-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 { useAuthState } from 'react-firebase-hooks/auth'; const CurrentUser = () => { const [user, initialising, error] = useAuthState(firebase.auth()); const login = () => { firebase.auth().signInWithEmailAndPassword('test@test.com', 'password'); }; const logout = () => { firebase.auth().signOut(); }; if (initialising) { return ( <div> <p>Initialising User...</p> </div> ); } if (error) { return ( <div> <p>Error: {error}</p> </div> ); } if (user) { return ( <div> <p>Current User: {user.email}</p> <button onClick={logout}>Log out</button> </div> ); } return <button onClick={login}>Log in</button>; };`, `38084276753995000000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useAuthState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-firebase-hooks/auth'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">CurrentUser</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">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> initialising<span class="token punctuation">,</span> error<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useAuthState</span><span class="token punctuation">(</span>firebase<span class="token punctuation">.</span><span class="token function">auth</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> <span class="token function-variable function">login</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> firebase<span class="token punctuation">.</span><span class="token function">auth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">signInWithEmailAndPassword</span><span class="token punctuation">(</span><span class="token string">'test@test.com'</span><span class="token punctuation">,</span> <span class="token string">'password'</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> <span class="token function-variable function">logout</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> firebase<span class="token punctuation">.</span><span class="token function">auth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">signOut</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>initialising<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>p<span class="token operator">></span>Initialising User<span class="token operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></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>error<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>p<span class="token operator">></span>Error<span class="token operator">:</span> <span class="token punctuation">{</span>error<span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></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>user<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>p<span class="token operator">></span>Current User<span class="token operator">:</span> <span class="token punctuation">{</span>user<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>logout<span class="token punctuation">}</span><span class="token operator">></span>Log out<span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>login<span class="token punctuation">}</span><span class="token operator">></span>Log <span class="token keyword">in</span><span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Of course you don’t hard code your username and password right? 😁</p> <p>Find out more <a href="https://github.com/CSFrequency/react-firebase-hooks" target="_blank" rel="nofollow noopener noreferrer">here</a>.</p> <h2 id="code-classlanguage-textuse-onclickoutsidecode-hook" style="position:relative;"><a href="#code-classlanguage-textuse-onclickoutsidecode-hook" aria-label="code classlanguage textuse onclickoutsidecode hook permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">use-onClickOutside</code> hook</h2> <p>Many times has happened for me to need to be aware of when the user clicks outside of an element. This might be to change something or perform an action. This little hook allows you to do exactly that:</p> <div class="gatsby-code-button-container" data-toaster-id="19939656522946470000" data-toaster-class="gatsby-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 * as React from 'react' import useOnClickOutside from 'use-onclickoutside' export default function Modal({ close }) { const ref = React.useRef(null) useOnClickOutside(ref, close) return <div ref={ref}>{'Modal content'}</div> }`, `19939656522946470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> useOnClickOutside <span class="token keyword">from</span> <span class="token string">'use-onclickoutside'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Modal</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> close <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> ref <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token function">useOnClickOutside</span><span class="token punctuation">(</span>ref<span class="token punctuation">,</span> close<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>div ref<span class="token operator">=</span><span class="token punctuation">{</span>ref<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token string">'Modal content'</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see, you can provide a ref to an element and pass it to the hook. If there is a click anywhere outside of the element, the the call-back function, in this case <code class="language-text">close</code> is called.</p> <p>Find out more about this hook <a href="https://github.com/Andarist/use-onclickoutside" target="_blank" rel="nofollow noopener noreferrer">in this GitHub repo</a>.</p> <h2 id="code-classlanguage-textuseintersectionobservercode-hook" style="position:relative;"><a href="#code-classlanguage-textuseintersectionobservercode-hook" aria-label="code classlanguage textuseintersectionobservercode hook permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">useIntersectionObserver</code> hook</h2> <p>You might remember I did a <a href="https://yashints.dev/blog/2018/11/12/web-perf-4" target="_blank" rel="nofollow noopener noreferrer">post on image optimisation</a> and how <code class="language-text">IntersectionObserver</code> API is a handy tool to load an image lazily when it appears on viewport.</p> <p>This hook allows you to use this great API:</p> <div class="gatsby-code-button-container" data-toaster-id="19812755324002440000" data-toaster-class="gatsby-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 React, { useRef, useState } from &quot;react&quot;; import { useIntersectionObserver } from &quot;react-hook-intersection-observer&quot;; const App = () => { const root = useRef(); // We need a ref to our &quot;root&quot; or our parent, const target = useRef(); // We need a ref to our &quot;target&quot; or our child-to-watch, // Let's use a bit of state. const [isThingIntersecting, setThingIntersecting] = useState(false); // Here's our hook! Let's give it some configuration... useIntersectionObserver({ root, target, // What do we do when it intersects? // The signature of this callback is (collectionOfIntersections, observerElement). onIntersect: ([{ isIntersecting }]) => setThingIntersecting(isIntersecting) }); return ( <div className=&quot;App&quot;> <h1>useIntersectionObserver</h1> <h2> The thing is currently{&quot; &quot;} {!isThingIntersecting && <span style={{ color: &quot;red&quot; }}>not</span>}{&quot; &quot;} <span style={{ color: isThingIntersecting ? &quot;green&quot; : &quot;black&quot; }}> intersecting </span> ! </h2> <div ref={root} className=&quot;black-box&quot;> <div className=&quot;larger-box&quot;> <div ref={target}>THE THING</div> </div> </div> </div> ); };`, `19812755324002440000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useRef<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useIntersectionObserver <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-hook-intersection-observer"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">App</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">const</span> root <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// We need a ref to our "root" or our parent,</span> <span class="token keyword">const</span> target <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// We need a ref to our "target" or our child-to-watch,</span> <span class="token comment">// Let's use a bit of state.</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>isThingIntersecting<span class="token punctuation">,</span> setThingIntersecting<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Here's our hook! Let's give it some configuration...</span> <span class="token function">useIntersectionObserver</span><span class="token punctuation">(</span><span class="token punctuation">{</span> root<span class="token punctuation">,</span> target<span class="token punctuation">,</span> <span class="token comment">// What do we do when it intersects?</span> <span class="token comment">// The signature of this callback is (collectionOfIntersections, observerElement).</span> <span class="token function-variable function">onIntersect</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">[</span><span class="token punctuation">{</span> isIntersecting <span class="token punctuation">}</span><span class="token punctuation">]</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setThingIntersecting</span><span class="token punctuation">(</span>isIntersecting<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> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator">&lt;</span>h1<span class="token operator">></span>useIntersectionObserver<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator">&lt;</span>h2<span class="token operator">></span> The thing is currently<span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token operator">!</span>isThingIntersecting <span class="token operator">&amp;&amp;</span> <span class="token operator">&lt;</span>span style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token string">"red"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span>not<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span> <span class="token operator">&lt;</span>span style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">color</span><span class="token operator">:</span> isThingIntersecting <span class="token operator">?</span> <span class="token string">"green"</span> <span class="token operator">:</span> <span class="token string">"black"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> intersecting <span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">!</span> <span class="token operator">&lt;</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator">&lt;</span>div ref<span class="token operator">=</span><span class="token punctuation">{</span>root<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"black-box"</span><span class="token operator">></span> <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"larger-box"</span><span class="token operator">></span> <span class="token operator">&lt;</span>div ref<span class="token operator">=</span><span class="token punctuation">{</span>target<span class="token punctuation">}</span><span class="token operator">></span><span class="token constant">THE</span> <span class="token constant">THING</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>To find out more, have a look at <a href="https://github.com/TejasQ/react-hook-intersection-observer" target="_blank" rel="nofollow noopener noreferrer">this GitHub repo</a>.</p> <h2 id="react-use-collection" style="position:relative;"><a href="#react-use-collection" aria-label="react use collection permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>react use collection</h2> <p>This is a collection of some great hooks you can use in categories like <strong>Sensors</strong>, <strong>UI</strong>, <strong>Animations</strong>, <strong>Side-effects</strong>, <strong>Lifecycles</strong>, and <strong>State</strong>.</p> <p>An example is <code class="language-text">useLocation</code> which gives you the ability to access the location of the browser.</p> <div class="gatsby-code-button-container" data-toaster-id="75228831225499450000" data-toaster-class="gatsby-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 {useLocation} from 'react-use'; const Demo = () => { const state = useLocation(); return ( <pre> {JSON.stringify(state, null, 2)} </pre> ); };`, `75228831225499450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span>useLocation<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-use'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">Demo</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">const</span> state <span class="token operator">=</span> <span class="token function">useLocation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>pre<span class="token operator">></span> <span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">&lt;</span><span class="token operator">/</span>pre<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you’re using Internet Explorer (but why 😂), you can use <a href="https://github.com/streamich/react-use/issues/73" target="_blank" rel="nofollow noopener noreferrer">this polyfill</a>.</p> <p>Or you can use <code class="language-text">useBattery</code> to track the battery status on a mobile device:</p> <div class="gatsby-code-button-container" data-toaster-id="52623193925467530000" data-toaster-class="gatsby-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 {useBattery} from 'react-use'; const Demo = () => { const batteryState = useBattery(); if (!batteryState.isSupported) { return ( <div> <strong>Battery sensor</strong>: <span>not supported</span> </div> ); } if (!batteryState.fetched) { return ( <div> <strong>Battery sensor</strong>: <span>supported</span> <br /> <strong>Battery state</strong>: <span>fetching</span> </div> ); } return ( <div> <strong>Battery sensor</strong>:&nbsp;&nbsp; <span>supported</span> <br /> <strong>Battery state</strong>: <span>fetched</span> <br /> <strong>Charge level</strong>:&nbsp;&nbsp; <span>{ (batteryState.level * 100).toFixed(0) }%</span> <br /> <strong>Charging</strong>:&nbsp;&nbsp; <span>{ batteryState.charging ? 'yes' : 'no' }</span> <br /> <strong>Charging time</strong>:&nbsp;&nbsp; <span>{ batteryState.chargingTime ? batteryState.chargingTime : 'finished' }</span> <br /> <strong>Discharging time</strong>:&nbsp;&nbsp; <span>{ batteryState.dischargingTime }</span> </div> ); };`, `52623193925467530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span>useBattery<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-use'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">Demo</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">const</span> batteryState <span class="token operator">=</span> <span class="token function">useBattery</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>batteryState<span class="token punctuation">.</span>isSupported<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Battery sensor<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span> <span class="token operator">&lt;</span>span<span class="token operator">></span>not supported<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></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>batteryState<span class="token punctuation">.</span>fetched<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Battery sensor<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span> <span class="token operator">&lt;</span>span<span class="token operator">></span>supported<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Battery state<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span> <span class="token operator">&lt;</span>span<span class="token operator">></span>fetching<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Battery sensor<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span> <span class="token operator">&lt;</span>span<span class="token operator">></span>supported<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Battery state<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span> <span class="token operator">&lt;</span>span<span class="token operator">></span>fetched<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Charge level<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span> <span class="token operator">&lt;</span>span<span class="token operator">></span><span class="token punctuation">{</span> <span class="token punctuation">(</span>batteryState<span class="token punctuation">.</span>level <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token operator">%</span><span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Charging<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span> <span class="token operator">&lt;</span>span<span class="token operator">></span><span class="token punctuation">{</span> batteryState<span class="token punctuation">.</span>charging <span class="token operator">?</span> <span class="token string">'yes'</span> <span class="token operator">:</span> <span class="token string">'no'</span> <span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Charging time<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span> <span class="token operator">&lt;</span>span<span class="token operator">></span><span class="token punctuation">{</span> batteryState<span class="token punctuation">.</span>chargingTime <span class="token operator">?</span> batteryState<span class="token punctuation">.</span>chargingTime <span class="token operator">:</span> <span class="token string">'finished'</span> <span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>Discharging time<span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">:</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span><span class="token operator">&amp;</span>nbsp<span class="token punctuation">;</span> <span class="token operator">&lt;</span>span<span class="token operator">></span><span class="token punctuation">{</span> batteryState<span class="token punctuation">.</span>dischargingTime <span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>To find out about all of those, check <a href="https://github.com/streamich/react-use" target="_blank" rel="nofollow noopener noreferrer">this GitHub repo</a>.</p> <h2 id="react-redux-hooks" style="position:relative;"><a href="#react-redux-hooks" aria-label="react redux hooks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>React Redux hooks</h2> <p>React Redux now offers a set of hook APIs as an alternative to the existing <code class="language-text">connect()</code> Higher Order Component. These APIs allow you to subscribe to the Redux store and dispatch actions, without having to wrap your components in <code class="language-text">connect()</code>.</p> <p>Here is the <code class="language-text">useSelector</code> hook returns a part of all of store using a selector function.</p> <div class="gatsby-code-button-container" data-toaster-id="13520388526068361000" data-toaster-class="gatsby-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 React from 'react' import { useSelector } from 'react-redux' export const CounterComponent = () => { const counter = useSelector(state => state.counter) return <div>{counter}</div> }`, `13520388526068361000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useSelector <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-redux'</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">CounterComponent</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">const</span> counter <span class="token operator">=</span> <span class="token function">useSelector</span><span class="token punctuation">(</span><span class="token parameter">state</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>counter<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">></span><span class="token punctuation">{</span>counter<span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Checkout <a href="https://react-redux.js.org/next/api/hooks" target="_blank" rel="nofollow noopener noreferrer">their comprehensive documentation</a> to find out more.</p> <h2 id="react-hanger" style="position:relative;"><a href="#react-hanger" aria-label="react hanger permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>react-hanger</h2> <p>A set of helpful hooks with focus on primitive types state changing. They have two version, but the recommendation is to use V2.</p> <p>Install:</p> <div class="gatsby-code-button-container" data-toaster-id="59397211491391210000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`yarn add react-hanger`, `59397211491391210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">yarn</span> <span class="token function">add</span> react-hanger</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Usage:</p> <div class="gatsby-code-button-container" data-toaster-id="10090287182298563000" data-toaster-class="gatsby-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 React, { Component } from &quot;react&quot;; import { useInput, useBoolean, useNumber, useArray, useOnMount, useOnUnmount } from &quot;react-hanger&quot;; const App = () => { const newTodo = useInput(&quot;&quot;); const showCounter = useBoolean(true); const limitedNumber = useNumber(3, { lowerLimit: 0, upperLimit: 5 }); const counter = useNumber(0); const todos = useArray([&quot;hi there&quot;, &quot;sup&quot;, &quot;world&quot;]); const rotatingNumber = useNumber(0, { lowerLimit: 0, upperLimit: 4, loop: true }); return ( <div> <button onClick={showCounter.toggle}> toggle counter </button> <button onClick={() => counter.increase()}> increase </button> {showCounter.value && <span> {counter.value} </span>} <button onClick={() => counter.decrease()}> decrease </button> <button onClick={todos.clear}> clear todos </button> <input type=&quot;text&quot; value={newTodo.value} onChange={newTodo.onChange} /> </div> ); };`, `10090287182298563000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useInput<span class="token punctuation">,</span> useBoolean<span class="token punctuation">,</span> useNumber<span class="token punctuation">,</span> useArray<span class="token punctuation">,</span> useOnMount<span class="token punctuation">,</span> useOnUnmount <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-hanger"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">App</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">const</span> newTodo <span class="token operator">=</span> <span class="token function">useInput</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> showCounter <span class="token operator">=</span> <span class="token function">useBoolean</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> limitedNumber <span class="token operator">=</span> <span class="token function">useNumber</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 literal-property property">lowerLimit</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">upperLimit</span><span class="token operator">:</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 keyword">const</span> counter <span class="token operator">=</span> <span class="token function">useNumber</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">useArray</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"hi there"</span><span class="token punctuation">,</span> <span class="token string">"sup"</span><span class="token punctuation">,</span> <span class="token string">"world"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> rotatingNumber <span class="token operator">=</span> <span class="token function">useNumber</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">lowerLimit</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">upperLimit</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token literal-property property">loop</span><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 keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>showCounter<span class="token punctuation">.</span>toggle<span class="token punctuation">}</span><span class="token operator">></span> toggle counter <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> counter<span class="token punctuation">.</span><span class="token function">increase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> increase <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token punctuation">{</span>showCounter<span class="token punctuation">.</span>value <span class="token operator">&amp;&amp;</span> <span class="token operator">&lt;</span>span<span class="token operator">></span> <span class="token punctuation">{</span>counter<span class="token punctuation">.</span>value<span class="token punctuation">}</span> <span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> counter<span class="token punctuation">.</span><span class="token function">decrease</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> decrease <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator">&lt;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>todos<span class="token punctuation">.</span>clear<span class="token punctuation">}</span><span class="token operator">></span> clear todos <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator">&lt;</span>input type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>newTodo<span class="token punctuation">.</span>value<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>newTodo<span class="token punctuation">.</span>onChange<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can play with these in <a href="https://codesandbox.io/s/44m70xm70" target="_blank" rel="nofollow noopener noreferrer">this CodeSandbox</a>.</p> <p>Check <a href="https://github.com/kitze/react-hanger" target="_blank" rel="nofollow noopener noreferrer">this GitHub repo</a> for more 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>I was surprised to find out how many hooks have already being developed by the community to be honest. There are so many and I can’t go through all of them here. But if you’re hungry for more, check <a href="https://github.com/rehooks/awesome-react-hooks" target="_blank" rel="nofollow noopener noreferrer">this gem</a> I found which has a collection of tools, hooks, tutorials, videos, podcasts, and more.</p><![CDATA[Send performance metrics from client side with Navigation Timing API ⚡]]>https://yashints.dev/blog/2019/09/29/navigation-timinghttps://yashints.dev/blog/2019/09/29/navigation-timingSun, 29 Sep 2019 00:00:00 GMT<p>Everybody likes a fast loading web page. In fact, Google has an <a href="https://developers.google.com/web/fundamentals/performance/why-performance-matters/" target="_blank" rel="nofollow noopener noreferrer">entire section</a> dedicated to performance and how companies are moving towards a faster web. Wouldn’t it be good if we could measure some critical metrics like page load time in our production environment and constantly monitor them to find out where can be improved?</p> <!--more--> <h2 id="navigation-timing-api" style="position:relative;"><a href="#navigation-timing-api" aria-label="navigation timing 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>Navigation Timing API</h2> <p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API" target="_blank" rel="nofollow noopener noreferrer">Navigation Timing API</a> is a JavaScript API which can be used to accurately measure performance on the client side. This data can then be transmitted to server side to allow real time monitoring of performance metrics.</p> <p>The API provides a simple way to natively get accurate and detailed timing statistics for page navigation and load events. Metrics such as page load time, amount of time needed to unload the previous page, how long domain lookups take and so on can be measured by this API.</p> <h2 id="how-to-use-it" style="position:relative;"><a href="#how-to-use-it" aria-label="how to use 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 to use it?</h2> <p>This API has two interfaces, <code class="language-text">Performance</code> and <code class="language-text">PerformanceNavigationTiming</code>. The <code class="language-text">window.performance</code> property returns a <code class="language-text">Performance</code> interface which is defined by <a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance_API" target="_blank" rel="nofollow noopener noreferrer">High Resolution API</a>, plus two additional properties:</p> <ul> <li><strong>timing</strong>: data for navigation and page load events.</li> <li><strong>navigation</strong>: how the user navigated to the page.</li> </ul> <p>You can try this API in the browser’s console (pressing <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> for Chrome on Windows or <kbd>CMD</kbd>+<kbd>Option</kbd>+<kbd>J</kbd> for Mac users):</p> <div class="gatsby-code-button-container" data-toaster-id="25719967609349670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`> performance`, `25719967609349670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token operator">></span> performance</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And you will see an object like this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; " > <a class="gatsby-resp-image-link" href="/static/972374f6a070878ffaa1b7167327969e/41099/performance.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 35.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAHABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABy4AH/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFxABAQEBAAAAAAAAAAAAAAAAAQAhYf/aAAgBAQABPyE0JeEt/9oADAMBAAIAAwAAABDwD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExQYH/2gAIAQEAAT8QdBBo7A54TJon/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Performance object in browser console" title="" src="/static/972374f6a070878ffaa1b7167327969e/41099/performance.jpg" srcset="/static/972374f6a070878ffaa1b7167327969e/6f81f/performance.jpg 270w, /static/972374f6a070878ffaa1b7167327969e/41099/performance.jpg 500w" sizes="(max-width: 500px) 100vw, 500px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="better-alternative-to-code-classlanguage-textdatecode-object" style="position:relative;"><a href="#better-alternative-to-code-classlanguage-textdatecode-object" aria-label="better alternative to code classlanguage textdatecode 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>Better alternative to <code class="language-text">Date</code> object</h2> <p>Historically, we’ve used <code class="language-text">Date</code> object for timing metrics like:</p> <div class="gatsby-code-button-container" data-toaster-id="49040940299491660000" data-toaster-class="gatsby-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 start = Date.now();`, `49040940299491660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> start <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And at the end of the page:</p> <div class="gatsby-code-button-container" data-toaster-id="28661173070544610000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`console.log(\`It took: \${Date.now() - start} ms for the page to load!\`);`, `28661173070544610000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">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">It took: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> start<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ms for the page to load!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>However, this is very inefficient because of a couple of reasons. First, the timing code is on the page which takes time itself and affects performance. Besides, you should know that JavaScript time is <a href="https://johnresig.com/blog/accuracy-of-javascript-time/" target="_blank" rel="nofollow noopener noreferrer">not accurate</a>. Furthermore, it wouldn’t be close to what users experienced it, and worst of all, you can’t use <code class="language-text">Date</code> object, to measure network latency before the page started loading.</p> <p>If you think of events which happen before the page even begins to load such as DNS resolution, redirects and server response time, technically you can’t measure these by inline code since your code hasn’t arrived yet.</p> <h2 id="navigation-timing-api-ftw" style="position:relative;"><a href="#navigation-timing-api-ftw" aria-label="navigation timing api ftw permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Navigation Timing API FTW</h2> <p>Each of the properties of of <code class="language-text">performance.timing</code> shows the time of navigation events such as when the page was requested 👉🏼 <code class="language-text">requestStart</code> or page load events such as when the DOM began loading 👉🏼 <code class="language-text">domLoading</code> in milliseconds since the midnight of Jan 1, 1970 UTC.</p> <p>💡 A <code class="language-text">zero</code> value means that the event didn’t occur. Events such as <code class="language-text">redirectStart</code> or <code class="language-text">secureConnectionStart</code> might not happen at all.</p> <p>For more information on these events, you can have a look at the <a href="https://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface" target="_blank" rel="nofollow noopener noreferrer">W3C Recommendation</a>.</p> <p>You can see the order of these events from the picture below from the above document:</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/7e63b0174961f257d375e7f12ca790fe/0c156/timing-overview.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 59.62962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABcSAAAXEgFnn9JSAAACqklEQVR42pWTf0hTURTHr23TKbOZPyr7IwoSZBAGwzAR/DMLM/95f5iIoDVlYqVlURH3j8AUEpNSm0utNpUeUUGohbops/ee+va2ptt7Ph22dKgxlYGQj4jXvVpRUKEXDvdxz7kfvufc7wPgt2UwsSoA9DGcd/aUk3OuCILwUZblYziH9l1gpyszrz42Pb82gYBkvJPzNPI8/02SpKHwxkYKAkajiMCxLVh2NlSmF9Um4MitNiXqCKhhOF9BcGFhfnFxUQ6FQr0Ipt622rTixrjMEqQQAfG33lCnBTpCc6eNPOzj+f6VUEheWlpyra6uXkJA5Q/w39Xq9SZVKmoVqVTrC+CmOtx6ftGDBAByY+w0f4geY9sDgcB6OByeX1tbK0Ww5H8qPVHespeoI7XHC+HutLMwTpdt1CDo/tSTN5PRHolKFBCN5PXo6AG3e+q23z/Xtv5FKl1eXtbg+yRJKux2uxIHaHn73tM65Bywjnkd5mE3ax7huDYbN4HO6CcMz3RNeH3d3Iyvh/UJndQk1e2eG+lxic5nzKTnpTfg6XYKsxba019FUtGb6u69shms7Ky51/9ZemRzV5sGmbJOii/vGJ08j4BlCHbFMi5efu7yV1nHhYoOh/eqZWz6loXha6zj0zeabR+uPaV9FwYo6uinmZkjm9D7b7iU1gFXYTHsVG8N4b/WwDkFAESk3mBSGY0PNYKXrxVFETvBAXDfEG4N1wBNMcR1k/bMRfO+nMr2JGwfIyQ1TX1iFCnLCvwIuL4AdiUCUKxmOFHnmfLakV/X0TyHUf4g+Pn8+MIfvoRQmUE0RCMV2ozShvisc3f3YFvh88ySx7Ev+oZO87wgBoPBja+S1IwYqh38Q3JETmVTVF5NfSxIMmoc7FQWTVPvkCoWgSp+VclyxHece32TjXQUigAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Order of navigation events" title="" src="/static/7e63b0174961f257d375e7f12ca790fe/302a4/timing-overview.png" srcset="/static/7e63b0174961f257d375e7f12ca790fe/01bf6/timing-overview.png 270w, /static/7e63b0174961f257d375e7f12ca790fe/07484/timing-overview.png 540w, /static/7e63b0174961f257d375e7f12ca790fe/302a4/timing-overview.png 1080w, /static/7e63b0174961f257d375e7f12ca790fe/0c156/timing-overview.png 1473w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="some-use-cases" style="position:relative;"><a href="#some-use-cases" aria-label="some 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>Some use cases</h2> <p>Now let’s have a look at how we can calculate some metrics using these useful properties.</p> <h3 id="total-page-load-time" style="position:relative;"><a href="#total-page-load-time" aria-label="total page load time permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Total page load time</h3> <p>In order to calculate the total page load time, you can use the <code class="language-text">loadEventEnd</code> and <code class="language-text">navigationStart</code> properties:</p> <div class="gatsby-code-button-container" data-toaster-id="48868611911626990000" data-toaster-class="gatsby-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 perfObj = window.performance.timing; let pageLoadTime = perfObj.loadEventEnd - perfObj.navigationStart;`, `48868611911626990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> perfObj <span class="token operator">=</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>timing<span class="token punctuation">;</span> <span class="token keyword">let</span> pageLoadTime <span class="token operator">=</span> perfObj<span class="token punctuation">.</span>loadEventEnd <span class="token operator">-</span> perfObj<span class="token punctuation">.</span>navigationStart<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="page-render-time" style="position:relative;"><a href="#page-render-time" aria-label="page render time permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Page render time</h3> <p>To calculate the total time taken to render the page, simply use <code class="language-text">domComplete</code> and <code class="language-text">domLoading</code> properties:</p> <div class="gatsby-code-button-container" data-toaster-id="20407354854224204000" data-toaster-class="gatsby-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 perfObj = window.performance.timing; let renderTime = perfObj.domComplete - perfObj.domLoading;`, `20407354854224204000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> perfObj <span class="token operator">=</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>timing<span class="token punctuation">;</span> <span class="token keyword">let</span> renderTime <span class="token operator">=</span> perfObj<span class="token punctuation">.</span>domComplete <span class="token operator">-</span> perfObj<span class="token punctuation">.</span>domLoading<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="request-response-time" style="position:relative;"><a href="#request-response-time" aria-label="request response time permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Request response time</h3> <p>To calculate the time between beginning of the request to the end of response retrieval, you can use:</p> <div class="gatsby-code-button-container" data-toaster-id="45586123950457450000" data-toaster-class="gatsby-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 perfObj = window.performance.timing; let renderTime = perfObj.responseEnd - perfObj.requestStart;`, `45586123950457450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> perfObj <span class="token operator">=</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>timing<span class="token punctuation">;</span> <span class="token keyword">let</span> renderTime <span class="token operator">=</span> perfObj<span class="token punctuation">.</span>responseEnd <span class="token operator">-</span> perfObj<span class="token punctuation">.</span>requestStart<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="network-latency" style="position:relative;"><a href="#network-latency" aria-label="network latency permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Network latency</h3> <p>If you want to measure network latency:</p> <div class="gatsby-code-button-container" data-toaster-id="39804007364850524000" data-toaster-class="gatsby-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 perfObj = window.performance.timing; let renderTime = perfObj.responseEnd - perfObj.fetchStart;`, `39804007364850524000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> perfObj <span class="token operator">=</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>timing<span class="token punctuation">;</span> <span class="token keyword">let</span> renderTime <span class="token operator">=</span> perfObj<span class="token punctuation">.</span>responseEnd <span class="token operator">-</span> perfObj<span class="token punctuation">.</span>fetchStart<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="navigation-and-page-load-together" style="position:relative;"><a href="#navigation-and-page-load-together" aria-label="navigation and page load together permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Navigation and page load together</h3> <p>To have the sum of navigation and page load time:</p> <div class="gatsby-code-button-container" data-toaster-id="37808661983017350000" data-toaster-class="gatsby-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 perfObj = window.performance.timing; let renderTime = perfObj.loadEventEnd - perfObj.navigationStart;`, `37808661983017350000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> perfObj <span class="token operator">=</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>timing<span class="token punctuation">;</span> <span class="token keyword">let</span> renderTime <span class="token operator">=</span> perfObj<span class="token punctuation">.</span>loadEventEnd <span class="token operator">-</span> perfObj<span class="token punctuation">.</span>navigationStart<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="pinpoint-redirect-problems" style="position:relative;"><a href="#pinpoint-redirect-problems" aria-label="pinpoint redirect problems permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Pinpoint redirect problems</h3> <p>To find out about any issue in redirects:</p> <div class="gatsby-code-button-container" data-toaster-id="36542443588367180000" data-toaster-class="gatsby-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 perfObj = window.performance.timing; let renderTime = perfObj.redirectEnd - perfObj.redirectStart;`, `36542443588367180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> perfObj <span class="token operator">=</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>timing<span class="token punctuation">;</span> <span class="token keyword">let</span> renderTime <span class="token operator">=</span> perfObj<span class="token punctuation">.</span>redirectEnd <span class="token operator">-</span> perfObj<span class="token punctuation">.</span>redirectStart<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="code-classlanguage-textnavigationcode-property" style="position:relative;"><a href="#code-classlanguage-textnavigationcode-property" aria-label="code classlanguage textnavigationcode property permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">navigation</code> property</h2> <p>There are many ways to end up on a page. If you want to know how your user ended up on your page, or how many redirects they’ve had before landing there, this property is your friend. <code class="language-text">performance.navigation</code> has two properties:</p> <ul> <li><strong>redirectCount</strong>: the number of times the document request was redirected.</li> <li><strong>type</strong>: type of the navigation which lead to this page.</li> </ul> <p>The <code class="language-text">type</code> property is an <code class="language-text">enum</code> which can have three values:</p> <ul> <li><strong>0</strong>: action by the user such as clicking a link or entering a URL in the browser address bar.</li> <li><strong>1</strong>: page reload.</li> <li><strong>2</strong>: navigation through going back and forth from history of the browser.</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>We saw how we can use the Navigation Timing API to get performance metrics on client side which can be sent to server to monitor performance of users in real time regardless of where they are and how they got there. This API is really powerful and has helped me a lot to help customers find out where they need to focus their energy to improve performance on which pages 😍.</p> <p>Hope this has been helpful and till next time, <em>au revoir</em> 👋.</p><![CDATA[Page Visibility API, let's help users save their battery life 😀]]>https://yashints.dev/blog/2019/09/22/page-visibility-apihttps://yashints.dev/blog/2019/09/22/page-visibility-apiSun, 22 Sep 2019 00:00:00 GMT<p>Are you want of those people with 200 tabs open? Are you tired of carrying your laptop charger with you all the time? Well, I am here to let you know we can help users save battery, data, and time, if we know how to use the <strong>Page Visibility API</strong>.</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>Imagine your user has a few tabs open, one running a heavy animation, the other getting a lot of data from the server, and another running a video from YouTube. These all require resources from user’s computer and that’s why sometimes having a few tabs open you suddenly realise you’re running out of battery, or your data allowance is finishing.</p> <p>💡 What if you could pause the current operation on a tab/window if the user isn’t looking at it?</p> <p>With <code class="language-text">Page Visibility API</code>, you can do that.</p> <h2 id="page-visibility-api" style="position:relative;"><a href="#page-visibility-api" aria-label="page visibility 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>Page Visibility API</h2> <p>This API allows a developer to become aware if the user has lost focus on the page, or has returned to it again. When the user minimises, or switches to another tab/window, the API sends a <code class="language-text">visibilitychange</code> event to let the listeners know the state of the page.</p> <p><strong>Page Visibility API</strong> is a very useful tool in your toolbox which gives you the power to not perform unnecessary operations when the page is not visible to user.</p> <p>This API adds the following properties to the <code class="language-text">Document</code> interface:</p> <ul> <li><code class="language-text">hidden</code>: which is a read-only attribute and returns true if the page is in a state to be considered hidden to user.</li> <li><code class="language-text">visibilityState</code>: which is a <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMString" target="_blank" rel="nofollow noopener noreferrer"><code class="language-text">DOMString</code></a> indicating the document’s current visibility state. It can have four values, <code class="language-text">visible</code>, <code class="language-text">hidden</code>, <code class="language-text">prerender</code>, and <code class="language-text">unloaded</code>.</li> </ul> <p>You can also listen to the <code class="language-text">visibilitychange</code> event which will trigger your callback function whenever the visibility changes:</p> <div class="gatsby-code-button-container" data-toaster-id="5671022886591271000" data-toaster-class="gatsby-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 handleVisibilityChange () { if (document.hidden) { // stop that task 🛑 } else { // you can start it again go ▶️ } } document.addEventListener('visibilitychange', handleVisibilityChange, false);`, `5671022886591271000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">handleVisibilityChange</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>document<span class="token punctuation">.</span>hidden<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// stop that task 🛑</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// you can start it again go ▶️</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'visibilitychange'</span><span class="token punctuation">,</span> handleVisibilityChange<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="code-classlanguage-textvisibilitystatecode" style="position:relative;"><a href="#code-classlanguage-textvisibilitystatecode" aria-label="code classlanguage textvisibilitystatecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">visibilityState</code></h2> <p>As mentioned before, this property can have four different values each of which representing a different tab/window state:</p> <ul> <li><strong>visible</strong>: This means the tab/window is visible or partially so. In other words, it means the page is the foreground tab of a non-minimised window.</li> <li><strong>hidden</strong>: Page is not visible due to being minimised or the device’s screen is off.</li> <li><strong>prerender</strong>: The page is now being prerendered and is not visible to user.</li> <li><strong>unloaded</strong>: This means the user is about to close the current page.</li> </ul> <div class="custom-block warning"><div class="custom-block-body"> ⚠️ You need to know that not all browsers support the last two states.</div></div> <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>The simplest scenario is playing video on the page, so we will be using that as an example. Let’s use a simple video element on the page which will be paused when the user focuses on another tab.</p> <div class="gatsby-code-button-container" data-toaster-id="80408603882506620000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<body> <h1>Demo: Page Visibility API</h1> <main> <video id=&quot;videoElement&quot; poster=&quot;http://media.w3.org/2010/05/sintel/poster.png&quot; width=&quot;400&quot; controls=&quot;&quot; > <source id='mp4' src=&quot;http://media.w3.org/2010/05/sintel/trailer.mp4&quot; type='video/mp4'/> <source id='webm' src=&quot;http://media.w3.org/2010/05/sintel/trailer.webm&quot; type='video/webm'/> <source id='ogv' src=&quot;http://media.w3.org/2010/05/sintel/trailer.ogv&quot; type='video/ogg'/> <p>Sorry, there's a problem playing this video. Please try using a different browser</p> </video> </main> <script> (function() { 'use strict'; // Set the name of the &quot;hidden&quot; property and the change event for visibility var hidden, visibilityChange; if (typeof document.hidden !== &quot;undefined&quot;) { hidden = &quot;hidden&quot;; visibilityChange = &quot;visibilitychange&quot;; } else if (typeof document.mozHidden !== &quot;undefined&quot;) { // Firefox up to v17 hidden = &quot;mozHidden&quot;; visibilityChange = &quot;mozvisibilitychange&quot;; } else if (typeof document.webkitHidden !== &quot;undefined&quot;) { // Chrome up to v32, Android up to v4.4, Blackberry up to v10 hidden = &quot;webkitHidden&quot;; visibilityChange = &quot;webkitvisibilitychange&quot;; } var videoElement = document.getElementById(&quot;videoElement&quot;); // If the page is hidden, pause the video; // if the page is shown, play the video function handleVisibilityChange() { if (document[hidden]) { videoElement.pause(); } else { videoElement.play(); } } // Warn if the browser doesn't support addEventListener or the Page Visibility API if (typeof document.addEventListener === &quot;undefined&quot; || typeof document[hidden] === &quot;undefined&quot;) { alert(&quot;This demo requires a modern browser that supports the Page Visibility API.&quot;); } else { // Handle page visibility change document.addEventListener(visibilityChange, handleVisibilityChange, false); // When the video pauses and plays, change the title. videoElement.addEventListener(&quot;pause&quot;, function(){ document.title = 'Paused'; }, false); videoElement.addEventListener(&quot;play&quot;, function(){ document.title = 'Playing' }, false); } })(); </script> </body>`, `80408603882506620000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Demo: Page Visibility API<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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>video</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>videoElement<span class="token punctuation">"</span></span> <span class="token attr-name">poster</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://media.w3.org/2010/05/sintel/poster.png<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">controls</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>source</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>mp4<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>http://media.w3.org/2010/05/sintel/trailer.mp4<span class="token punctuation">"</span></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>video/mp4<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>source</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>webm<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>http://media.w3.org/2010/05/sintel/trailer.webm<span class="token punctuation">"</span></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>video/webm<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>source</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>ogv<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>http://media.w3.org/2010/05/sintel/trailer.ogv<span class="token punctuation">"</span></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>video/ogg<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>p</span><span class="token punctuation">></span></span>Sorry, there's a problem playing this video. Please try using a different browser<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>video</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>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token string">'use strict'</span><span class="token punctuation">;</span> <span class="token comment">// Set the name of the "hidden" property and the change event for visibility</span> <span class="token keyword">var</span> hidden<span class="token punctuation">,</span> visibilityChange<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> document<span class="token punctuation">.</span>hidden <span class="token operator">!==</span> <span class="token string">"undefined"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> hidden <span class="token operator">=</span> <span class="token string">"hidden"</span><span class="token punctuation">;</span> visibilityChange <span class="token operator">=</span> <span class="token string">"visibilitychange"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> document<span class="token punctuation">.</span>mozHidden <span class="token operator">!==</span> <span class="token string">"undefined"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Firefox up to v17</span> hidden <span class="token operator">=</span> <span class="token string">"mozHidden"</span><span class="token punctuation">;</span> visibilityChange <span class="token operator">=</span> <span class="token string">"mozvisibilitychange"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> document<span class="token punctuation">.</span>webkitHidden <span class="token operator">!==</span> <span class="token string">"undefined"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Chrome up to v32, Android up to v4.4, Blackberry up to v10</span> hidden <span class="token operator">=</span> <span class="token string">"webkitHidden"</span><span class="token punctuation">;</span> visibilityChange <span class="token operator">=</span> <span class="token string">"webkitvisibilitychange"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> videoElement <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"videoElement"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// If the page is hidden, pause the video;</span> <span class="token comment">// if the page is shown, play the video</span> <span class="token keyword">function</span> <span class="token function">handleVisibilityChange</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>document<span class="token punctuation">[</span>hidden<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> videoElement<span class="token punctuation">.</span><span class="token function">pause</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> videoElement<span class="token punctuation">.</span><span class="token function">play</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 comment">// Warn if the browser doesn't support addEventListener or the Page Visibility API</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> document<span class="token punctuation">.</span>addEventListener <span class="token operator">===</span> <span class="token string">"undefined"</span> <span class="token operator">||</span> <span class="token keyword">typeof</span> document<span class="token punctuation">[</span>hidden<span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">"undefined"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"This demo requires a modern browser that supports the Page Visibility API."</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">// Handle page visibility change </span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>visibilityChange<span class="token punctuation">,</span> handleVisibilityChange<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// When the video pauses and plays, change the title.</span> videoElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"pause"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">'Paused'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> videoElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"play"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">'Playing'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <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></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>All we’re doing is to get a reference to the video element and hook into the <code class="language-text">visibilitychange</code> event. When the page is hidden, we simply pause the video. Once the focus is back in, we play it.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 403px; " > <a class="gatsby-resp-image-link" href="/static/3675698702ae0f0c46a1642df44a4db0/c80d3/simples.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 101.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGQABAQADAQAAAAAAAAAAAAAAAAQCAwUG/8QAFwEBAQEBAAAAAAAAAAAAAAAAAgABA//aAAwDAQACEAMQAAAB3yXckr0rJp5MxdLBH//EABoQAAMBAQEBAAAAAAAAAAAAAAECAwQSEwD/2gAIAQEAAQUC16jMppr3F/SeuXZkACnIXTMNbyH0UAX/xAAVEQEBAAAAAAAAAAAAAAAAAAAQAf/aAAgBAwEBPwEh/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHRAAAgEEAwAAAAAAAAAAAAAAAAERAhIhQTFRgf/aAAgBAQAGPwKyhZ7FsuiCU0nsiWQmhvJyz0//xAAaEAEAAwEBAQAAAAAAAAAAAAABABExIWHx/9oACAEBAAE/IVvA1Ssil24oK3Eh0eHF9Zy6tiAkHsQTgyfViEFj/9oADAMBAAIAAwAAABDQKLz/xAAXEQADAQAAAAAAAAAAAAAAAAAAATEQ/9oACAEDAQE/EFkDp//EABcRAQEBAQAAAAAAAAAAAAAAAAEAEBH/2gAIAQIBAT8QYuuf/8QAHRABAAICAwEBAAAAAAAAAAAAAQARUWEhMUGh0f/aAAgBAQABPxBOQoEyXR+xSPMgaiK1VPiNM7MSJMHyKr0C+h3cB2tWCBSKHKvJUIcneXzUdwLPNYNT/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Simples" title="" src="/static/3675698702ae0f0c46a1642df44a4db0/c80d3/simples.jpg" srcset="/static/3675698702ae0f0c46a1642df44a4db0/6f81f/simples.jpg 270w, /static/3675698702ae0f0c46a1642df44a4db0/c80d3/simples.jpg 403w" sizes="(max-width: 403px) 100vw, 403px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>I’ve create a <a href="https://aluminum-argon.glitch.me" target="_blank" rel="nofollow noopener noreferrer">live version on Glitch</a> you can have a look. Play the video and click on another tab. The video will get paused and once you’re back, it plays again.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>A good web application does not necessarily require hot features and impressive UX. Sometimes a performing web application would appeal to users like no other. Hope this little article helps you help your users in many ways.</p> <p>Happy exploring 😊.</p><![CDATA[Let's build a game with Tensorflow.js in 10 minutes 🎮]]>https://yashints.dev/blog/2019/09/19/ai-js-gamehttps://yashints.dev/blog/2019/09/19/ai-js-gameThu, 19 Sep 2019 00:00:00 GMT<p>I’ve been looking into <a href="https://www.tensorflow.org/js" target="_blank" rel="nofollow noopener noreferrer">Tensorflow.js</a> recently and have found the whole concept fascinating. Previously I wrote a piece on <a href="https://yashints.dev/blog/2018/11/27/get-started-with-tensorflowjs" target="_blank" rel="nofollow noopener noreferrer">how to get started</a>, and I intent to write more around all aspects of creating a new model, transfer learning with it, or just use pre-trained models for inference.</p> <!--more--> <h2 id="lets-review-our-plan-️" style="position:relative;"><a href="#lets-review-our-plan-%EF%B8%8F" aria-label="lets review our plan ️ permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Let’s review our plan 🗺️</h2> <p>Today we want to:</p> <ul> <li>Find a game written with JavaScript</li> <li>Find a model which we can control the game with</li> <li>Mix these two together and have fun 🤪</li> <li>Not complain about the code we just wrote to spoil the fun 😁</li> </ul> <h2 id="disclaimer" style="position:relative;"><a href="#disclaimer" aria-label="disclaimer permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Disclaimer</h2> <p>I am not showing any best practices here around the JavaScript code. It is copy pasted from somewhere else and our purpose is to make it work.</p> <h2 id="finding-the-game" style="position:relative;"><a href="#finding-the-game" aria-label="finding the game permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the game</h2> <p>The very first thing I did when I was creating one of the demo’s for <a href="https://www.youtube.com/watch?v=P1gBGT7R7jE" target="_blank" rel="nofollow noopener noreferrer">my talk on AI and JavaScript</a> was to search for a game written with JavaScript. I didn’t want a complex game, just something lightweight which could be customised easily.</p> <p>PS: You can now watch my talk 👇🏼</p> <p><a href="http://www.youtube.com/watch?v=P1gBGT7R7jE" title="AI and JavaScript, no you&#x27;re not dreaming" target="_blank" rel="nofollow noopener noreferrer"><img src="https://img.youtube.com/vi/P1gBGT7R7jE/0.jpg" alt="IMAGE ALT TEXT"></a></p> <p>After searching for <code class="language-text">JavaScript game</code> in Google, I found <a href="https://www.w3schools.com/graphics/game_score.asp" target="_blank" rel="nofollow noopener noreferrer">this game on W3schools</a>:</p> <p><img src="/7b9df80edb7f05ddcad4cde99d9d9db0/jsgame.gif" alt="A simple game written in JavaScript and HTML"></p> <p>The game is very simple. You just need to guide the red cube between incoming green bars. If it touches any of the green bars, the game is over.</p> <h2 id="finding-the-right-model" style="position:relative;"><a href="#finding-the-right-model" aria-label="finding the right model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the right model</h2> <p>For this game, what I could think of really quick was <a href="https://github.com/tensorflow/tfjs-models/tree/master/speech-commands" target="_blank" rel="nofollow noopener noreferrer">SpeechCommand</a>. This model recognises the spoken commands comprised of simple words. For now it only has 18 words, but we wouldn’t even need that since all we need is directions (<code class="language-text">up</code>, <code class="language-text">down</code>, <code class="language-text">left</code>, and <code class="language-text">right</code>).</p> <p>This model is using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API" target="_blank" rel="nofollow noopener noreferrer">WebAudio API</a> to listen to your voice through your microphone.</p> <h2 id="lets-code-" style="position:relative;"><a href="#lets-code-" aria-label="lets 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>Let’s code 💻</h2> <p>First thing first, we need to get the code behind our game. Thankfully, it’s on the same <a href="https://www.w3schools.com/graphics/tryit.asp?filename=trygame_score" target="_blank" rel="nofollow noopener noreferrer">page we found the game</a>.</p> <div class="gatsby-code-button-container" data-toaster-id="46326329027208570000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<html> <head> <meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;/> <style> canvas { border:1px solid #d3d3d3; background-color: #f1f1f1; } </style> </head> <body onload=&quot;startGame()&quot;> <script> var myGamePiece; var myObstacles = []; var myScore; function startGame() { myGamePiece = new component(30, 30, &quot;red&quot;, 10, 120); myScore = new component(&quot;30px&quot;, &quot;Consolas&quot;, &quot;black&quot;, 280, 40, &quot;text&quot;); myGameArea.start(); } var myGameArea = { canvas : document.createElement(&quot;canvas&quot;), start : function() { this.canvas.width = 480; this.canvas.height = 270; this.context = this.canvas.getContext(&quot;2d&quot;); document.body.insertBefore(this.canvas, document.body.childNodes[0]); this.frameNo = 0; this.interval = setInterval(updateGameArea, 20); }, clear : function() { this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); }, stop : function() { clearInterval(this.interval); } } function component(width, height, color, x, y, type) { this.type = type; this.width = width; this.height = height; this.speedX = 0; this.speedY = 0; this.x = x; this.y = y; this.update = function() { ctx = myGameArea.context; if (this.type == &quot;text&quot;) { ctx.font = this.width + &quot; &quot; + this.height; ctx.fillStyle = color; ctx.fillText(this.text, this.x, this.y); } else { ctx.fillStyle = color; ctx.fillRect(this.x, this.y, this.width, this.height); } } this.newPos = function() { this.x += this.speedX; this.y += this.speedY; } this.crashWith = function(otherobj) { var myleft = this.x; var myright = this.x + (this.width); var mytop = this.y; var mybottom = this.y + (this.height); var otherleft = otherobj.x; var otherright = otherobj.x + (otherobj.width); var othertop = otherobj.y; var otherbottom = otherobj.y + (otherobj.height); var crash = true; if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) { crash = false; } return crash; } } function updateGameArea() { var x, height, gap, minHeight, maxHeight, minGap, maxGap; for (i = 0; i < myObstacles.length; i += 1) { if (myGamePiece.crashWith(myObstacles[i])) { myGameArea.stop(); return; } } myGameArea.clear(); myGameArea.frameNo += 1; if (myGameArea.frameNo == 1 || everyinterval(150)) { x = myGameArea.canvas.width; minHeight = 20; maxHeight = 200; height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight); minGap = 50; maxGap = 200; gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap); myObstacles.push(new component(10, height, &quot;green&quot;, x, 0)); myObstacles.push(new component(10, x - height - gap, &quot;green&quot;, x, height + gap)); } for (i = 0; i < myObstacles.length; i += 1) { myObstacles[i].speedX = -1; myObstacles[i].newPos(); myObstacles[i].update(); } myScore.text=&quot;SCORE: &quot; + myGameArea.frameNo; myScore.update(); myGamePiece.newPos(); myGamePiece.update(); } function everyinterval(n) { if ((myGameArea.frameNo / n) % 1 == 0) {return true;} return false; } function moveup() { myGamePiece.speedY = -1; } function movedown() { myGamePiece.speedY = 1; } function moveleft() { myGamePiece.speedX = -1; } function moveright() { myGamePiece.speedX = 1; } function clearmove() { myGamePiece.speedX = 0; myGamePiece.speedY = 0; } </script> <div style=&quot;text-align:center;width:480px;&quot;> <button onmousedown=&quot;moveup()&quot; onmouseup=&quot;clearmove()&quot; ontouchstart=&quot;moveup()&quot;>UP</button><br><br> <button onmousedown=&quot;moveleft()&quot; onmouseup=&quot;clearmove()&quot; ontouchstart=&quot;moveleft()&quot;>LEFT</button> <button onmousedown=&quot;moveright()&quot; onmouseup=&quot;clearmove()&quot; ontouchstart=&quot;moveright()&quot;>RIGHT</button><br><br> <button onmousedown=&quot;movedown()&quot; onmouseup=&quot;clearmove()&quot; ontouchstart=&quot;movedown()&quot;>DOWN</button> </div> <p>The score will count one point for each frame you manage to &quot;stay alive&quot;.</p> </body> </html>`, `46326329027208570000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.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>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"> <span class="token selector">canvas</span> <span class="token punctuation">{</span> <span class="token property">border</span><span class="token punctuation">:</span>1px solid #d3d3d3<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #f1f1f1<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span> <span class="token special-attr"><span class="token attr-name">onload</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">startGame</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">var</span> myGamePiece<span class="token punctuation">;</span> <span class="token keyword">var</span> myObstacles <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">var</span> myScore<span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">startGame</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token punctuation">,</span> <span class="token string">"red"</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">120</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myScore <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token string">"30px"</span><span class="token punctuation">,</span> <span class="token string">"Consolas"</span><span class="token punctuation">,</span> <span class="token string">"black"</span><span class="token punctuation">,</span> <span class="token number">280</span><span class="token punctuation">,</span> <span class="token number">40</span><span class="token punctuation">,</span> <span class="token string">"text"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGameArea<span class="token punctuation">.</span><span class="token function">start</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> myGameArea <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">canvas</span> <span class="token operator">:</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"canvas"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function-variable function">start</span> <span class="token operator">:</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">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>width <span class="token operator">=</span> <span class="token number">480</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>height <span class="token operator">=</span> <span class="token number">270</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>context <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">"2d"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">,</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>childNodes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>frameNo <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>interval <span class="token operator">=</span> <span class="token function">setInterval</span><span class="token punctuation">(</span>updateGameArea<span class="token punctuation">,</span> <span class="token number">20</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-variable function">clear</span> <span class="token operator">:</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">this</span><span class="token punctuation">.</span>context<span class="token punctuation">.</span><span class="token function">clearRect</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>width<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function-variable function">stop</span> <span class="token operator">:</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 function">clearInterval</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>interval<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">component</span><span class="token punctuation">(</span><span class="token parameter">width<span class="token punctuation">,</span> height<span class="token punctuation">,</span> color<span class="token punctuation">,</span> x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> type</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">=</span> type<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">=</span> width<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> height<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">=</span> x<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">=</span> y<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function-variable function">update</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ctx <span class="token operator">=</span> myGameArea<span class="token punctuation">.</span>context<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">==</span> <span class="token string">"text"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ctx<span class="token punctuation">.</span>font <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">;</span> ctx<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> color<span class="token punctuation">;</span> ctx<span class="token punctuation">.</span><span class="token function">fillText</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>text<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<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> ctx<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> color<span class="token punctuation">;</span> ctx<span class="token punctuation">.</span><span class="token function">fillRect</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">)</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><span class="token function-variable function">newPos</span> <span class="token operator">=</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">this</span><span class="token punctuation">.</span>x <span class="token operator">+=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedX<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">+=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedY<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function-variable function">crashWith</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">otherobj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> myleft <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">;</span> <span class="token keyword">var</span> myright <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> mytop <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token punctuation">;</span> <span class="token keyword">var</span> mybottom <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> otherleft <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>x<span class="token punctuation">;</span> <span class="token keyword">var</span> otherright <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>x <span class="token operator">+</span> <span class="token punctuation">(</span>otherobj<span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> othertop <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>y<span class="token punctuation">;</span> <span class="token keyword">var</span> otherbottom <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token punctuation">(</span>otherobj<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> crash <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>mybottom <span class="token operator">&lt;</span> othertop<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>mytop <span class="token operator">></span> otherbottom<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>myright <span class="token operator">&lt;</span> otherleft<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>myleft <span class="token operator">></span> otherright<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> crash <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> crash<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">updateGameArea</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> x<span class="token punctuation">,</span> height<span class="token punctuation">,</span> gap<span class="token punctuation">,</span> minHeight<span class="token punctuation">,</span> maxHeight<span class="token punctuation">,</span> minGap<span class="token punctuation">,</span> maxGap<span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> myObstacles<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>myGamePiece<span class="token punctuation">.</span><span class="token function">crashWith</span><span class="token punctuation">(</span>myObstacles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGameArea<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><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 punctuation">}</span> myGameArea<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGameArea<span class="token punctuation">.</span>frameNo <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>myGameArea<span class="token punctuation">.</span>frameNo <span class="token operator">==</span> <span class="token number">1</span> <span class="token operator">||</span> <span class="token function">everyinterval</span><span class="token punctuation">(</span><span class="token number">150</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> x <span class="token operator">=</span> myGameArea<span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>width<span class="token punctuation">;</span> minHeight <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span> maxHeight <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span> height <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">*</span><span class="token punctuation">(</span>maxHeight<span class="token operator">-</span>minHeight<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">+</span>minHeight<span class="token punctuation">)</span><span class="token punctuation">;</span> minGap <span class="token operator">=</span> <span class="token number">50</span><span class="token punctuation">;</span> maxGap <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span> gap <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">*</span><span class="token punctuation">(</span>maxGap<span class="token operator">-</span>minGap<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">+</span>minGap<span class="token punctuation">)</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> height<span class="token punctuation">,</span> <span class="token string">"green"</span><span class="token punctuation">,</span> x<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> x <span class="token operator">-</span> height <span class="token operator">-</span> gap<span class="token punctuation">,</span> <span class="token string">"green"</span><span class="token punctuation">,</span> x<span class="token punctuation">,</span> height <span class="token operator">+</span> gap<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> myObstacles<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myObstacles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">newPos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> myScore<span class="token punctuation">.</span>text<span class="token operator">=</span><span class="token string">"SCORE: "</span> <span class="token operator">+</span> myGameArea<span class="token punctuation">.</span>frameNo<span class="token punctuation">;</span> myScore<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGamePiece<span class="token punctuation">.</span><span class="token function">newPos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGamePiece<span class="token punctuation">.</span><span class="token function">update</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">everyinterval</span><span class="token punctuation">(</span><span class="token parameter">n</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 punctuation">(</span>myGameArea<span class="token punctuation">.</span>frameNo <span class="token operator">/</span> n<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><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> <span class="token keyword">function</span> <span class="token function">moveup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">movedown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">moveleft</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">moveright</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">clearmove</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> myGamePiece<span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</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 special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">text-align</span><span class="token punctuation">:</span>center<span class="token punctuation">;</span><span class="token property">width</span><span class="token punctuation">:</span>480px<span class="token punctuation">;</span></span><span class="token punctuation">"</span></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 special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">moveup</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">clearmove</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token attr-name">ontouchstart</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>moveup()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>UP<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>br</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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 special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">moveleft</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">clearmove</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token attr-name">ontouchstart</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>moveleft()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>LEFT<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>button</span> <span class="token special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">moveright</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">clearmove</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token attr-name">ontouchstart</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>moveright()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>RIGHT<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>br</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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 special-attr"><span class="token attr-name">onmousedown</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">movedown</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onmouseup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">clearmove</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token attr-name">ontouchstart</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>movedown()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>DOWN<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>p</span><span class="token punctuation">></span></span>The score will count one point for each frame you manage to "stay alive".<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>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="creating-the-project-structure" style="position:relative;"><a href="#creating-the-project-structure" aria-label="creating the project structure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 structure</h3> <p>Let’s setup our project structure at this point. We will need the following files:</p> <ul> <li><code class="language-text">package.json</code></li> <li><code class="language-text">index.html</code></li> <li><code class="language-text">game.js</code></li> <li><code class="language-text">index.js</code></li> </ul> <p>In our <code class="language-text">package.json</code> we will need some dependencies and a script command to run the app.</p> <div class="gatsby-code-button-container" data-toaster-id="13185607961067647000" data-toaster-class="gatsby-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;dependencies&quot;: { &quot;@tensorflow-models/speech-commands&quot;: &quot;^0.3.9&quot;, &quot;@tensorflow/tfjs&quot;: &quot;^1.2.8&quot; }, &quot;scripts&quot;: { &quot;watch&quot;: &quot;cross-env NODE_OPTIONS=--max_old_space_size=4096 NODE_ENV=development parcel index.html --no-hmr --open&quot; }, &quot;devDependencies&quot;: { &quot;@babel/core&quot;: &quot;^7.0.0-0&quot;, &quot;@babel/plugin-transform-runtime&quot;: &quot;^7.1.0&quot;, &quot;babel-core&quot;: &quot;^6.26.3&quot;, &quot;babel-polyfill&quot;: &quot;~6.26.0&quot;, &quot;babel-preset-env&quot;: &quot;~1.6.1&quot;, &quot;babel-preset-es2017&quot;: &quot;^6.24.1&quot;, &quot;clang-format&quot;: &quot;~1.2.2&quot;, &quot;cross-env&quot;: &quot;^5.2.0&quot;, &quot;eslint&quot;: &quot;^4.19.1&quot;, &quot;eslint-config-google&quot;: &quot;^0.9.1&quot;, &quot;parcel-bundler&quot;: &quot;~1.10.3&quot; }, ... }`, `13185607961067647000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> ... <span class="token property">"dependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"@tensorflow-models/speech-commands"</span><span class="token operator">:</span> <span class="token string">"^0.3.9"</span><span class="token punctuation">,</span> <span class="token property">"@tensorflow/tfjs"</span><span class="token operator">:</span> <span class="token string">"^1.2.8"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"watch"</span><span class="token operator">:</span> <span class="token string">"cross-env NODE_OPTIONS=--max_old_space_size=4096 NODE_ENV=development parcel index.html --no-hmr --open"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"@babel/core"</span><span class="token operator">:</span> <span class="token string">"^7.0.0-0"</span><span class="token punctuation">,</span> <span class="token property">"@babel/plugin-transform-runtime"</span><span class="token operator">:</span> <span class="token string">"^7.1.0"</span><span class="token punctuation">,</span> <span class="token property">"babel-core"</span><span class="token operator">:</span> <span class="token string">"^6.26.3"</span><span class="token punctuation">,</span> <span class="token property">"babel-polyfill"</span><span class="token operator">:</span> <span class="token string">"~6.26.0"</span><span class="token punctuation">,</span> <span class="token property">"babel-preset-env"</span><span class="token operator">:</span> <span class="token string">"~1.6.1"</span><span class="token punctuation">,</span> <span class="token property">"babel-preset-es2017"</span><span class="token operator">:</span> <span class="token string">"^6.24.1"</span><span class="token punctuation">,</span> <span class="token property">"clang-format"</span><span class="token operator">:</span> <span class="token string">"~1.2.2"</span><span class="token punctuation">,</span> <span class="token property">"cross-env"</span><span class="token operator">:</span> <span class="token string">"^5.2.0"</span><span class="token punctuation">,</span> <span class="token property">"eslint"</span><span class="token operator">:</span> <span class="token string">"^4.19.1"</span><span class="token punctuation">,</span> <span class="token property">"eslint-config-google"</span><span class="token operator">:</span> <span class="token string">"^0.9.1"</span><span class="token punctuation">,</span> <span class="token property">"parcel-bundler"</span><span class="token operator">:</span> <span class="token string">"~1.10.3"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I am using parcel here since it’s easy to setup and it just works. Besides, most of the demo’s on <a href="https://github.com/tensorflow/tfjs-models" target="_blank" rel="nofollow noopener noreferrer">Tensorflow.js models GitHub repository</a> are using parcel.</p> <p>Your project structure should look like:</p> <p><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/97e1f96635448653fd72a4b1f79e3dd5/20e5d/proj.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 94.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAATABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHmZ6UIAAB//8QAFxAAAwEAAAAAAAAAAAAAAAAAEBEgQf/aAAgBAQABBQLJZ//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABQQAQAAAAAAAAAAAAAAAAAAADD/2gAIAQEABj8CH//EABkQAAMAAwAAAAAAAAAAAAAAAAEQEQAxYf/aAAgBAQABPyHtyjDtU//aAAwDAQACAAMAAAAQIAgA/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHBABAQACAgMAAAAAAAAAAAAAAREQYQAhkeHw/9oACAEBAAE/EIVE3PWYgn3jhCASbwp1SOjP/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Project structure" title="" src="/static/97e1f96635448653fd72a4b1f79e3dd5/20e5d/proj.jpg" srcset="/static/97e1f96635448653fd72a4b1f79e3dd5/6f81f/proj.jpg 270w, /static/97e1f96635448653fd72a4b1f79e3dd5/20e5d/proj.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" decoding="async" /> </a> </span></p> <h3 id="converting-the-game-code-into-a-module" style="position:relative;"><a href="#converting-the-game-code-into-a-module" aria-label="converting the game code into a module permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Converting the game code into a module</h3> <p>For now, let’s not focus on the code that much since we need to do some refactoring. First thing first, let’s separate our JavaScript code into a separate file. With doing so your HTML should look like:</p> <div class="gatsby-code-button-container" data-toaster-id="42498352917515400000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE html> <html class=&quot;no-js&quot;> <head> <meta charset=&quot;utf-8&quot; /> <meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /> <title>TensorFlow.js Speech Commands Model Demo</title> <meta name=&quot;description&quot; content=&quot;&quot; /> <meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /> <style> canvas { border: 1px solid #d3d3d3; background-color: #f1f1f1; } </style> </head> <body> <script src=&quot;index.js&quot;></script> </body> </html>`, `42498352917515400000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</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>no-js<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>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-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>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<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>title</span><span class="token punctuation">></span></span>TensorFlow.js Speech Commands Model Demo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>description<span class="token punctuation">"</span></span> <span class="token attr-name">content</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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<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>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"> <span class="token selector">canvas</span> <span class="token punctuation">{</span> <span class="token property">border</span><span class="token punctuation">:</span> 1px solid #d3d3d3<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #f1f1f1<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>index.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Since we are going to use <strong>SpeechCommand</strong> module, we need to change our JavaScript code to support that. Create a file called <code class="language-text">main.js</code> and paste the below code in it.</p> <div class="gatsby-code-button-container" data-toaster-id="54834589428113030000" data-toaster-class="gatsby-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 myGamePiece; var myObstacles = []; var myScore; export const startGame = function() { myGamePiece = new component(30, 30, &quot;red&quot;, 10, 120); myScore = new component(&quot;30px&quot;, &quot;Consolas&quot;, &quot;black&quot;, 280, 40, &quot;text&quot;); myGameArea.start(); } var myGameArea = { canvas : document.createElement(&quot;canvas&quot;), start : function() { this.canvas.width = 480; this.canvas.height = 270; this.context = this.canvas.getContext(&quot;2d&quot;); document.body.insertBefore(this.canvas, document.body.childNodes[0]); this.frameNo = 0; this.interval = setInterval(updateGameArea, 40); }, clear : function() { this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); }, stop : function() { clearInterval(this.interval); } } function component(width, height, color, x, y, type) { this.type = type; this.width = width; this.height = height; this.speedX = 0; this.speedY = 0; this.x = x; this.y = y; this.update = function() { let ctx = myGameArea.context; if (this.type == &quot;text&quot;) { ctx.font = this.width + &quot; &quot; + this.height; ctx.fillStyle = color; ctx.fillText(this.text, this.x, this.y); } else { ctx.fillStyle = color; ctx.fillRect(this.x, this.y, this.width, this.height); } } this.newPos = function() { this.x += this.speedX; this.y += this.speedY; } this.crashWith = function(otherobj) { let myleft = this.x; let myright = this.x + (this.width); let mytop = this.y; let mybottom = this.y + (this.height); let otherleft = otherobj.x; let otherright = otherobj.x + (otherobj.width); let othertop = otherobj.y; let otherbottom = otherobj.y + (otherobj.height); let crash = true; if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) { crash = false; } return crash; } } function updateGameArea() { let x, height, gap, minHeight, maxHeight, minGap, maxGap; for (let i = 0; i < myObstacles.length; i += 1) { if (myGamePiece.crashWith(myObstacles[i])) { myGameArea.stop(); return; } } myGameArea.clear(); myGameArea.frameNo += 1; if (myGameArea.frameNo == 1 || everyinterval(180)) { x = myGameArea.canvas.width; minHeight = 20; maxHeight = 200; height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight); minGap = 50; maxGap = 200; gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap); myObstacles.push(new component(10, height, &quot;green&quot;, x, 0)); myObstacles.push(new component(10, x - height - gap, &quot;green&quot;, x, height + gap)); } for (let j = 0; j < myObstacles.length; j += 1) { myObstacles[j].speedX = -1; myObstacles[j].newPos(); myObstacles[j].update(); } myScore.text=&quot;SCORE: &quot; + myGameArea.frameNo; myScore.update(); myGamePiece.newPos(); myGamePiece.update(); } export const everyinterval = function(n) { if ((myGameArea.frameNo / n) % 1 == 0) {return true;} return false; } export const moveup = function() { myGamePiece.speedY = -1; } export const movedown = function() { myGamePiece.speedY = 1; } export const moveleft = function() { myGamePiece.speedX = -1; } export const moveright = function() { myGamePiece.speedX = 1; } export const clearmove = function() { myGamePiece.speedX = 0; myGamePiece.speedY = 0; }`, `54834589428113030000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> myGamePiece<span class="token punctuation">;</span> <span class="token keyword">var</span> myObstacles <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">var</span> myScore<span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">startGame</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token punctuation">,</span> <span class="token string">"red"</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">120</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myScore <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token string">"30px"</span><span class="token punctuation">,</span> <span class="token string">"Consolas"</span><span class="token punctuation">,</span> <span class="token string">"black"</span><span class="token punctuation">,</span> <span class="token number">280</span><span class="token punctuation">,</span> <span class="token number">40</span><span class="token punctuation">,</span> <span class="token string">"text"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGameArea<span class="token punctuation">.</span><span class="token function">start</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> myGameArea <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">canvas</span> <span class="token operator">:</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"canvas"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function-variable function">start</span> <span class="token operator">:</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">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>width <span class="token operator">=</span> <span class="token number">480</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>height <span class="token operator">=</span> <span class="token number">270</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>context <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">"2d"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">,</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>childNodes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>frameNo <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>interval <span class="token operator">=</span> <span class="token function">setInterval</span><span class="token punctuation">(</span>updateGameArea<span class="token punctuation">,</span> <span class="token number">40</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-variable function">clear</span> <span class="token operator">:</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">this</span><span class="token punctuation">.</span>context<span class="token punctuation">.</span><span class="token function">clearRect</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>width<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function-variable function">stop</span> <span class="token operator">:</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 function">clearInterval</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>interval<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">component</span><span class="token punctuation">(</span><span class="token parameter">width<span class="token punctuation">,</span> height<span class="token punctuation">,</span> color<span class="token punctuation">,</span> x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> type</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">=</span> type<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">=</span> width<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> height<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">=</span> x<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">=</span> y<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function-variable function">update</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> ctx <span class="token operator">=</span> myGameArea<span class="token punctuation">.</span>context<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">==</span> <span class="token string">"text"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ctx<span class="token punctuation">.</span>font <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">;</span> ctx<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> color<span class="token punctuation">;</span> ctx<span class="token punctuation">.</span><span class="token function">fillText</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>text<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<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> ctx<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> color<span class="token punctuation">;</span> ctx<span class="token punctuation">.</span><span class="token function">fillRect</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">)</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><span class="token function-variable function">newPos</span> <span class="token operator">=</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">this</span><span class="token punctuation">.</span>x <span class="token operator">+=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedX<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">+=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>speedY<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function-variable function">crashWith</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">otherobj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> myleft <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">;</span> <span class="token keyword">let</span> myright <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> mytop <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token punctuation">;</span> <span class="token keyword">let</span> mybottom <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> otherleft <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>x<span class="token punctuation">;</span> <span class="token keyword">let</span> otherright <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>x <span class="token operator">+</span> <span class="token punctuation">(</span>otherobj<span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> othertop <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>y<span class="token punctuation">;</span> <span class="token keyword">let</span> otherbottom <span class="token operator">=</span> otherobj<span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token punctuation">(</span>otherobj<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> crash <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>mybottom <span class="token operator">&lt;</span> othertop<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>mytop <span class="token operator">></span> otherbottom<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>myright <span class="token operator">&lt;</span> otherleft<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>myleft <span class="token operator">></span> otherright<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> crash <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> crash<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">updateGameArea</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> x<span class="token punctuation">,</span> height<span class="token punctuation">,</span> gap<span class="token punctuation">,</span> minHeight<span class="token punctuation">,</span> maxHeight<span class="token punctuation">,</span> minGap<span class="token punctuation">,</span> maxGap<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> myObstacles<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>myGamePiece<span class="token punctuation">.</span><span class="token function">crashWith</span><span class="token punctuation">(</span>myObstacles<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGameArea<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><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 punctuation">}</span> myGameArea<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGameArea<span class="token punctuation">.</span>frameNo <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>myGameArea<span class="token punctuation">.</span>frameNo <span class="token operator">==</span> <span class="token number">1</span> <span class="token operator">||</span> <span class="token function">everyinterval</span><span class="token punctuation">(</span><span class="token number">180</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> x <span class="token operator">=</span> myGameArea<span class="token punctuation">.</span>canvas<span class="token punctuation">.</span>width<span class="token punctuation">;</span> minHeight <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span> maxHeight <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span> height <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">*</span><span class="token punctuation">(</span>maxHeight<span class="token operator">-</span>minHeight<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">+</span>minHeight<span class="token punctuation">)</span><span class="token punctuation">;</span> minGap <span class="token operator">=</span> <span class="token number">50</span><span class="token punctuation">;</span> maxGap <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span> gap <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">*</span><span class="token punctuation">(</span>maxGap<span class="token operator">-</span>minGap<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">+</span>minGap<span class="token punctuation">)</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> height<span class="token punctuation">,</span> <span class="token string">"green"</span><span class="token punctuation">,</span> x<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">component</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> x <span class="token operator">-</span> height <span class="token operator">-</span> gap<span class="token punctuation">,</span> <span class="token string">"green"</span><span class="token punctuation">,</span> x<span class="token punctuation">,</span> height <span class="token operator">+</span> gap<span class="token punctuation">)</span><span class="token punctuation">)</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">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> myObstacles<span class="token punctuation">.</span>length<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> myObstacles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">newPos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObstacles<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> myScore<span class="token punctuation">.</span>text<span class="token operator">=</span><span class="token string">"SCORE: "</span> <span class="token operator">+</span> myGameArea<span class="token punctuation">.</span>frameNo<span class="token punctuation">;</span> myScore<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGamePiece<span class="token punctuation">.</span><span class="token function">newPos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myGamePiece<span class="token punctuation">.</span><span class="token function">update</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">export</span> <span class="token keyword">const</span> <span class="token function-variable function">everyinterval</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">n</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 punctuation">(</span>myGameArea<span class="token punctuation">.</span>frameNo <span class="token operator">/</span> n<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><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> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">moveup</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">movedown</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">moveleft</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">moveright</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">clearmove</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> myGamePiece<span class="token punctuation">.</span>speedX <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> myGamePiece<span class="token punctuation">.</span>speedY <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>All I did here is change some of those functions to be constant and export what need later on. Now let’s write our <code class="language-text">index.js</code> and import the speech command model.</p> <div class="gatsby-code-button-container" data-toaster-id="40011245327770360000" data-toaster-class="gatsby-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 * as speechCommands from &quot;@tensorflow-models/speech-commands&quot;;`, `40011245327770360000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> speechCommands <span class="token keyword">from</span> <span class="token string">"@tensorflow-models/speech-commands"</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Next, import the functions we will need to play the game:</p> <div class="gatsby-code-button-container" data-toaster-id="45152730941957930000" data-toaster-class="gatsby-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 { startGame, moveup, movedown, clearmove } from './main';`, `45152730941957930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> startGame<span class="token punctuation">,</span> moveup<span class="token punctuation">,</span> movedown<span class="token punctuation">,</span> clearmove <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./main'</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>I am not going to use left and write, but you could totally use them too. Next up, we need to create an instance of the model and initialise it. Since loading the model requires an async call, we will use an <a href="https://en.wikipedia.org/wiki/Immediately-invoked_function_expression" target="_blank" rel="nofollow noopener noreferrer">IIFE (Immediately-Invoked Function Expression)</a>:</p> <div class="gatsby-code-button-container" data-toaster-id="23577000649294553000" data-toaster-class="gatsby-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 recognizer = speechCommands.create(&quot;BROWSER_FFT&quot;); (async function() { await recognizer.ensureModelLoaded(); console.log(recognizer.wordLabels()); startGame(); })();`, `23577000649294553000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> recognizer <span class="token operator">=</span> speechCommands<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">"BROWSER_FFT"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">(</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">await</span> recognizer<span class="token punctuation">.</span><span class="token function">ensureModelLoaded</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>recognizer<span class="token punctuation">.</span><span class="token function">wordLabels</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">startGame</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We call start game once the model is loaded. At last, we need to call the <code class="language-text">listen</code> method on our instance to be able to listen to commands:</p> <div class="gatsby-code-button-container" data-toaster-id="96054419603429130000" data-toaster-class="gatsby-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 suppressionTimeMillis = 1000; const allowedCommands = ['up', 'down']; recognizer .listen( result => { checkPredictions(recognizer.wordLabels(), result.scores, 2, suppressionTimeMillis); }, { includeSpectrogram: true, suppressionTimeMillis, probabilityThreshold: 0.8 } ) .then(() => { console.log(&quot;Streaming recognition started.&quot;); }) .catch(err => { console.log(&quot;ERROR: Failed to start streaming display: &quot; + err.message); }); const checkPredictions = ( candidateWords, probabilities, topK, timeToLiveMillis ) => { if (topK != null) { let wordsAndProbs = []; for (let i = 0; i < candidateWords.length; ++i) { wordsAndProbs.push([candidateWords[i], probabilities[i]]); } wordsAndProbs.sort((a, b) => b[1] - a[1]); wordsAndProbs = wordsAndProbs.slice(0, topK); candidateWords = wordsAndProbs.map(item => item[0]); probabilities = wordsAndProbs.map(item => item[1]); console.log(wordsAndProbs); // Highlight the top word. const topWord = wordsAndProbs[0][0]; if(allowedCommands.includes(topWord)) { if(topWord === 'up') { moveup(); setTimeout(() => clearmove(), 850); console.log('up'); } else { movedown(); setTimeout(() => clearmove(), 850); console.log('down'); } } } }`, `96054419603429130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> suppressionTimeMillis <span class="token operator">=</span> <span class="token number">1000</span><span class="token punctuation">;</span> <span class="token keyword">const</span> allowedCommands <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'up'</span><span class="token punctuation">,</span> <span class="token string">'down'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> recognizer <span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span> <span class="token parameter">result</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">checkPredictions</span><span class="token punctuation">(</span>recognizer<span class="token punctuation">.</span><span class="token function">wordLabels</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> result<span class="token punctuation">.</span>scores<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> suppressionTimeMillis<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 literal-property property">includeSpectrogram</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> suppressionTimeMillis<span class="token punctuation">,</span> <span class="token literal-property property">probabilityThreshold</span><span class="token operator">:</span> <span class="token number">0.8</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 punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Streaming recognition started."</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">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"ERROR: Failed to start streaming display: "</span> <span class="token operator">+</span> err<span class="token punctuation">.</span>message<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> <span class="token function-variable function">checkPredictions</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">candidateWords<span class="token punctuation">,</span> probabilities<span class="token punctuation">,</span> topK<span class="token punctuation">,</span> timeToLiveMillis</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>topK <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> wordsAndProbs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> candidateWords<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span> wordsAndProbs<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">[</span>candidateWords<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> probabilities<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> wordsAndProbs<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> b<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">-</span> a<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> wordsAndProbs <span class="token operator">=</span> wordsAndProbs<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> topK<span class="token punctuation">)</span><span class="token punctuation">;</span> candidateWords <span class="token operator">=</span> wordsAndProbs<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">item</span> <span class="token operator">=></span> item<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> probabilities <span class="token operator">=</span> wordsAndProbs<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">item</span> <span class="token operator">=></span> item<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> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>wordsAndProbs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Highlight the top word.</span> <span class="token keyword">const</span> topWord <span class="token operator">=</span> wordsAndProbs<span class="token punctuation">[</span><span class="token number">0</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> <span class="token keyword">if</span><span class="token punctuation">(</span>allowedCommands<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>topWord<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>topWord <span class="token operator">===</span> <span class="token string">'up'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">moveup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">clearmove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">850</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">'up'</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 function">movedown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">clearmove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">850</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">'down'</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This will start our game and also listens to your mic. You will need to give permission to your browser to use your mic if you haven’t done already.</p> <p>Listen method returns a promise which will have a result object. When we get the result, we will call our little helper function to check which words are recognised an fire an action based on that.</p> <p><a href="https://jsgame-speechcommand.netlify.com/" target="_blank" rel="nofollow noopener noreferrer">Check the live demo here</a>.</p> <h2 id="improvement" style="position:relative;"><a href="#improvement" aria-label="improvement permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Improvement</h2> <p>If you’ve had a look at the documentation on <a href="https://github.com/tensorflow/tfjs-models/tree/master/speech-commands" target="_blank" rel="nofollow noopener noreferrer">SpeechCommand repo</a>, you can see when calling <code class="language-text">speechCommands.create()</code>, you can specify the vocabulary the loaded model will be able to recognize. This is specified as the second, optional argument to <code class="language-text">speechCommands.create()</code>. We can use that to limit the words to only directional:</p> <div class="gatsby-code-button-container" data-toaster-id="60519544190020280000" data-toaster-class="gatsby-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 recognizer = speechCommands.create('BROWSER_FFT', 'directional4w');`, `60519544190020280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> recognizer <span class="token operator">=</span> speechCommands<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'BROWSER_FFT'</span><span class="token punctuation">,</span> <span class="token string">'directional4w'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now if you try the model, it will be more accurate because it only focuses on directional words (<code class="language-text">up</code>, <code class="language-text">down</code>, <code class="language-text">left</code>, and <code class="language-text">right</code>).</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>That’s it. This is all you need to do in order to control this mini game using your voice with <code class="language-text">Tensorflow.js</code> <strong>SpeechCommand</strong> model.</p> <p>Now go and create something fun with those pre-trained models and make sure to check their example repository.</p> <p>For more inspiring demo’s check <a href="https://aijs.rocks/" target="_blank" rel="nofollow noopener noreferrer">aijs.rocks</a> which is built by <a href="https://twitter.com/jawache" target="_blank" rel="nofollow noopener noreferrer">Asim Hussain</a>, <a href="https://twitter.com/EleanorHaproff" target="_blank" rel="nofollow noopener noreferrer">Eleanor Haproff</a> and <a href="https://twitter.com/osama_jandali" target="_blank" rel="nofollow noopener noreferrer">Osama Jandali</a>.</p><![CDATA[aria-live, accessibility tips 🦮]]>https://yashints.dev/blog/2019/09/14/aria-livehttps://yashints.dev/blog/2019/09/14/aria-liveSat, 14 Sep 2019 00:00:00 GMT<p>Last week I talked about <a href="https://www.componentsconf.com.au/schedule" target="_blank" rel="nofollow noopener noreferrer">JavaScript and AI using Tensorflow.js</a> at <a href="https://www.componentsconf.com.au/" target="_blank" rel="nofollow noopener noreferrer">ComponentsConf</a> in Melbourne, Australia. The line up was a killer and I got to listen to some amazing talks, one of which got me hooked. It’s about accessibility and how we can be more inclusive by doing very little at our end.</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>We all create websites or applications which is used by many people who can see our pages, however, we don’t realise these are also consumed by people who can’t see them and use assistive technologies such as screen readers.</p> <p>I am not talking about static pages here, we’re dealing with dynamic pages where an area in the page gets changed without refreshing the whole page thanks to our friend JavaScript. This can be updating the ticket’s price list, or updating the search result on the fly.</p> <p>When this happens screen readers usually are not aware, unless we let them know there was an update on the page and that’s where <code class="language-text">aria-live</code> regions come to the rescue.</p> <h2 id="how-does-code-classlanguage-textaria-livecode-works" style="position:relative;"><a href="#how-does-code-classlanguage-textaria-livecode-works" aria-label="how does code classlanguage textaria livecode works permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 <code class="language-text">aria-live</code> works?</h2> <p><code class="language-text">aria-live</code> lets us mark a part of the page as “live”, which means updates to this area should be communicated to the user regardless of where in the page they have focused on rather than requiring the user to be on that area when the update happens. This means they won’t miss the updates even if they’re currently reviewing other parts of the page.</p> <p>For example, if the user clicks a button and an action is done, the status message which appears as a result should be communicated to them.</p> <p>In its simplest form, an <code class="language-text">aria-live</code> looks like this:</p> <div class="gatsby-code-button-container" data-toaster-id="29856252688690676000" data-toaster-class="gatsby-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;status&quot; aria-live=&quot;polite&quot;>Thanks for your feedback.</div>`, `29856252688690676000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>status<span class="token punctuation">"</span></span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Thanks for your feedback.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>There are three values which can be used with <code class="language-text">aria-live</code> attribute, <code class="language-text">polite</code>, <code class="language-text">assertive</code>, and <code class="language-text">off</code>.</p> <h2 id="it-doesnt-make-sense-lets-see-it-in-action" style="position:relative;"><a href="#it-doesnt-make-sense-lets-see-it-in-action" aria-label="it doesnt make sense lets see it in action permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 doesn’t make sense? Let’s see it in action</h2> <p>To demonstrate how it all works, I’ve created a CodePen with three regions for each of the above values.</p> <p>Here is the code:</p> <div class="gatsby-code-button-container" data-toaster-id="17007761849919280000" data-toaster-class="gatsby-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>Polite</h1> <button onclick=&quot;updateContent('msg')&quot;>To view the updates, click this button!</button> <br/> <br/> <div id=&quot;msg&quot; role=&quot;region&quot; aria-live=&quot;polite&quot; id=&quot;msg&quot;></div> <h1>Assertive</h1> <button onclick=&quot;updateContent('msg2')&quot;>To view the updates immediately, click this button!</button> <br/> <br/> <div id=&quot;msg2&quot; role=&quot;region&quot; aria-live=&quot;assertive&quot; id=&quot;msg&quot;></div> <h1>Off</h1> <button onclick=&quot;updateContent('msg3')&quot;>No updates will be announced, so don't click this button 😂!</button> <br/> <br/> <div id=&quot;msg3&quot; role=&quot;region&quot; aria-live=&quot;off&quot; id=&quot;msg&quot;></div>`, `17007761849919280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Polite<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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 special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">updateContent</span><span class="token punctuation">(</span><span class="token string">'msg'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>To view the updates, click this button!<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>br</span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>msg<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>region<span class="token punctuation">"</span></span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<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>msg<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>h1</span><span class="token punctuation">></span></span>Assertive<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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 special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">updateContent</span><span class="token punctuation">(</span><span class="token string">'msg2'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>To view the updates immediately, click this button!<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>br</span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>msg2<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>region<span class="token punctuation">"</span></span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>assertive<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>msg<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>h1</span><span class="token punctuation">></span></span>Off<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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 special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">updateContent</span><span class="token punctuation">(</span><span class="token string">'msg3'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>No updates will be announced, so don't click this button 😂!<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>br</span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>msg3<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>region<span class="token punctuation">"</span></span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>off<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>msg<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And a simple function to simulate the content change:</p> <div class="gatsby-code-button-container" data-toaster-id="13976052596222743000" data-toaster-class="gatsby-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 updateContent(id) { document.querySelector(\`#\${id}\`).textContent = 'Content changed: ' + Math.random() };`, `13976052596222743000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">updateContent</span><span class="token punctuation">(</span><span class="token parameter">id</span><span class="token punctuation">)</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 template-string"><span class="token template-punctuation string">`</span><span class="token string">#</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>id<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>textContent <span class="token operator">=</span> <span class="token string">'Content changed: '</span> <span class="token operator">+</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="lets-be-polite-" style="position:relative;"><a href="#lets-be-polite-" aria-label="lets be polite permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Let’s be polite 😊</h2> <p><code class="language-text">aria-live="polite"</code> tells assistive technology to alert the user to this change when it has finished whatever it is currently doing. It’s great to use if something is important but not urgent, and accounts for the majority of <code class="language-text">aria-live</code> use.</p> <p>You can see how it works in the video below using a demo I created on <a href="https://codepen.io/yashints/pen/jONKgMw" target="_blank" rel="nofollow noopener noreferrer">CodePen</a>. In this demo I am changing the content of the message box with each click with a random number. You can see that windows narrator reads the current message before reading the next one, although the message has changed.</p> <video controls="controls"> <source type="video/mp4" src="https://yashintsblogassets.s3-ap-southeast-2.amazonaws.com/2019/polite.mp4"></source> <p>Your browser does not support the video element.</p> </video> <h2 id="holly-molly-something-urgent-happened-️" style="position:relative;"><a href="#holly-molly-something-urgent-happened-%EF%B8%8F" aria-label="holly molly something urgent happened ️ permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Holly molly, something urgent happened ⚠️</h2> <p><code class="language-text">aria-live="assertive"</code> tells assistive technology to interrupt whatever it’s going on and alert the user to this change immediately. This is only for important and urgent updates, such as a status message like “There has been a server error and your changes are not saved; please refresh the page”, or updates to an input field as a direct result of a user action, such as buttons on a stepper widget.</p> <p>You can see that in the assertive <code class="language-text">aria-live</code> region, the narrator reads the next message as soon as it appears, even if it means it cuts off the previous one.</p> <video controls="controls"> <source type="video/mp4" src="https://yashintsblogassets.s3-ap-southeast-2.amazonaws.com/2019/assertive.mp4"></source> <p>Your browser does not support the video element.</p> </video> <h2 id="turn-it-off-and-save-energy-" style="position:relative;"><a href="#turn-it-off-and-save-energy-" aria-label="turn it off and save energy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Turn it off and save energy 😁</h2> <p><code class="language-text">aria-live="off"</code> tells assistive technology to temporarily suspend <code class="language-text">aria-live</code> interruptions. If the updates are finished, you should definitely set the <code class="language-text">aria-live</code> region to off. This will help the assistive technology to stop tracking changes of the dynamic content.</p> <h2 id="making-sure-the-code-classlanguage-textaria-livecode-regions-work-effectively" style="position:relative;"><a href="#making-sure-the-code-classlanguage-textaria-livecode-regions-work-effectively" aria-label="making sure the code classlanguage textaria livecode regions work effectively permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Making sure the <code class="language-text">aria-live</code> regions work effectively</h2> <p>This is a powerful tool, but you know the saying:</p> <blockquote> <p>With great power, comes great responsibility.</p> </blockquote> <h3 id="include-the-area-from-beginning" style="position:relative;"><a href="#include-the-area-from-beginning" aria-label="include the area from beginning permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Include the area from beginning</h3> <p>The first and foremost consideration is that you have to make sure the region is there on page load and it’s empty. This is not a hard and fast rule, but many issues might occur if the region is not there initially.</p> <p>❌ Don’t do:</p> <div class="gatsby-code-button-container" data-toaster-id="52049977213403960000" data-toaster-class="gatsby-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;dynamic-content&quot;></div> <script> document.querySelector(&quot;.dynamic-content&quot;).innerHTML = \`<div id=&quot;msg&quot; aria-live=&quot;polite&quot;> Content changed! </div>\` <script>`, `52049977213403960000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>dynamic-content<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>script</span><span class="token punctuation">></span></span> document.querySelector(".dynamic-content").innerHTML = `<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</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>msg<span class="token punctuation">"</span></span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Content changed! <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>script</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>✔️ Instead:</p> <div class="gatsby-code-button-container" data-toaster-id="79878955079227930000" data-toaster-class="gatsby-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;dynamic-content&quot;> <div id=&quot;msg&quot; aria-live=&quot;polite&quot;></div> </div> <script> document.querySelector('#msg').textContent = 'Content changed!' </script>`, `79878955079227930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>dynamic-content<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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>msg<span class="token punctuation">"</span></span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<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> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#msg'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">'Content changed!'</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="want-to-hide-the-text-but-get-it-announced-" style="position:relative;"><a href="#want-to-hide-the-text-but-get-it-announced-" aria-label="want to hide the text but get it announced permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Want to hide the text but get it announced 😲?</h2> <p>If you want screen readers to announce your updates but would like to visually hide the text on screen, you have a bit of problem with usual wats like <code class="language-text">display: none</code> or <code class="language-text">visibility: hidden</code>. Both of these would cause the updates to be missed.</p> <p>Another historical way was to add <code class="language-text">text-indent: -9999px</code> to your element, but that has some performance issues since the browser WILL draw a 9999 pixel box on your (even worst on mobile).</p> <p>So what should we do? Well, there are two ways you can do this:</p> <p>Using <code class="language-text">overflow: hidden</code> and small width and height:</p> <div class="gatsby-code-button-container" data-toaster-id="48866310173459610000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.hide-text { position: absolute; width: 1px; height: 1px; overflow: hidden; }`, `48866310173459610000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.hide-text</span> <span class="token punctuation">{</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Or using <code class="language-text">overflow: hidden</code> and <code class="language-text">text-indent: 100%</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="33395265233740080000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.hide-text { text-indent: 100%; white-space: nowrap; overflow: hidden; }`, `33395265233740080000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.hide-text</span> <span class="token punctuation">{</span> <span class="token property">text-indent</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">white-space</span><span class="token punctuation">:</span> nowrap<span class="token punctuation">;</span> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>These are the most efficient ways of hiding text on screen, while keeping the performance in check.</p> <h2 id="code-classlanguage-textaria-atomiccode" style="position:relative;"><a href="#code-classlanguage-textaria-atomiccode" aria-label="code classlanguage textaria atomiccode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">aria-atomic</code></h2> <p>This attribute indicates that the entire region should be considered as whole when communicating updates. Imagine a date widget consisting of day, month and year which has <code class="language-text">aria-live=assertive</code> and <code class="language-text">aria-atomic=true</code>. When the user changes the value of the day, the whole date will be read again.</p> <div class="gatsby-code-button-container" data-toaster-id="83300471182737440000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<input type=&quot;number&quot; value=&quot;02&quot; onchange=&quot;updateDate('day', event)&quot;/>/ <input type=&quot;number&quot; value=&quot;12&quot; onchange=&quot;updateDate('month', event)&quot;/>/ <input type=&quot;number&quot; value=&quot;1983&quot; onchange=&quot;updateDate('year', event)&quot;/> <div class=&quot;user-date&quot; aria-live=&quot;assertive&quot; aria-atomic=&quot;true&quot;> <span id=&quot;day&quot;>02</span>/ <span id=&quot;month&quot;>12</span>/ <span id=&quot;year&quot;>1983</span> </div>`, `83300471182737440000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>number<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>02<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onchange</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">updateDate</span><span class="token punctuation">(</span><span class="token string">'day'</span><span class="token punctuation">,</span> event<span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">/></span></span>/ <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>number<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onchange</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">updateDate</span><span class="token punctuation">(</span><span class="token string">'month'</span><span class="token punctuation">,</span> event<span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">/></span></span>/ <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>number<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1983<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onchange</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">updateDate</span><span class="token punctuation">(</span><span class="token string">'year'</span><span class="token punctuation">,</span> event<span class="token punctuation">)</span></span><span class="token punctuation">"</span></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>user-date<span class="token punctuation">"</span></span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>assertive<span class="token punctuation">"</span></span> <span class="token attr-name">aria-atomic</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>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>day<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>02<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>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>month<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>12<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>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>year<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1983<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>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And for its JavaScript:</p> <div class="gatsby-code-button-container" data-toaster-id="12967963583798348000" data-toaster-class="gatsby-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 updateDate(type, event) { if(event && event.target && event.target.value) { document.querySelector(\`#\${type}\`).textContent = event.target.value; } }`, `12967963583798348000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">updateDate</span><span class="token punctuation">(</span><span class="token parameter">type<span class="token punctuation">,</span> event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>event <span class="token operator">&amp;&amp;</span> event<span class="token punctuation">.</span>target <span class="token operator">&amp;&amp;</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</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 template-string"><span class="token template-punctuation string">`</span><span class="token string">#</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>type<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>textContent <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now if you change the stepper in any of the inputs, the whole date should be read.</p> <div class="custom-block warning"><div class="custom-block-body"> ⚠ The above did not work with windows narrator. However, <a href="https://chrome.google.com/webstore/detail/chromevox-classic-extensi/kgejglhpjiefppelpmljglcjbhoiplfn" target="_blank" rel="nofollow noopener noreferrer">ChromeVox</a>, a Chrome extension I use for accessibility testing, worked as expected.</div></div> <h2 id="what-else" style="position:relative;"><a href="#what-else" aria-label="what else permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What else?</h2> <p>There are other useful attributes you might want to look at:</p> <ul> <li><code class="language-text">aria-relevant</code>: which indicates what types of changes should be presented to the user.</li> <li><code class="language-text">aria-busy</code>: which lets you notify assistive technology that it should temporarily ignore changes to an element, such as when things are loading.</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>We discussed the what, the how and the why of <code class="language-text">aria-live</code> so far. We also saw how to hide the text without losing the ability to communicating updates to users, and furthermore, saw how to make the whole area atomically live using <code class="language-text">aria-atomic</code>.</p> <p>Hope this helps you with your journey to make web a more inclusive place for everybody, and happy coding.</p><![CDATA[Let's get to know the ResizeObserver 👋🏼]]>https://yashints.dev/blog/2019/09/05/resize-observerhttps://yashints.dev/blog/2019/09/05/resize-observerThu, 05 Sep 2019 00:00:00 GMT<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver" target="_blank" rel="nofollow noopener noreferrer">Resize Observer</a> API is another great JavaScript API which lets you get notified when the size of an element changes. Think <code class="language-text">window.onresize</code> but on element level.</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 most common case when the size of an element could change is when the viewport is resized. Or in terms of mobile device the orientation changes.</p> <p>Prior to <code class="language-text">ResizeObserver</code> you would have to hook into <code class="language-text">window.onresize</code> or use <code class="language-text">window.resize</code> to be able to figure out whether an element’s size has changed or not. This was very inefficient since it would trigger so many events.</p> <p>Another scenario where this API can come handy is when you add/remove an element dynamically, in which case the size of the parent changes and not the viewport.</p> <blockquote> <p>The <code class="language-text">ResizeObserver</code> interface reports changes to the dimensions of an <code class="language-text">Element</code>’s content or border box, or the bounding box of an <code class="language-text">SVGElement</code>.</p> </blockquote> <p>The content box is the box in which content can be placed, meaning the border box minus the padding and border width. The border box encompasses the content, padding, and border.</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: 38.148148148148145%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAABkElEQVR42mNw840OiEz1CY1y8w3wDAzyCgjyhKDAIFe/YCDDKxAmAkWBzl4BVg5+QMRg5+K38Ujtnkud+86WHTibe+Bs3sFz+QfP5R04l7/9VPX+swVANhwdOJN34krJ0cslQF3mtj5Azf6Hz+R3dXX0d65urZ1dUzSjqhCEgIz+1qV1JTOrCqZDRKoLZ1QUzKyqrD52rsDJw9/MxofB3tVv87HyjpYZ8xa/mr/vw4xNb6eufzttw9sJa9/0rnvdt+bN9A1vp24AC25+O2XWm57WhdtPVTh4BJjbgG3ecbywpryvsfZac9+Nlt4brWCyqfdGz8w7zb0IkdYJN5obblSXTt59qsgRotnW2e/0+eJ5i0onT6meNrV6KhI5f2HX9Gm1U6dUwUWAambPL710rczR3R/kZ2CgTZybvnpH7pKNGUs3ZizZmA4nZ6wqWLwhE1lk8Yb0lVuzZyxJt3Hys7DzZbCw87FxiXDySrC0DzUw9TI08zEy94GQxubecDaENDL3tXWJtnYMs7D3tbT3BQC4keqkY52fFQAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Box model" title="" src="/static/50b7eadf4d9c73b344120ffabb2e09fc/302a4/box-model.png" srcset="/static/50b7eadf4d9c73b344120ffabb2e09fc/01bf6/box-model.png 270w, /static/50b7eadf4d9c73b344120ffabb2e09fc/07484/box-model.png 540w, /static/50b7eadf4d9c73b344120ffabb2e09fc/302a4/box-model.png 1080w, /static/50b7eadf4d9c73b344120ffabb2e09fc/cd138/box-model.png 1220w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <h2 id="enough-talking-shoe-me-the-code-" style="position:relative;"><a href="#enough-talking-shoe-me-the-code-" aria-label="enough talking shoe me 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>Enough talking, shoe me the code 😉</h2> <p>In its simplest form, you can use <code class="language-text">ResizeObserver</code> by just instantiating a new instance of the API and pass a call-back to it.</p> <div class="gatsby-code-button-container" data-toaster-id="49160002904313970000" data-toaster-class="gatsby-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 myObserver = new ResizeObserver(entries => { // iterate over the entries, do something. });`, `49160002904313970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> myObserver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ResizeObserver</span><span class="token punctuation">(</span><span class="token parameter">entries</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// iterate over the entries, do something.</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>By itself, this wouldn’t help much, however if you call the <code class="language-text">observe</code> method on the instance and give it an element, it will start capturing it’s size changes and calls your call-back function.</p> <div class="gatsby-code-button-container" data-toaster-id="97227559084541170000" data-toaster-class="gatsby-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 myEl = document.querySelector('.my-element'); myObserver.observe(myEl);`, `97227559084541170000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> myEl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.my-element'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObserver<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>myEl<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Now whenever my element’s size changes, it will trigger the call-back and voila.</p> <h2 id="call-back-input-object" style="position:relative;"><a href="#call-back-input-object" aria-label="call back input 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>call-back input object</h2> <p>When you pass a call-back to the constructor of the API, what you get is an array of objects which look like below:</p> <p><img src="/3ac48867d1829098a61c99d61abc3c26/resizeobserverentry.jpg" alt="ResizeObserver Entry"></p> <p>As you can see, the object you get has two properties, <strong><code class="language-text">contentRect</code></strong> and <code class="language-text">target</code>. Target is obvious, it’s the DOM element itself. The <code class="language-text">width</code> and <code class="language-text">height</code> values on the <strong><code class="language-text">contentRect</code></strong> don’t include the padding unlike the element’s <code class="language-text">getBoundingClientRect</code>.</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 do a lot with this API, from changing the font size based on the element’s size to change the styling when the size changes. Below is one where I’m changing the border radios based on element’s size. Resize your window and see what happens 😎.</p> <iframe height="265" style="width: 100%;" scrolling="no" title="ResizeObserver" src="//codepen.io/yashints/embed/QWLaMej/?height=265&theme-id=0&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/QWLaMej/'>ResizeObserver</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <h2 id="demo-explained" style="position:relative;"><a href="#demo-explained" aria-label="demo explained permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 explained</h2> <p>The demo is not that complex, we have a <code class="language-text">div</code> which is got two children:</p> <div class="gatsby-code-button-container" data-toaster-id="78516331885161940000" data-toaster-class="gatsby-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;boxes&quot;> <div class=&quot;box&quot;></div> <div class=&quot;box&quot;></div> </div>`, `78516331885161940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>boxes<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>box<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>box<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>We add a bit of styling so we can see the changes:</p> <div class="gatsby-code-button-container" data-toaster-id="48855189092659640000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.boxes { display: flex; flex-wrap: wrap; width: 40vw; margin-bottom: 50px; } .box { height: 200px; flex-shrink: 1; flex-grow: 1; margin: 10px; box-sizing: border-box; border: 3px solid black; }`, `48855189092659640000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">.boxes</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span> <span class="token property">flex-wrap</span><span class="token punctuation">:</span> wrap<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 40vw<span class="token punctuation">;</span> <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.box</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span> <span class="token property">flex-shrink</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token property">flex-grow</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span> <span class="token property">box-sizing</span><span class="token punctuation">:</span> border-box<span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> 3px solid black<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Once we’re done, we add our little snippet to get the observer notify us of changes:</p> <div class="gatsby-code-button-container" data-toaster-id="14862413057866197000" data-toaster-class="gatsby-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 ro = new ResizeObserver(entries => { for (let entry of entries) { entry.target.style.borderRadius = Math.max(0, 250 - entry.contentRect.width) + 'px' } }) console.log('horay'); // Only observe the 2nd box ro.observe( document.querySelector('.box:nth-child(2)') )`, `14862413057866197000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> ro <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ResizeObserver</span><span class="token punctuation">(</span><span class="token parameter">entries</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">let</span> entry <span class="token keyword">of</span> entries<span class="token punctuation">)</span> <span class="token punctuation">{</span> entry<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>borderRadius <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">250</span> <span class="token operator">-</span> entry<span class="token punctuation">.</span>contentRect<span class="token punctuation">.</span>width<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'px'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'horay'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Only observe the 2nd box</span> ro<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">'.box:nth-child(2)'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In the call-back, we simply change the border radios based on width of the element, and voila.</p> <h2 id="browser-support" style="position:relative;"><a href="#browser-support" aria-label="browser support permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Browser support</h2> <p><a href="https://caniuse.com/#feat=resizeobserver" target="_blank" rel="nofollow noopener noreferrer">Browser support</a> is there for most major browsers, we have Chrome 64+, Firefox 69+, Microsoft Edge 76, and Safari 13-TP supporting the API, but a poor support on mobile browsers.</p> <p>Have fun exploring the API and do some cool stuff with it 😍.</p><![CDATA[Let's write HTML like a pro 😎]]>https://yashints.dev/blog/2019/09/03/html-best-practiceshttps://yashints.dev/blog/2019/09/03/html-best-practicesTue, 03 Sep 2019 00:00:00 GMT<p>How often have you wrote a block of HTML without realising the code you’ve written might not be ideal?</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><code class="language-text">HTML</code> has always been that kid in the corner where nobody talks to because <code class="language-text">JavaScript</code> and <code class="language-text">CSS</code> have always stolen the attention.</p> <p>Now keep that picture in your mind cause I am going to go through some simple tips which together, make a difference and help bring that kid in the centre again 😁.</p> <p>These are part of a perspective of creating a clean, maintainable and scalable code, that will make a good use of the semantic markup elements of <code class="language-text">HTML5</code> and that will render correctly in supported browsers.</p> <p>So just to stop me from going on and on about why, let’s have a look at the what.</p> <h2 id="doctype" style="position:relative;"><a href="#doctype" aria-label="doctype permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>DOCTYPE</h2> <p>Starting from the top of your <code class="language-text">index.html</code>, make sure you’re declaring a <code class="language-text">DOCTYPE</code>. This will activate the standard mode in all browsers and let them know how the document should be interpreted. Keep in mind that <code class="language-text">DOCTYPE</code> is not an HTML element.</p> <p>For <code class="language-text">HTML5</code> it looks like:</p> <div class="gatsby-code-button-container" data-toaster-id="22096877096135705000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE html>`, `22096877096135705000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p><strong>Note:</strong> If you’re using a framework, this is prepopulated for you. If not, I highly recommend using code snippets like <a href="https://code.visualstudio.com/docs/editor/emmet" target="_blank" rel="nofollow noopener noreferrer">Emmet</a> which is available in <a href="https://code.visualstudio.com" target="_blank" rel="nofollow noopener noreferrer">VS Code</a>.</p> <p><img src="/bbb023577349366babf2ae19bfa615c1/emmet.gif" alt="Emmet to the rescue"></p> <p>Curious to find out more about other doc types? <a href="https://html.com/tags/doctype/" target="_blank" rel="nofollow noopener noreferrer">Have a look at this reference document</a>.</p> <h2 id="optional-tags" style="position:relative;"><a href="#optional-tags" aria-label="optional tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Optional tags</h2> <p>Some tags are optional in HTML5, mostly because the element is implicitly present. Believe it or not, you can omit the <code class="language-text">&lt;html></code> tag and the page will render just fine.</p> <div class="gatsby-code-button-container" data-toaster-id="48126946185422130000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE HTML> <head> <title>Hello</title> </head> <body> <p>Welcome to this example.</p> </body> </html>`, `48126946185422130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">HTML</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</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>Welcome to this example.<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>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Above is a valid <code class="language-text">HTML</code>, however, there are some cases where you can’t do so, such as tags followed by comments:</p> <div class="gatsby-code-button-container" data-toaster-id="32640028752900153000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE HTML> <!-- where is this comment in the DOM? --> <head> <title>Hello</title> </head> <body> <p>Welcome to this example.</p> </body> </html>`, `32640028752900153000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">HTML</span><span class="token punctuation">></span></span> <span class="token comment">&lt;!-- where is this comment in the DOM? --></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</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>Welcome to this example.<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>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Above is invalid because the parse tree changes due to comment being outside of <code class="language-text">&lt;html></code> tag.</p> <h2 id="closing-tags" style="position:relative;"><a href="#closing-tags" aria-label="closing tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Closing tags</h2> <p>You should always consider closing your tags because some browsers will have trouble rendering your page. However, it’s recommended to keep those for readability and other reasons which I will go through later.</p> <div class="gatsby-code-button-container" data-toaster-id="43591586087628770000" data-toaster-class="gatsby-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 id=&quot;example&quot;> <img src=&quot;example.jpg&quot; alt=&quot;example&quot; /> <a href=&quot;#&quot; title=&quot;test&quot;>example</a> <p>example</p> </div>`, `43591586087628770000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>example<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">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>example.jpg<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>example<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">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>test<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>example<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>p</span><span class="token punctuation">></span></span>example<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Above are all valid tags. But there are also some exceptions 👇🏼 to this rule.</p> <p>Self-closing tags are valid, but not required. These elements include:</p> <div class="gatsby-code-button-container" data-toaster-id="72722727350874325000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<br>, <hr>, <img>, <input>, <link>, <meta>, <area>, <base>, <col>, <command>, <embed>, <keygen>, <param>, <source>, <track>, <wbr>`, `72722727350874325000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</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 punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>area</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>base</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>col</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>command</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>embed</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>keygen</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>track</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>wbr</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p><strong>Note:</strong> Normal elements can never have self-closing tags.</p> <div class="gatsby-code-button-container" data-toaster-id="64497523786631600000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<title />`, `64497523786631600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Above is invalid obviously.</p> <h2 id="charset" style="position:relative;"><a href="#charset" aria-label="charset permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Charset</h2> <p>Define your character set upfront. It is best practice to put it right on top inside <code class="language-text">&lt;head></code> element.</p> <div class="gatsby-code-button-container" data-toaster-id="28782502868921920000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<head> <title>This is a super duper cool title, right 😥?</title> <meta charset=&quot;utf-8&quot;> </head>`, `28782502868921920000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>This is a super duper cool title, right 😥?<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-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>head</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Above is invalid and title wouldn’t render properly. Instead move the character set deceleration on top.</p> <div class="gatsby-code-button-container" data-toaster-id="80794097594969300000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<head> <meta charset=&quot;utf-8&quot;> <title>This is a super duper cool title, right 😃?</title> </head>`, `80794097594969300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-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>title</span><span class="token punctuation">></span></span>This is a super duper cool title, right 😃?<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="language" style="position:relative;"><a href="#language" aria-label="language permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Language</h2> <p>Another reason to not omit the optional tags is when using attributes. In this case you can and you should define the language of your web page. This is really important for accessibility and searching.</p> <div class="gatsby-code-button-container" data-toaster-id="9646530439646274000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<html lang=&quot;fr-CA&quot;> ... </html>`, `9646530439646274000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fr-CA<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>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="title" style="position:relative;"><a href="#title" aria-label="title permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Title</h2> <p>Never, never, ever omit the title tag. It’s super bad for accessibility, and I will personally never use your site because I can’t find it 2 seconds after opening it and 20 more tabs later 😁 (the browser tab won’t have anything to show).</p> <h2 id="the-code-classlanguage-textbasecode-tag" style="position:relative;"><a href="#the-code-classlanguage-textbasecode-tag" aria-label="the code classlanguage textbasecode tag permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">base</code> tag</h2> <p>This is a really useful tag which should be used with cautious. This will set the base URL for the app. Once set, all links will be relative to this base URL, which might cause some unwanted behaviour:</p> <div class="gatsby-code-button-container" data-toaster-id="16890454168961133000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<base href=&quot;http://www.example.com/&quot; />`, `16890454168961133000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>base</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>http://www.example.com/<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>With above set, <code class="language-text">href="#internal"</code> will be interpreted as <code class="language-text">href="http://www.example.com/#internal"</code>.</p> <p>Or <code class="language-text">href="example.org"</code> will be interpreted as <code class="language-text">href="http://www.example.com/example.org"</code>.</p> <h2 id="description" style="position:relative;"><a href="#description" aria-label="description permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Description</h2> <p>This meta tag is very useful although it’s not strictly part of best practices. This is super useful for search engines when they crawl your site.</p> <div class="gatsby-code-button-container" data-toaster-id="28373414053650924000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<meta name=&quot;description&quot; content=&quot;HTML best practices&quot;>`, `28373414053650924000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>description<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>HTML best practices<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>I have a <a href="https://yashints.dev/blog/2019/06/11/seo-tips" target="_blank" rel="nofollow noopener noreferrer">post you can check on SEO which has been super popular</a>.</p> <h2 id="semantic-tags" style="position:relative;"><a href="#semantic-tags" aria-label="semantic tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Semantic tags</h2> <p>Although you can create your UX engineer’s wire frames with just <code class="language-text">div</code>s, it doesn’t mean you should. <a href="https://www.w3schools.com/html/html5_semantic_elements.asp" target="_blank" rel="nofollow noopener noreferrer">Semantic HTML</a> gives meaning to your page rather than just presentations. Tags like <code class="language-text">p</code>, <code class="language-text">section</code>, <code class="language-text">h</code>{1-6}, <code class="language-text">main</code>, <code class="language-text">nav</code>, etc are all semantic tags. If you use a <code class="language-text">p</code> tag, users will know this represents a paragraph of text and browsers know how to represent them.</p> <p>On the other hand, tags like <code class="language-text">i</code> and <code class="language-text">b</code> do not represent semantics. They just try to define how the text should look like. Semantic HTML is way beyond the scope of this article. But you should defo <a href="https://developer.mozilla.org/en-US/docs/Glossary/Semantics" target="_blank" rel="nofollow noopener noreferrer">check them out</a> and use them as if they’re your pen when you’re writing. Can you write without a pen ❓ (or mouse 😁)?</p> <h2 id="code-classlanguage-texthrcode-shouldnt-be-used-for-formatting" style="position:relative;"><a href="#code-classlanguage-texthrcode-shouldnt-be-used-for-formatting" aria-label="code classlanguage texthrcode shouldnt be used for formatting permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">hr</code> shouldn’t be used for formatting</h2> <p><code class="language-text">&lt;hr></code> is not a formatting element, so stop using it to format your content. In HTML5 this tag represents a thematic break of your content. A proper use of it might look like this:</p> <div class="gatsby-code-button-container" data-toaster-id="76305802202918160000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<p>Paragraph about puppies</p> <p>Paragraph about puppies' favourite foods</p> <p>Paragraph about puppies' breeds</p> <hr> <p>Paragraph about why I am shaving my head 😂</p>`, `76305802202918160000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Paragraph about puppies<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 punctuation">></span></span>Paragraph about puppies' favourite foods<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 punctuation">></span></span>Paragraph about puppies' breeds<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>hr</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>Paragraph about why I am shaving my head 😂<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="be-careful-when-you-use-the-code-classlanguage-texttitlecode-attribute" style="position:relative;"><a href="#be-careful-when-you-use-the-code-classlanguage-texttitlecode-attribute" aria-label="be careful when you use the code classlanguage texttitlecode attribute permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Be careful when you use the <code class="language-text">title</code> attribute</h2> <p>The <code class="language-text">title</code> attribute is a powerful tool which can help clarify an action or the purpose of an element on the page like a tooltip. However, it’s not interchangeable with other attributes like <code class="language-text">alt</code> on an image.</p> <p>From the HTML5 spec:</p> <blockquote> <p>Relying on the <code class="language-text">title</code> attribute is currently discouraged as many user agents do not expose the attribute in an accessible manner as required by this specification (e.g., requiring a pointing device such as a mouse to cause a tooltip to appear, which excludes keyboard-only users and touch-only users, such as anyone with a modern phone or tablet).</p> </blockquote> <p><a href="https://html.spec.whatwg.org/multipage/dom.html#the-title-attribute" target="_blank" rel="nofollow noopener noreferrer">Read more about how to properly use this attribute</a>.</p> <h2 id="single-or-double-quotes" style="position:relative;"><a href="#single-or-double-quotes" aria-label="single or double quotes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Single or double quotes</h2> <p>I’ve faced many code bases where there are a mix of both in the markup. This is not good especially if you are using a framework which depends on single quote like <code class="language-text">php</code> and also when <em><code class="language-text">you're</code></em> using a single quote in a sentence just like I did now. Another reason is to keep it consistent which is always good. Don’t do:</p> <div class="gatsby-code-button-container" data-toaster-id="38076721623060660000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img alt=&quot;super funny meme&quot; src='/img/meme.jpg'>`, `38076721623060660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>super funny meme<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>/img/meme.jpg<span class="token punctuation">'</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Instead:</p> <div class="gatsby-code-button-container" data-toaster-id="32223009333354803000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img alt=&quot;super funny meme&quot; src=&quot;/img/meme.jpg&quot;>`, `32223009333354803000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>super funny meme<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>/img/meme.jpg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h2 id="omit-boolean-values" style="position:relative;"><a href="#omit-boolean-values" aria-label="omit boolean values permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Omit boolean values</h2> <p>When it comes to having boolean values for attributes, it’s recommended to omit those as they don’t add any value and also increase your markup’s weight.</p> <div class="gatsby-code-button-container" data-toaster-id="83288060417531820000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<audio autoplay=&quot;autoplay&quot; src=&quot;podcast.mp3&quot;> <!-- instead 👇🏼 --> <audio autoplay src=&quot;podcast.mp3&quot;>`, `83288060417531820000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>audio</span> <span class="token attr-name">autoplay</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>autoplay<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>podcast.mp3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token comment">&lt;!-- instead 👇🏼 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>audio</span> <span class="token attr-name">autoplay</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>podcast.mp3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="omit-type-attribute" style="position:relative;"><a href="#omit-type-attribute" aria-label="omit type attribute permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Omit type attribute</h2> <p>There is no need to add <code class="language-text">type</code> attribute to <code class="language-text">script</code>and <code class="language-text">style</code> tags. You also get a validation error from some services such as <a href="#validate-your-markup">W3C’s markup validation tool</a>.</p> <h2 id="validate-your-markup" style="position:relative;"><a href="#validate-your-markup" aria-label="validate your markup permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Validate your markup</h2> <p>You can use services like <a href="http://validator.w3.org/" target="_blank" rel="nofollow noopener noreferrer">W3C’s markup validation</a> to make sure you have a valid markup 😍.</p> <h2 id="say-no-to-inline-style-" style="position:relative;"><a href="#say-no-to-inline-style-" aria-label="say no to inline style permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Say no to inline style ☢</h2> <p>What you write in your HTML file is the content, how it looks like is presentation. Leave the presentation to CSS and don’t use inline styles. This will benefit both your developers and browsers to digest your mark up.</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>These are just a tip of the iceberg in terms of small things to keep in mind when writing markup. There are heaps of good resources you can have a look for deeper insights, and I highly recommend you to skim through them at least once.</p> <ul> <li><a href="https://github.com/hail2u/html-best-practices" target="_blank" rel="nofollow noopener noreferrer">HTML best practices on GitHub</a></li> <li><a href="https://www.w3schools.com/html/html5_syntax.asp" target="_blank" rel="nofollow noopener noreferrer">W3C school HTML style guide</a></li> </ul> <p>Hope you’ve enjoyed the read. And stay classy 😊, with your markup 😁.</p><![CDATA[JavaScript modules, the good, the bad and the ugly 🧐]]>https://yashints.dev/blog/2019/08/27/js-moduleshttps://yashints.dev/blog/2019/08/27/js-modulesTue, 27 Aug 2019 00:00:00 GMT<p>If you ever stumbled upon a piece of vanilla JavaScript code and wanted to refactor it to a module, or have a <code class="language-text">CommonJS</code> module and want to convert it to <a href="https://tc39.es/ecma262/#sec-modules" target="_blank" rel="nofollow noopener noreferrer"><code class="language-text">ES6 Modules</code></a>, you might have faced a couple of tricky situations. I had to go through one of those recently and stumbled upon some differences/points that you need to be aware of when working with modules. As always, thought sharing these would help someone else, so here we go 😊.</p> <!--more--> <h2 id="commonjs--code-classlanguage-textrequirecode" style="position:relative;"><a href="#commonjs--code-classlanguage-textrequirecode" aria-label="commonjs code classlanguage textrequirecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CommonJS &#x26; <code class="language-text">require</code></h2> <p>This is the most common type of code seen on many open source projects before ES6 was put on earth by the GODS 😁.</p> <h3 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</h3> <div class="gatsby-code-button-container" data-toaster-id="65857090657445224000" data-toaster-class="gatsby-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 _ = require('underscore'); // from an npm package const reverseString = require('./reverseString.js'); // from internal module`, `65857090657445224000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> _ <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'underscore'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// from an npm package </span> <span class="token keyword">const</span> reverseString <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./reverseString.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// from internal module</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="definition" style="position:relative;"><a href="#definition" aria-label="definition permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Definition</h3> <p>In the <code class="language-text">reverseString.js</code> you would need to write something like this to get it working:</p> <div class="gatsby-code-button-container" data-toaster-id="61994874409942050000" data-toaster-class="gatsby-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 reverseString = (sentence) => sentence.split(&quot;&quot;).reverse().join(&quot;&quot;); module.exports = reverseString;`, `61994874409942050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">reverseString</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</span> <span class="token operator">=></span> sentence<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 function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> reverseString<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>The only thing you need to pay attention to is that the value you assign to <code class="language-text">module.exports</code> is the same you get when using <code class="language-text">require</code>. And if you want to use the function you just exported:</p> <div class="gatsby-code-button-container" data-toaster-id="32529811813270970000" data-toaster-class="gatsby-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 reverseString = require('./reverseString.js'); console.log(reverseString(&quot;madam&quot;)); // madam, gotcha 😂`, `32529811813270970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> reverseString <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./reverseString.js'</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 function">reverseString</span><span class="token punctuation">(</span><span class="token string">"madam"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// madam, gotcha 😂</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="multi-export" style="position:relative;"><a href="#multi-export" aria-label="multi export permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Multi export</h3> <p>In real life situations, we will need to export more than one function from our module. This is as easy as wrapping all of those in an object. Imagine you have a file called <code class="language-text">stringHelpers.js</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="70506661830052870000" data-toaster-class="gatsby-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 reverseString = (sentence) => {...}; const toUpperCase = (sentence) => {...}; const convertToCamelCase = (sentence) => {...}; module.exports = { reverseString: reverseString, toUpperCase, // you can omit the assignment if the name is equal toLowerCase: convertToLowerCase, };`, `70506661830052870000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">reverseString</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token keyword">const</span> <span class="token function-variable function">toUpperCase</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token keyword">const</span> <span class="token function-variable function">convertToCamelCase</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">reverseString</span><span class="token operator">:</span> reverseString<span class="token punctuation">,</span> toUpperCase<span class="token punctuation">,</span> <span class="token comment">// you can omit the assignment if the name is equal</span> <span class="token literal-property property">toLowerCase</span><span class="token operator">:</span> convertToLowerCase<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see, the value of the <code class="language-text">module.exports</code> will be an object, which means when using it, you will have to use the properties on the object:</p> <div class="gatsby-code-button-container" data-toaster-id="44636423396352590000" data-toaster-class="gatsby-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 stringHelpers = require('./stringHelpers.js'); console.log(stringHelpers.reverseString('racecar')); // racecar 🤣`, `44636423396352590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> stringHelpers <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./stringHelpers.js'</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>stringHelpers<span class="token punctuation">.</span><span class="token function">reverseString</span><span class="token punctuation">(</span><span class="token string">'racecar'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// racecar 🤣</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>We can also rewrite our module in a different way:</p> <div class="gatsby-code-button-container" data-toaster-id="65639632111223990000" data-toaster-class="gatsby-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 = {}; module.exports.reverseString = () => {...}; module.exports.toUpperCase = () => {...}; module.exports.toLowerCase = () => {...};`, `65639632111223990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span><span class="token function-variable function">reverseString</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 operator">...</span><span class="token punctuation">}</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span><span class="token function-variable function">toUpperCase</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 operator">...</span><span class="token punctuation">}</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span><span class="token function-variable function">toLowerCase</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 operator">...</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>These two ways of creating the module are exactly the same, it’s up to you which convention to follow.</p> <h2 id="es6-modules" style="position:relative;"><a href="#es6-modules" aria-label="es6 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>ES6 Modules</h2> <p><a href="https://tc39.es/ecma262/#sec-modules" target="_blank" rel="nofollow noopener noreferrer">ES6 Modules</a> is created to create a format which both <code class="language-text">CommonJS</code> and <code class="language-text">AMD</code> (Async Module Definition) users are happy with. In their simplest form compared to <code class="language-text">CommonJS</code> approach, ES6 Modules <em><strong>always</strong></em> export an object.</p> <div class="gatsby-code-button-container" data-toaster-id="85696601922830220000" data-toaster-class="gatsby-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 reverseString = (sentence) => {...}; export default reverseString;`, `85696601922830220000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">reverseString</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token keyword">export</span> <span class="token keyword">default</span> reverseString<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="default-export" style="position:relative;"><a href="#default-export" aria-label="default export permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Default export</h3> <p>One of the major benefits of having modules are to hide the internal implementation details and expose only what’s needed. In this case I am just exporting one function, and in addition I am exporting it as <code class="language-text">default</code>. When you export something as <code class="language-text">default</code>, you get to import it with their original name or even an alias. Plus you get to omit the curly braces.</p> <div class="gatsby-code-button-container" data-toaster-id="2829056434987142700" data-toaster-class="gatsby-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 reverseString from './reverseString.js'; import defaultExport from './reverseString.js'; console.log(reverseString('madam')); //madam console.log(defaultExport('madam')); //madam`, `2829056434987142700`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> reverseString <span class="token keyword">from</span> <span class="token string">'./reverseString.js'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> defaultExport <span class="token keyword">from</span> <span class="token string">'./reverseString.js'</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 function">reverseString</span><span class="token punctuation">(</span><span class="token string">'madam'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//madam</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">defaultExport</span><span class="token punctuation">(</span><span class="token string">'madam'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//madam</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><img src="/cf5441038e2c4e6740a3da2df16b9353/madeup.gif" alt="Made up name gif"></p> <p>If you look into the object which is exported from the file, you will see below object:</p> <div class="gatsby-code-button-container" data-toaster-id="46011014728996405000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ default: (sentence) => {...} }`, `46011014728996405000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">{</span> <span class="token function-variable function">default</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>You can also export the function directly:</p> <div class="gatsby-code-button-container" data-toaster-id="85153170444034410000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export const reverseString = (sentence) => {...};`, `85153170444034410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">reverseString</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Which will result in:</p> <div class="gatsby-code-button-container" data-toaster-id="17904776422523950000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ reverseString: (sentence) => {...} }`, `17904776422523950000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">{</span> <span class="token function-variable function">reverseString</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>In which case you will need to use its name to be able to import it, plus you have to use curly braces:</p> <div class="gatsby-code-button-container" data-toaster-id="86326136106276930000" data-toaster-class="gatsby-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 { reverseString } from './reverseString.js'; console.log(reverseString('madam')); //madam`, `86326136106276930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> reverseString <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./reverseString.js'</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 function">reverseString</span><span class="token punctuation">(</span><span class="token string">'madam'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//madam</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="mixed-export" style="position:relative;"><a href="#mixed-export" aria-label="mixed export permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Mixed export</h3> <p>You can also have a default export alongside named ones:</p> <div class="gatsby-code-button-container" data-toaster-id="57488505636038090000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export const reverseString = (sentence) => {...}; export const toUpperCase = (sentence) => {...}; const convertToCamelCase = (sentence) => {...}; export default convertToCamelCase;`, `57488505636038090000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">reverseString</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">toUpperCase</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token keyword">const</span> <span class="token function-variable function">convertToCamelCase</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token keyword">export</span> <span class="token keyword">default</span> convertToCamelCase<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Which then will give you:</p> <div class="gatsby-code-button-container" data-toaster-id="65104769612333180000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ reverseString: (sentence) => {...}, toUpperCase: (sentence) => {...}, default: (sentence) => {...} }`, `65104769612333180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">{</span> <span class="token function-variable function">reverseString</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token function-variable function">toUpperCase</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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> <span class="token function-variable function">default</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">sentence</span><span class="token punctuation">)</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And when importing, you can use their names, or import everything in one object:</p> <div class="gatsby-code-button-container" data-toaster-id="3418937197441707000" data-toaster-class="gatsby-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 convertToCamelCase, { reverseString, toUpperCase } from './stringHelpers.js'; // or import * as stringHelpers from './stringHelpers.js';`, `3418937197441707000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> convertToCamelCase<span class="token punctuation">,</span> <span class="token punctuation">{</span> reverseString<span class="token punctuation">,</span> toUpperCase <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./stringHelpers.js'</span><span class="token punctuation">;</span> <span class="token comment">// or</span> <span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> stringHelpers <span class="token keyword">from</span> <span class="token string">'./stringHelpers.js'</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now to be fair, you can change the name of a named export after exporting too:</p> <div class="gatsby-code-button-container" data-toaster-id="71279741454440186000" data-toaster-class="gatsby-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 { reverseString as madeUpName } from './stringHelpers.js';`, `71279741454440186000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> reverseString <span class="token keyword">as</span> madeUpName <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./stringHelpers.js'</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h3 id="importing-the-whole-module" style="position:relative;"><a href="#importing-the-whole-module" aria-label="importing the whole module permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Importing the whole module</h3> <p>Sometimes you have a block of code which needs to be executed without the need to access any of the module’s internal values. In this case you can import the whole module just to have its global code executed:</p> <div class="gatsby-code-button-container" data-toaster-id="51442196827009390000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// other code or possible exports window.addEventListener(&quot;load&quot;, function() { console.log(&quot;Window is loaded&quot;); });`, `51442196827009390000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// other code or possible exports</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"load"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Window is loaded"</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Then import the whole module:</p> <div class="gatsby-code-button-container" data-toaster-id="82916258347388290000" data-toaster-class="gatsby-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 './loadEventListener.js';`, `82916258347388290000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'./loadEventListener.js'</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h2 id="why-should-you-use-modules-" style="position:relative;"><a href="#why-should-you-use-modules-" aria-label="why should you use 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>Why should you use modules 😍?</h2> <p>There are many benefits when it comes to use ES6 Modules (or even CommonJS format). I will go through some of those here:</p> <ul> <li>Ease in sharing the code (both internal and between projects).</li> <li>Independant testability.</li> <li>Having ability to hide the implementation details.</li> <li>Single responsibility principle, code can be split in smaller chunks with a specific purpose.</li> <li>Simplifying dependency detection/injection.</li> <li>Defining clear interface for a block of code.</li> <li>Can be used alongside a dependency injection system to load a block of code.</li> <li>Can help the tree shaking to eliminate unused code.</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>There are a few points you should be aware of while using ES6 Modules:</p> <ul> <li>They are running in strict mode by default (you don’t need to have <code class="language-text">use strict</code> anymore).</li> <li>Top level value of <code class="language-text">this</code> is <code class="language-text">undefined</code>.</li> <li>Top level variables are local to the module.</li> <li>ES6 Modules are loaded and executed asynchronously. This means the browser will finish parsing and loading the <code class="language-text">HTML</code> first, and then executes the module code. The load can be in parallel or be done beforehand using <code class="language-text">link rel=preload</code>.</li> </ul> <h2 id="trick-or-treat" style="position:relative;"><a href="#trick-or-treat" aria-label="trick or treat permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Trick or treat?</h2> <p>This one is probably my favourite part. You can dynamically load the module and execute it. This is done by using the <code class="language-text">import</code> keyword as a function rather than normal command.</p> <div class="gatsby-code-button-container" data-toaster-id="22815745212297610000" data-toaster-class="gatsby-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('/modules/my-module.js') .then((module) => { // Do something with the module. });`, `22815745212297610000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'/modules/my-module.js'</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 punctuation">(</span><span class="token parameter">module</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Do something with the module.</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Or even better:</p> <div class="gatsby-code-button-container" data-toaster-id="7830512250214339000" data-toaster-class="gatsby-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 module = await import('/modules/my-module.js');`, `7830512250214339000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> module <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'/modules/my-module.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h3 id="wow-thats-great-but-why-" style="position:relative;"><a href="#wow-thats-great-but-why-" aria-label="wow thats great but 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>Wow that’s great, but why 🧐?</h3> <p>Suppose you have an application which has different user experience or behaviour for mobile vs desktop. This problem can’t be solved just by having a responsive design, so you build a <em>page renderer</em> which loads and renders each page based on visitor’s platform.</p> <p>Technically this is just a strategy pattern where the page renderer decides which module to load at run time. This can be solved easily using dynamic imports. There are many other use cases out there which can be benefited from dynamic imports.</p> <p>However, with great power, comes great responsibility. You need to be careful when to use this fantastic feature as it has its own drawbacks. At the least, you lose automatic bundling of lazy-loaded chunks, type inference and more.</p> <h2 id="how-can-i-use-them" style="position:relative;"><a href="#how-can-i-use-them" aria-label="how can i use them permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 use them?</h2> <p>I’ve shown you many examples in this article how to consume a module in another file or module. However, sometimes you need to consume them in browser (from <code class="language-text">HTML</code>). Chrome, Safari, Firefox and Edge all support ES6 Modules, however you need to change your script tag’s type from script to module:</p> <div class="gatsby-code-button-container" data-toaster-id="16960299249380784000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// html.js export function tag (tag, text) { const el = document.createElement(tag) el.textContent = text return el }`, `16960299249380784000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// html.js</span> <span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">tag</span> <span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> text</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span> el<span class="token punctuation">.</span>textContent <span class="token operator">=</span> text <span class="token keyword">return</span> el <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="gatsby-code-button-container" data-toaster-id="82447051091133680000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script type=&quot;module&quot;> import { tag } from './html.js' const h1 = tag('h1', ' Hello Modules!') document.body.appendChild(h1) </script>`, `82447051091133680000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>module<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">import</span> <span class="token punctuation">{</span> tag <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./html.js'</span> <span class="token keyword">const</span> h1 <span class="token operator">=</span> <span class="token function">tag</span><span class="token punctuation">(</span><span class="token string">'h1'</span><span class="token punctuation">,</span> <span class="token string">' Hello Modules!'</span><span class="token punctuation">)</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>h1<span class="token punctuation">)</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Or just simply import the module file into another file and use external reference:</p> <div class="gatsby-code-button-container" data-toaster-id="35120113267345654000" data-toaster-class="gatsby-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.js import { tag } from './html.js' const h1 = tag('h1', ' Hello Modules!') document.body.appendChild(h1)`, `35120113267345654000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// app.js</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> tag <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./html.js'</span> <span class="token keyword">const</span> h1 <span class="token operator">=</span> <span class="token function">tag</span><span class="token punctuation">(</span><span class="token string">'h1'</span><span class="token punctuation">,</span> <span class="token string">' Hello Modules!'</span><span class="token punctuation">)</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>h1<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="gatsby-code-button-container" data-toaster-id="83308236288673700000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script type=&quot;module&quot; src=&quot;app.js&quot;></script>`, `83308236288673700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>module<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>app.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p><strong>Tip</strong>: There are still some old browsers out there <strong>cough</strong> IE11 <strong>cough</strong> which doesn’t support it, so make sure you have a back up plan. This can be done using <code class="language-text">nomodule</code> attribute.</p> <div class="gatsby-code-button-container" data-toaster-id="42713259251555050000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script type=&quot;module&quot; src=&quot;module.js&quot;></script> <script nomodule src=&quot;fallback.js&quot;></script>`, `42713259251555050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token operator">&lt;</span>script type<span class="token operator">=</span><span class="token string">"module"</span> src<span class="token operator">=</span><span class="token string">"module.js"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator">&lt;</span>script nomodule src<span class="token operator">=</span><span class="token string">"fallback.js"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We had a look at before and after ES6 Modules and saw some of the differences in syntax. We saw the power of the module system in JavaScript and its benefits when it comes to using it in larger code bases. And at last we reviewed dynamic import which has massive potential but should be used with cautious.</p> <p>Hope you’ve enjoyed the read and till next time 👋🏼.</p><![CDATA[Native lazy loading is landed in Chrome]]>https://yashints.dev/blog/2019/08/25/native-lazyloadinghttps://yashints.dev/blog/2019/08/25/native-lazyloadingSun, 25 Aug 2019 00:00:00 GMT<p>Lazy loading resources is one of the important parts of web performance tuning, simply because offscreen resources can add a lot of weight to your page if loaded eagerly.</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>I’ve gone through many tips and tricks in my <a href="https://yashints.dev/blog/2018/11/12/web-perf-4" target="_blank" rel="nofollow noopener noreferrer">image optimisation article</a> which is <a href="https://dev.to/yashints/improve-html-and-css-performance-4o08" target="_blank" rel="nofollow noopener noreferrer">one of the series I’ve done on web performance</a>. However, when it comes to lazy loading, I mentioned that you have two options:</p> <ul> <li>Use <code class="language-text">data-src</code> attribute on <code class="language-text">&lt;img></code> tag and hook into either of <code class="language-text">scroll</code>, <code class="language-text">resize</code>, or <code class="language-text">orientationChange</code> to figure out when to replace the <code class="language-text">data-src</code> with <code class="language-text">src</code> to make the call.</li> <li>Use <code class="language-text">IntersectionObserver</code> API to asynchronously observe the changes and make the call when the item in is the viewport.</li> </ul> <p>The good news is, from <a href="https://www.google.com.au/chrome/" target="_blank" rel="nofollow noopener noreferrer">Chrome</a> 76, you can use the <code class="language-text">loading</code> attribute of an image tag to tell the browser how to load the image.</p> <p>In fact it’s so simple that you won’t believe it 🤯:</p> <div class="gatsby-code-button-container" data-toaster-id="64653082291502465000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img src=&quot;../path/to/image.jpg&quot; loading=&quot;lazy&quot;>`, `64653082291502465000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>../path/to/image.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">loading</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lazy<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>I’ve created a demo to show you how it works, look closely on the network tab.</p> <p><img src="/1827f7c8b9ed52279a64a0fab330f8d9/loading.gif" alt="Lazy loading images natively in Chorme"></p> <p><a href="https://codepen.io/yashints/pen/VwZpKYY/" target="_blank" rel="nofollow noopener noreferrer">Here is a CodePen which contains the code</a>.</p> <p>I’ve just used below bash script to hack together the HTML 🤷🏽‍♂️.</p> <div class="gatsby-code-button-container" data-toaster-id="79906994837804450000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`for i in {400..499}; > do echo &quot;<img loading='lazy' src='https://placedog.net/\${i}/\${i}' height='\${i}' width='\${i}' />&quot;; > done`, `79906994837804450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token keyword">for</span> <span class="token for-or-select variable">i</span> <span class="token keyword">in</span> <span class="token punctuation">{</span><span class="token number">400</span><span class="token punctuation">..</span><span class="token number">499</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token operator">></span> <span class="token keyword">do</span> <span class="token builtin class-name">echo</span> <span class="token string">"&lt;img loading='lazy' src='https://placedog.net/<span class="token variable">${i}</span>/<span class="token variable">${i}</span>' height='<span class="token variable">${i}</span>' width='<span class="token variable">${i}</span>' />"</span><span class="token punctuation">;</span> <span class="token operator">></span> <span class="token keyword">done</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="about-the-attribute" style="position:relative;"><a href="#about-the-attribute" aria-label="about the attribute permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the attribute</h2> <p>Currently the images are fetched with different priority in <a href="https://www.google.com.au/chrome/" target="_blank" rel="nofollow noopener noreferrer">Chrome</a>, the ones which are not in the viewport have less priority. But they’re fetched as soon as possible regardless.</p> <p>With this new <code class="language-text">loading</code> attribute, you can completely defer the loading of offscreen images (and <strong>iframes</strong>) to when they’re reached by scrolling:</p> <div class="gatsby-code-button-container" data-toaster-id="40137041350829560000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img src=&quot;../path/to/image.jpg&quot; loading=&quot;lazy&quot;> <iframe src=&quot;https://placedog.net&quot; loading=&quot;lazy&quot;></iframe>`, `40137041350829560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>../path/to/image.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">loading</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lazy<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>iframe</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://placedog.net<span class="token punctuation">"</span></span> <span class="token attr-name">loading</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lazy<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>iframe</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>You can use three values with this attribute:</p> <ul> <li><code class="language-text">auto</code>: Default behaviour of the browser, equal to not including the attribute.</li> <li><code class="language-text">lazy</code>: Defer loading of resources until it reaches a <a href="https://web.dev/native-lazy-loading#load-in-distance-threshold" target="_blank" rel="nofollow noopener noreferrer">calculated distance</a> from viewport.</li> <li><code class="language-text">eager</code>: Load the resource immediately</li> </ul> <p>My <a href="https://www.google.com.au/chrome/" target="_blank" rel="nofollow noopener noreferrer">Chrome</a> version is <code class="language-text">76.0.3809.100</code> as of writing this post, but if you have any of the previous version below 76, you can activate this using flags:</p> <ul> <li>For images 👉🏽 <code class="language-text">chrome://flags/#enable-lazy-image-loading</code></li> <li>For iframes 👉🏽 <code class="language-text">chrome://flags/#enable-lazy-frame-loading</code></li> </ul> <h2 id="feature-detection" style="position:relative;"><a href="#feature-detection" aria-label="feature detection permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Feature detection</h2> <p>If you want to use this attribute today, you can use below code to feature detect it and have a polyfill in place such as <a href="https://github.com/mfranzke/loading-attribute-polyfill" target="_blank" rel="nofollow noopener noreferrer">loading-attribute-polyfill</a>.</p> <div class="gatsby-code-button-container" data-toaster-id="68028068747908460000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if ('loading' in HTMLImageElement.prototype === true) { // use the attribute } else { // use polyfill }`, `68028068747908460000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">'loading'</span> <span class="token keyword">in</span> HTMLImageElement<span class="token punctuation">.</span>prototype <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// use the attribute</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// use polyfill</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="prevent-content-reflow" style="position:relative;"><a href="#prevent-content-reflow" aria-label="prevent content reflow permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prevent content reflow</h2> <p>Since the images are lazy loaded, if you haven’t set <code class="language-text">width</code> and <code class="language-text">height</code> for your image, the content might reflow when the image is loaded and fill its place. To prevent that to happen, simply set the required values on the image tag by either <code class="language-text">style</code> or directly using <code class="language-text">width</code> and <code class="language-text">height</code> attributes:</p> <div class="gatsby-code-button-container" data-toaster-id="49615427474285760000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img src=&quot;../path/to/image.jpg&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;200&quot;> <img src=&quot;../path/to/image.jpg&quot; loading=&quot;lazy&quot; style=&quot;height:200px; width:200px;&quot;>`, `49615427474285760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>../path/to/image.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">loading</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lazy<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<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">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>../path/to/image.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">loading</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lazy<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">height</span><span class="token punctuation">:</span>200px<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span>200px<span class="token punctuation">;</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="iframe-loading" style="position:relative;"><a href="#iframe-loading" aria-label="iframe loading permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>iframe loading</h2> <p>The same behaviour is applied to <code class="language-text">iframe</code> when it’s used with <code class="language-text">loading</code> attribute. However, there are times when an iframe is hidden for analytics purposes. Examples are they are very small (less than <code class="language-text">4px</code> in width and height), or they have <code class="language-text">display:none</code> or <code class="language-text">visibility: hidden</code> applied to them, or simply is offscreen using negative margin.</p> <p>In these cases it won’t get lazy loaded even if you have used the attribute.</p> <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>There are few points you have to consider when using lazy loading in general. Plus there are a few things you can’t do with the <code class="language-text">loading</code> attribute as of now.</p> <p><strong>Can’t do</strong></p> <ul> <li>You can’t change the threshold to load the resource for now since it’s been hard coded in the source.</li> <li>This can’t be used with CSS’ background image for now</li> </ul> <p><strong>Catches</strong></p> <ul> <li>This might affect the third party ads since they will be lazy loaded too</li> <li>There will be side effect when printing 😉, as in the lazy loaded resources won’t be printed. However, there is an <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=875403" target="_blank" rel="nofollow noopener noreferrer">open issue</a> you can follow.</li> </ul> <h2 id="what-about-other-browsers" style="position:relative;"><a href="#what-about-other-browsers" aria-label="what about other browsers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 about other browsers?</h2> <p>For now, <a href="https://www.google.com.au/chrome/" target="_blank" rel="nofollow noopener noreferrer">Chrome</a> is the only browser supporting this feature. Although there is an <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1542784" target="_blank" rel="nofollow noopener noreferrer">open bug for Firefox</a> and nothing for Edge and IE.</p> <p>Happy lazy loading everybody and make sure not to miss the catches 👋🏽.</p><![CDATA[Let's setup a VPN server, for free, on AWS, under 5 min]]>https://yashints.dev/blog/2019/08/21/vpn-awshttps://yashints.dev/blog/2019/08/21/vpn-awsWed, 21 Aug 2019 00:00:00 GMT<p>Sometimes you want to connect to internet without someone watching you. This can be due to restrictions applied by governments, ISPs, etc. Maintaining privacy while using internet is very important to some people, and for me personally, the experience was to bypass a ridiculous censor on sites like Twitter and software like Telegram.</p> <!--more--> <p>So I thought how hard can it be to setup a VPN server (because I didn’t want to pay $5 per month) for a web developer. After Googling a bit, I found out you could easily do this on AWS for free using <a href="https://openvpn.net/" target="_blank" rel="nofollow noopener noreferrer">OpenVPN</a>. I started setting it up and a couple of mins later I had it up and running.</p> <blockquote> <p><a href="https://openvpn.net/" target="_blank" rel="nofollow noopener noreferrer">OpenVPN</a> is a popular open-source tool that is well tested and give you a production ready VPN solution.</p> </blockquote> <p>So just to not forget how I did it, as usual I thought let’s write up something, and who knows, maybe it was useful to you too 😉.</p> <p>So are you ready?</p> <h2 id="aws-console" style="position:relative;"><a href="#aws-console" aria-label="aws console permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>AWS console</h2> <p>If you don’t have an account on <a href="https://aws.amazon.com/" target="_blank" rel="nofollow noopener noreferrer">AWS (Amazon Web Services)</a>, go ahead and create one. It’s free, but you will need to have your credit card info handy.</p> <p>Once signed up, login and under the services menu look for EC2 (you can type and it will filter the services as you type).</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/db3d399d267774478d124f4853a0fa21/f43b1/awsservices.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 40%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB2wQH/8QAFhAAAwAAAAAAAAAAAAAAAAAAAAIS/9oACAEBAAEFAoUhSFP/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAATKR/9oACAEBAAY/ApWErCVh/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABPyFUpX//2gAMAwEAAgADAAAAEIPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxAAAQUBAQAAAAAAAAAAAAAAAQARIUFR0TH/2gAIAQEAAT8QLzVYQhvGOKIN5Y4v/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Selecting EC2 services from AWS console" title="" src="/static/db3d399d267774478d124f4853a0fa21/47311/awsservices.jpg" srcset="/static/db3d399d267774478d124f4853a0fa21/6f81f/awsservices.jpg 270w, /static/db3d399d267774478d124f4853a0fa21/09d21/awsservices.jpg 540w, /static/db3d399d267774478d124f4853a0fa21/47311/awsservices.jpg 1080w, /static/db3d399d267774478d124f4853a0fa21/f43b1/awsservices.jpg 1426w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Click on EC2 and you will be redirected to its dashboard. Click launch instance button under create instance section.</p> <h2 id="select-the-openvpn" style="position:relative;"><a href="#select-the-openvpn" aria-label="select the openvpn permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Select the OpenVPN</h2> <p>Many articles will walk you through setting up an new Linux VM and installing the <strong>OpenVPN</strong> manually. However, things have changed and some lovely people have put a ready to use service in the AWS marketplace, so we will choose that.</p> <p>Once in the dashboard, click <code class="language-text">AWS Marketplace</code> menu from left and type OpenVPN, then press enter.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1013px; " > <a class="gatsby-resp-image-link" href="/static/dc6ac5c27b83c8abb490e0a59df408d9/326df/awsmarket.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 39.62962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB2KFB/8QAFxAAAwEAAAAAAAAAAAAAAAAAAAITEv/aAAgBAQABBQLCE0Jof//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAAMBAQAAAAAAAAAAAAAAAAAykQIB/9oACAEBAAY/Al5BcwXMP//EABcQAQEBAQAAAAAAAAAAAAAAAADxAeH/2gAIAQEAAT8hnmcYnH//2gAMAwEAAgADAAAAEAAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBAAAQMFAAAAAAAAAAAAAAAAAQAh0RFBscHw/9oACAEBAAE/EBcA9GiRYzRLjtL/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="OpenVPN in AWS Marketplace" title="" src="/static/dc6ac5c27b83c8abb490e0a59df408d9/326df/awsmarket.jpg" srcset="/static/dc6ac5c27b83c8abb490e0a59df408d9/6f81f/awsmarket.jpg 270w, /static/dc6ac5c27b83c8abb490e0a59df408d9/09d21/awsmarket.jpg 540w, /static/dc6ac5c27b83c8abb490e0a59df408d9/326df/awsmarket.jpg 1013w" sizes="(max-width: 1013px) 100vw, 1013px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Click on select button on the first one with the <code class="language-text">free tier eligible</code> badge.</p> <h2 id="selecting-instance-type" style="position:relative;"><a href="#selecting-instance-type" aria-label="selecting instance type permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Selecting instance type</h2> <p>On the next page click continue and select <code class="language-text">t2.micro</code> from instance type list.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 710px; " > <a class="gatsby-resp-image-link" href="/static/8a0dd77b5403a96490bb2f7336b5deab/67e9d/instancetype.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 61.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEDAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB6zplEUD/xAAaEAACAgMAAAAAAAAAAAAAAAAAEwIDEBEi/9oACAEBAAEFAlwFwFV430f/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAZEAACAwEAAAAAAAAAAAAAAAACMgAQkRH/2gAIAQEABj8CQciDkQcrlf/EABoQAAICAwAAAAAAAAAAAAAAAABRAREQgfH/2gAIAQEAAT8h5EbiCQlFUaP/2gAMAwEAAgADAAAAEJ8//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8Qp//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPxBlf//EAB0QAQABAwUAAAAAAAAAAAAAAAEAESExQVFhkcH/2gAIAQEAAT8QuwBi7eTBzyxc6EVTqDEts6n/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Choosing free tier instance type" title="" src="/static/8a0dd77b5403a96490bb2f7336b5deab/67e9d/instancetype.jpg" srcset="/static/8a0dd77b5403a96490bb2f7336b5deab/6f81f/instancetype.jpg 270w, /static/8a0dd77b5403a96490bb2f7336b5deab/09d21/instancetype.jpg 540w, /static/8a0dd77b5403a96490bb2f7336b5deab/67e9d/instancetype.jpg 710w" sizes="(max-width: 710px) 100vw, 710px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>At this stage click on <em><strong>Review and Launch</strong></em> button.</p> <h2 id="launch-the-instance" style="position:relative;"><a href="#launch-the-instance" aria-label="launch the instance permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Launch the instance</h2> <p>Select general purpose SSD from the pop up and click next. Now click <code class="language-text">Launch</code> and you’ll see a pop up asking you to select a key pair. This is to let you access the instance later on.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 717px; " > <a class="gatsby-resp-image-link" href="/static/25da34eb308784196ea93d15cb8f2413/b0abb/keypair.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 75.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQAF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAdpZCI//xAAXEAEBAQEAAAAAAAAAAAAAAAAAERAS/9oACAEBAAEFAo5Ta//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABYQAQEBAAAAAAAAAAAAAAAAABAxAP/aAAgBAQAGPwJup//EABkQAAMBAQEAAAAAAAAAAAAAAAABEfAhUf/aAAgBAQABPyFKRkNfC4hvgiH/2gAMAwEAAgADAAAAEEwf/8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/EIf/xAAcEAEBAQABBQAAAAAAAAAAAAABEQAxQVFhgZH/2gAIAQEAAT8QTAD5ilAy0os7YUEAJx0aLtHgw4i+9//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Select a key pair to access the instance" title="" src="/static/25da34eb308784196ea93d15cb8f2413/b0abb/keypair.jpg" srcset="/static/25da34eb308784196ea93d15cb8f2413/6f81f/keypair.jpg 270w, /static/25da34eb308784196ea93d15cb8f2413/09d21/keypair.jpg 540w, /static/25da34eb308784196ea93d15cb8f2413/b0abb/keypair.jpg 717w" sizes="(max-width: 717px) 100vw, 717px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Select create a new key pair (or an existing if you already have one), enter a name and click download key pair.</p> <p>Save the <code class="language-text">.pem</code> file somewhere safe as this is like a back door to your server 😁. Click Launch Instance and wait for the instance to go to running state.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 699px; " > <a class="gatsby-resp-image-link" href="/static/d8f84b50c53a61b35c8bc4e0f92ff116/9149e/status.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 24.814814814814817%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAdyklB//xAAWEAADAAAAAAAAAAAAAAAAAAAAEBH/2gAIAQEAAQUCKv/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABYQAQEBAAAAAAAAAAAAAAAAABEAEP/aAAgBAQABPyFMN//aAAwDAQACAAMAAAAQiC//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAYEAEBAQEBAAAAAAAAAAAAAAABABEhkf/aAAgBAQABPxDSQzyFyGl//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="status" title="" src="/static/d8f84b50c53a61b35c8bc4e0f92ff116/9149e/status.jpg" srcset="/static/d8f84b50c53a61b35c8bc4e0f92ff116/6f81f/status.jpg 270w, /static/d8f84b50c53a61b35c8bc4e0f92ff116/09d21/status.jpg 540w, /static/d8f84b50c53a61b35c8bc4e0f92ff116/9149e/status.jpg 699w" sizes="(max-width: 699px) 100vw, 699px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Click on view instance to see the instance list.</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/00cf58adcb2632bf93c3b3d3387c8dc4/f7fe6/instances.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 27.40740740740741%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3KAH/8QAFhABAQEAAAAAAAAAAAAAAAAAABEB/9oACAEBAAEFApiI/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAGRAAAgMBAAAAAAAAAAAAAAAAAAERITGB/9oACAEBAAE/IUrKOiJ//9oADAMBAAIAAwAAABDzz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABoQAAICAwAAAAAAAAAAAAAAAAABEWFRcZH/2gAIAQEAAT8QSwsKIZ6KW9n/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Instance list" title="" src="/static/00cf58adcb2632bf93c3b3d3387c8dc4/47311/instances.jpg" srcset="/static/00cf58adcb2632bf93c3b3d3387c8dc4/6f81f/instances.jpg 270w, /static/00cf58adcb2632bf93c3b3d3387c8dc4/09d21/instances.jpg 540w, /static/00cf58adcb2632bf93c3b3d3387c8dc4/47311/instances.jpg 1080w, /static/00cf58adcb2632bf93c3b3d3387c8dc4/f7fe6/instances.jpg 1258w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Select your instance and click connect.</p> <h2 id="preparation" style="position:relative;"><a href="#preparation" aria-label="preparation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Preparation</h2> <p>You’ll see a set of instructions on a popup on how to connect to your instance.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 714px; " > <a class="gatsby-resp-image-link" href="/static/e72f829022cf1e63b1bf9c8ecbcf827d/ab20e/connect.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 96.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAATABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAECAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB9u0YaFByCf/EABcQAQEBAQAAAAAAAAAAAAAAAAEQABH/2gAIAQEAAQUC4RK03//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABYRAAMAAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwGs/8QAFhAAAwAAAAAAAAAAAAAAAAAAAAEw/9oACAEBAAY/AoM//8QAHBAAAgICAwAAAAAAAAAAAAAAAAEQETFhIUGR/9oACAEBAAE/IQpa8EXiL0NzLN5ds//aAAwDAQACAAMAAAAQUw8D/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxCrD//EABYRAAMAAAAAAAAAAAAAAAAAAAAQMf/aAAgBAgEBPxB0f//EAB0QAAICAgMBAAAAAAAAAAAAAAERACExkUFRcYH/2gAIAQEAAT8QuSIO4JCqmIU7yuIOxH5HBRFQGhjUfmoUYihDxz//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Instructions on how to connect" title="" src="/static/e72f829022cf1e63b1bf9c8ecbcf827d/ab20e/connect.jpg" srcset="/static/e72f829022cf1e63b1bf9c8ecbcf827d/6f81f/connect.jpg 270w, /static/e72f829022cf1e63b1bf9c8ecbcf827d/09d21/connect.jpg 540w, /static/e72f829022cf1e63b1bf9c8ecbcf827d/ab20e/connect.jpg 714w" sizes="(max-width: 714px) 100vw, 714px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>In the instruction set they tell you to use <a href="https://docs.aws.amazon.com/console/ec2/instances/connect/putty" target="_blank" rel="nofollow noopener noreferrer">PuTTY</a> to connect to your instance using <code class="language-text">SSH</code>. However, I already have Ubuntu set up in <code class="language-text">WSL</code> (windows subsystem for Linux) and we can use that. Otherwise you can use PuTTY or even the web browser connection.</p> <p>Before we do anything we need to set the permissions for our private key 👉🏽 <code class="language-text">.pem</code> 👈🏽 file, otherwise it wouldn’t allow you to connect. If you’re using a Linux or Mac machine, simply run the following command:</p> <div class="gatsby-code-button-container" data-toaster-id="26769653365031720000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`chmod 400 {name-of-file}.pem`, `26769653365031720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">chmod</span> <span class="token number">400</span> <span class="token punctuation">{</span>name-of-file<span class="token punctuation">}</span>.pem</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>For the rest of you who are like me, right click on the <code class="language-text">.pem</code> file and click <em>Security > Advance</em>. Then change the owner to yourself, click disable inheritance and remove all permissions. Click add and add yourself and give full control.</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/8f1d702ac72e1f6753c378b3631c3d3e/35868/permissions.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 65.92592592592594%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAdq0xkB//8QAGBAAAgMAAAAAAAAAAAAAAAAAAAEQERL/2gAIAQEAAQUCYps0f//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABUQAQEAAAAAAAAAAAAAAAAAACBB/9oACAEBAAY/Aqv/xAAdEAABAwUBAAAAAAAAAAAAAAAAARFBEDFRcaHR/9oACAEBAAE/IUTwWe0dcitg0P/aAAwDAQACAAMAAAAQ4A//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAdEAEAAwABBQAAAAAAAAAAAAABABEhMVFhobHR/9oACAEBAAE/EGDiys34lq2L3wxx0IA6k6ShftGz9z//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Setting the right permissions for private key" title="" src="/static/8f1d702ac72e1f6753c378b3631c3d3e/47311/permissions.jpg" srcset="/static/8f1d702ac72e1f6753c378b3631c3d3e/6f81f/permissions.jpg 270w, /static/8f1d702ac72e1f6753c378b3631c3d3e/09d21/permissions.jpg 540w, /static/8f1d702ac72e1f6753c378b3631c3d3e/47311/permissions.jpg 1080w, /static/8f1d702ac72e1f6753c378b3631c3d3e/35868/permissions.jpg 1525w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="connecting" style="position:relative;"><a href="#connecting" aria-label="connecting permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Connecting</h2> <p>Once that’s done, open a command prompt, type bash and then enter the following command:</p> <div class="gatsby-code-button-container" data-toaster-id="31279616091040596000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo ssh -i &quot;{name-of-file}.pem&quot; openvpnas@{serveraddress}.compute.amazonaws.com`, `31279616091040596000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">ssh</span> <span class="token parameter variable">-i</span> <span class="token string">"{name-of-file}.pem"</span> openvpnas@<span class="token punctuation">{</span>serveraddress<span class="token punctuation">}</span>.compute.amazonaws.com</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Don’t forget to replace the file name with whatever you’ve chosen previously and replace the name of server with what you got from the instruction popup.</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/6973d7e09fca7af87b498dc8fe0153ee/8ab28/connectprompt.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 64.07407407407408%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHPVQgIP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEAAQUCX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABgQAAMBAQAAAAAAAAAAAAAAABAx8AAB/9oACAEBAAE/IZ6Z6x//2gAMAwEAAgADAAAAEFz/AP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQABBQEBAAAAAAAAAAAAAAEAESFBUZExcf/aAAgBAQABPxCzqFAxVhauvjMyz09lXb2f/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Connect prompts" title="" src="/static/6973d7e09fca7af87b498dc8fe0153ee/47311/connectprompt.jpg" srcset="/static/6973d7e09fca7af87b498dc8fe0153ee/6f81f/connectprompt.jpg 270w, /static/6973d7e09fca7af87b498dc8fe0153ee/09d21/connectprompt.jpg 540w, /static/6973d7e09fca7af87b498dc8fe0153ee/47311/connectprompt.jpg 1080w, /static/6973d7e09fca7af87b498dc8fe0153ee/0047d/connectprompt.jpg 1620w, /static/6973d7e09fca7af87b498dc8fe0153ee/8ab28/connectprompt.jpg 1863w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Type yes for the agreement, then just hit enter to have all the defaults confirmed. Once you reached to the end, change the password for the user which will be used to login:</p> <div class="gatsby-code-button-container" data-toaster-id="369192119492911550" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo passwd openvpn`, `369192119492911550`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">passwd</span> openvpn</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Enter a new password twice and you’re all set. Open a browser window and type <code class="language-text">https://{server address}:943/admin</code> and login with <code class="language-text">openvpn</code> and the password you just set.</p> <h2 id="tidy-up-a-few-settings" style="position:relative;"><a href="#tidy-up-a-few-settings" aria-label="tidy up a few settings permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Tidy up a few settings</h2> <p>Once in the admin dashboard of OpenVPN, click configuration and apply the following changes:</p> <ul> <li>Change the toggle for <em>Should client Internet traffic be routed through the VPN?</em> to <strong>Yes</strong></li> <li>Change the toggle for <em>Have clients use specific DNS servers</em> to <strong>Yes</strong></li> <li>Select custom DNS server and set the first box to <code class="language-text">1.1.1.1</code> (CloudFlare DNS 🦄) and the second to <code class="language-text">8.8.8.8</code></li> </ul> <p>Now save the settings, wait for the pop up on the top and click apply the changes to server.</p> <h2 id="youre-good-to-go" style="position:relative;"><a href="#youre-good-to-go" aria-label="youre good to go permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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’re good to go</h2> <p>You’re all set. You can now connect to your very own VPN server and enjoy a private surf of the net 😎. On the first page of the browser window you opened earlier, there are five options to download the OpenVPN client for different platform. If you click on windows, you will get an installer with your server address pre-configured. Just enter your user name and password and voila.</p> <p>Hope this will help you if you need a VPN server setup for free.</p><![CDATA[6 points you need to know about async & await in JavaScript]]>https://yashints.dev/blog/2019/08/17/js-async-awaithttps://yashints.dev/blog/2019/08/17/js-async-awaitSat, 17 Aug 2019 00:00:00 GMT<p>If you have faced a code like below, then this article will help you in multiple ways 😁.</p> <div class="gatsby-code-button-container" data-toaster-id="29414344663303725000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`fetchPizzas() .then((pizzas) => { return sortByToppings(pizzas) .then((pizzas) => { return checkDeliveryOptions(pizzas) .then((pizzasWithDelivery) => { return checkBirthdayGift(pizzasWithDelivery) .then((pizza) => { return sendToCustomer(pizza); }); }); }); });`, `29414344663303725000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token function">fetchPizzas</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 punctuation">(</span>pizzas<span class="token punctuation">)</span> <span class="token operator">=</span>> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">sortByToppings</span><span class="token punctuation">(</span>pizzas<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>pizzas<span class="token punctuation">)</span> <span class="token operator">=</span>> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">checkDeliveryOptions</span><span class="token punctuation">(</span>pizzas<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>pizzasWithDelivery<span class="token punctuation">)</span> <span class="token operator">=</span>> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">checkBirthdayGift</span><span class="token punctuation">(</span>pizzasWithDelivery<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>pizza<span class="token punctuation">)</span> <span class="token operator">=</span>> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">sendToCustomer</span><span class="token punctuation">(</span>pizza<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><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <!--more--> <h2 id="a-little-bit-of-background" style="position:relative;"><a href="#a-little-bit-of-background" aria-label="a little bit of 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>A little bit of background</h2> <p>There are many a times where we have a bunch of tasks to be executed sequentially. The examples are from File handling to calling databases multiple times based on the result of the previous call. Or calling multiple APIs in a sequence where one call is dependenat on another.</p> <p>Prior to introduction of <code class="language-text">async/await</code>, many used callbacks alongside <code class="language-text">setTimeOut</code> to simulated the behaviour they wanted (aka callback hell). Later on people started to use promises which made the code much more readable but they would end up in the same place when the number of calls where high (aka promise hell).</p> <h2 id="async-functions" style="position:relative;"><a href="#async-functions" aria-label="async 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>Async functions</h2> <p>A function in JavaScript is <code class="language-text">async</code> when it operates asynchronously via the event loop, using an implicit promise to return its result. Furthermore, the type of its result should be an <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction" target="_blank" rel="nofollow noopener noreferrer"><code class="language-text">AsyncFuncton</code></a> object.</p> <p>This function is nothing but a combination of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank" rel="nofollow noopener noreferrer">promises</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Generator_functions" target="_blank" rel="nofollow noopener noreferrer">generators</a>. I will not going into details of generators, but they usually contains one or many <code class="language-text">yield</code> keywords.</p> <p>Now lets see the <code class="language-text">async</code> function in action. Assume we have a function which returns a string:</p> <div class="gatsby-code-button-container" data-toaster-id="80794604760554780000" data-toaster-class="gatsby-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 hi() { return 'Hi from JavaScript'; } hi(); // 'Hi from JavaScript'`, `80794604760554780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'Hi from JavaScript'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'Hi from JavaScript'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If we put <code class="language-text">async</code> in front of the function, then it no longer returns string, it will be a promise which is wrapped around the string value automatically.</p> <div class="gatsby-code-button-container" data-toaster-id="43854963307599634000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async function hi() { return 'Hi from JavaScript'; } hi(); // Promise {<resolved>: &quot;Hi from JavaScript&quot;}`, `43854963307599634000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'Hi from JavaScript'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Promise {&lt;resolved>: "Hi from JavaScript"}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now in order to get the value from the promise we act like before:</p> <div class="gatsby-code-button-container" data-toaster-id="38427837694441690000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`hi().then(console.log); // 'Hi from JavaScript'`, `38427837694441690000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token function">hi</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>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'Hi from JavaScript'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You might be wondering how this can help to solve the promise hell. Just bare with me and we’ll get there step by step with examples so it’d be clear when we’re finished.</p> <h2 id="await" style="position:relative;"><a href="#await" aria-label="await permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Await</h2> <p>The <code class="language-text">await</code> makes JavaScript engine to wait until a promise is resolved/rejected and returns it’s result. This keyword can only be used inside an <code class="language-text">async</code> function.</p> <div class="gatsby-code-button-container" data-toaster-id="68534450736794760000" data-toaster-class="gatsby-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 doSomething = async () => { console.log(await hi()) }; // 'Hi from JavaScript'`, `68534450736794760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">doSomething</span> <span class="token operator">=</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> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">await</span> <span class="token function">hi</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 comment">// 'Hi from JavaScript'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You might think since <code class="language-text">await</code> forces the JavaScript engine to wait, it will have some cost on CPU. But that’s not the case because the engine can perform other scripts while waiting for the promise to get resolves/rejected. Plus this is way more elegant that using <code class="language-text">promises</code> and <code class="language-text">.then</code>.</p> <div class="custom-block warning"><div class="custom-block-body"><strong>Warning:</strong> If you try to invoke an <code class="language-text">async</code> function using <code class="language-text">await</code> inside a normal function, you will get a syntax error.</div></div> <div class="gatsby-code-button-container" data-toaster-id="9817574368344517000" data-toaster-class="gatsby-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 doSomething() { await hi(); // Uncaught SyntaxError: await is only valid in async function }`, `9817574368344517000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Uncaught SyntaxError: await is only valid in async function</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="a-small-catch" style="position:relative;"><a href="#a-small-catch" aria-label="a small catch permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>A small catch</h2> <p>Most people who start working with <code class="language-text">async/await</code> forget that they can’t invoke an <code class="language-text">async</code> function on top level code. This is due to the fact that we can’t have <code class="language-text">await</code> inside a normal function and the top level functions are normal by default.</p> <div class="gatsby-code-button-container" data-toaster-id="35520206985240700000" data-toaster-class="gatsby-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 response = await hi(); // syntax error in top-level code console.log(response);`, `35520206985240700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// syntax error in top-level code</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>What you can do however, is to wrap your code in an <code class="language-text">async</code> <code class="language-text">IIFE</code> (immediately invoked function execution) and call it right there:</p> <div class="gatsby-code-button-container" data-toaster-id="37787951689115390000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`(async () => { let response = await hi(); console.log(response); // 'Hi from JavaScript' ... })();`, `37787951689115390000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><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">let</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">hi</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>response<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'Hi from JavaScript'</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="error-handling" style="position:relative;"><a href="#error-handling" aria-label="error handling permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Error handling</h2> <p>As I said before, most <code class="language-text">async</code> functions can be written as a normal function with promises. However, <code class="language-text">async</code> functions are less <code class="language-text">error-prone</code> when it comes to error handling. If an awaited call fails, the exception is automatically caught and the <code class="language-text">Error</code> object will be propagated to the caller using the implicit return promise.</p> <p>Prior to this, we had to reject the promise which was returned from the normal function and use a <code class="language-text">.catch</code> in the caller. I’ve seen many places where the developers used a try/catch and throw a new exception which meant the stack trace would be reset.</p> <div class="gatsby-code-button-container" data-toaster-id="98129102653147380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async function hi() { throw new Error(&quot;Whoops!&quot;); }; async function doSomething() { try { let response = await hi(); return response; } catch(err) { console.log(err); } } doSomething();`, `98129102653147380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Whoops!"</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">async</span> <span class="token keyword">function</span> <span class="token function">doSomething</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">let</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">hi</span><span class="token punctuation">(</span><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 punctuation">}</span> <span class="token keyword">catch</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>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Or you can avoid the <code class="language-text">try/catch</code> because the promise generated by the call to <code class="language-text">hi</code> becomes rejected. Then simply use <code class="language-text">.catch</code> to handle the error.</p> <div class="gatsby-code-button-container" data-toaster-id="1938624656650489300" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async function hi() { throw new Error(&quot;Whoops!&quot;); }; async function doSomething() { let response = await hi(); return response; } doSomething().catch(err => { console.log(err); });`, `1938624656650489300`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Whoops!"</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">async</span> <span class="token keyword">function</span> <span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">hi</span><span class="token punctuation">(</span><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 punctuation">}</span> <span class="token function">doSomething</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">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can ignore the catch all together and handle all the exceptions using a <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onrejectionhandled" target="_blank" rel="nofollow noopener noreferrer">global exception handler</a> if you think that’s more suitable to your situation. Something like this which uses the <code class="language-text">onrejectionhandled</code> property of <code class="language-text">WindowsEventHandlers</code> mixin.</p> <div class="gatsby-code-button-container" data-toaster-id="16997633327346006000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`window.onrejectionhandled = function(e) { console.log(e.reason); }`, `16997633327346006000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">window<span class="token punctuation">.</span><span class="token function-variable function">onrejectionhandled</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h2 id="promiseall-compatibility" style="position:relative;"><a href="#promiseall-compatibility" aria-label="promiseall compatibility permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Promise.all compatibility</h2> <p>You can use <code class="language-text">async/await</code> alongside <code class="language-text">Promise.all</code> to wait for multiple promises:</p> <div class="gatsby-code-button-container" data-toaster-id="56618639804297535000" data-toaster-class="gatsby-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 responses = await Promise.all([ fetch('yashints.dev/rss'), hi(), ... ])`, `56618639804297535000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> responses <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> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'yashints.dev/rss'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">hi</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If an error occurs, it propagates as usual, from the failed promise to <code class="language-text">Promise.all</code> and then turns to an exception that you can catch using any of the above methods.</p> <h2 id="code-classlanguage-textawaitcode-can-take-in-a-thenable" style="position:relative;"><a href="#code-classlanguage-textawaitcode-can-take-in-a-thenable" aria-label="code classlanguage textawaitcode can take in a thenable permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">await</code> can take in a “thenable”</h2> <p>Similar to <code class="language-text">promise.then</code>, if you have any object which has a <code class="language-text">.then</code> method, <code class="language-text">await</code> will accepts it. This is to support scenarios where a 3rd-party object which is not a promise, but promise-compatible (it supports <code class="language-text">.then</code>), it would be enough to use it with <code class="language-text">await</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="42374656677018320000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class Greeting { constructor(name) { this.name = name; } then(resolve, reject) { console.log(resolve); setTimeout(() => resolve(\`Hi \${this.name}\`)); } }; async function greet() { const greeting = await Greeting('Yaser'); console.log(greeting); // Hi Yaser }; greet();`, `42374656677018320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Greeting</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<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">resolve<span class="token punctuation">,</span> reject</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>resolve<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hi </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">greet</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> greeting <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">Greeting</span><span class="token punctuation">(</span><span class="token string">'Yaser'</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>greeting<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Hi Yaser</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token function">greet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="code-classlanguage-textasynccode-class-methods" style="position:relative;"><a href="#code-classlanguage-textasynccode-class-methods" aria-label="code classlanguage textasynccode class 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><code class="language-text">async</code> class methods</h2> <p>You can have an <code class="language-text">async</code> class method. Just prepend it with <code class="language-text">async</code> and you’re good to go.</p> <div class="gatsby-code-button-container" data-toaster-id="41922254480850270000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class Order { async deliver() { return await Promise.resolve('Pizza'); } } new Order() .delivery() .then(console.log); // Pizza`, `41922254480850270000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Order</span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token function">deliver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'Pizza'</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">new</span> <span class="token class-name">Order</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">delivery</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>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Pizza</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></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>Just to quickly go through what we discussed so far:</p> <ol> <li><code class="language-text">async</code> keyword makes a method asynchronous, which in turn always returns a promise and allows <code class="language-text">await</code> to be used.</li> <li><code class="language-text">await</code> keyword before a promise makes JavaScript wait until that is resolved/rejected. If the promise is rejected, an exception is generated, otherwise the result is returned.</li> <li>Together, they provide a great opportunity for us to write clean, more testable, asynchronous code.</li> <li>With <code class="language-text">async/await</code> you wouldn’t need <code class="language-text">.then/.catch</code>, but just note that they are still based on promises.</li> <li>You can use <code class="language-text">Promise.all</code> to wait for multiple <code class="language-text">async</code> functions calls.</li> <li>You can have an <code class="language-text">async</code> method in a class.</li> </ol> <p>I know there are many great articles around <code class="language-text">async/await</code>, but I tried to cover some items where I had to constantly remind myself of. Hope it will help you to have a centralised place for most of what you need to write clean asynchronous JavaScript.</p> <p>Have fun exploring these points.</p><![CDATA[Firefox Developer Tools can do that?]]>https://yashints.dev/blog/2019/08/08/firefox-dev-toolshttps://yashints.dev/blog/2019/08/08/firefox-dev-toolsThu, 08 Aug 2019 00:00:00 GMT<p>It’s been a while since one of the X can do that posts I’ve been publishing. Furthermore, <a href="https://developer.mozilla.org/en-US/docs/Tools" target="_blank" rel="nofollow noopener noreferrer">Firefox Developer tools</a> is just getting better and better everyday, so I thought it’s about time I write one for it.</p> <p>So, are you ready? 😎</p> <!--more--> <h2 id="how-to-open-it" style="position:relative;"><a href="#how-to-open-it" aria-label="how to open 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 to open it</h2> <p>You can open the <em>Firefox Developer Tools</em> from the menu by selecting <em>Tools</em> > <em>Web Developer</em> > <em>Toggle Tools</em> or use the keyboard shortcut <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> or <kbd>F12</kbd> on Windows and Linux, or <kbd>Cmd</kbd> + <kbd>Opt</kbd> + <kbd>I</kbd> on macOS.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 225px; " > <a class="gatsby-resp-image-link" href="/static/7e201c1dea64888838c1bfc2a1f0fa5b/3684f/menu.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 128.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAaCAIAAAA44esqAAAACXBIWXMAAAsTAAALEwEAmpwYAAADSUlEQVR42n1UaVPjOBDN//8ZMF+omk+7FLCzGagaSG0xkMM5vImP+Iwdx/GpOLbla57tJARmly7RtBw99dPrljqE7MLws7HdOkEQBgFxHNe2HUnRNd0EareLOpRmWZa340NcFKXvB93ud8Mwq6q6ubldSvLzS3++ECRJFsVlJ44TQqJmpz1ieMQkrMeORJ7nr1aG4zjIo2n62rJlRVO1VRiSOjP+sIpSCrRhGPBpmoJARmvD/6Io8rxIkxTTOI4xxQKA05R2mjOH2FtV1YuLC3Y24xaLOTubc7wkLtnZdDAYTCdTx/HAvCxLeOABBs1OFO1h2Aw5X19focyOELDFjiQMfd93HddaW/t9fA5Gyjoz9AQZfFIUpdvt8hyHMxk6JDVc19U1lVtw0K86s2PmtJM0hk9gfn9/b9sbZ7td6dDGQm2WgsAt+JR+BIMsPEpFW7Asy4+Pj7qmmaZpWxtzbXm+L8vS+WlP4BbyBtY0rdfrmYahqYrI8yp4G6vZbOZ+Akap2giCPTw8rNcmyh2hftArIKgPNLM3GxJFJzzATUVpDW4F4zju6upqu9mMx8Pe0z+D/oBhJqIkjoejYb/P8QLNixP4oDbAsDxHP1IUDAF+K0uMgzv4ssyOhmWENE2C6EQbyfG1LUzZZMBep2ztFLvAgyyCN8Gm0+nF5SWaixmNBsOhokhPT0/MaCLw/GTMvPz8ifsQhgEakWb5QbA4XSQpQYQ5z/PwWZ4nMXzWcEvRgsjT6to2NjIfwZRNkgCRaRqXX74gITPq//jRYxhGWEq/FSk3Vjo9gf+6vbVtGxG2lyQJ3ve9IAgstIpt1yfM8vZiNUfO26vWFqjDT2PfQ6/lB52Qp2zkquOqlSc7M0zB/AAW/qUkTBGFrgOejrM1jRXuhqJq0lLUdT1JaPXe3jrsxYz9qI72O6KoilybJKAnltJ8zqJPN7Zzdur34OdV7DVglDskZI+OITtcGs9xQbL6L3sDi+yBdryPBH7B4u0YT1mWfXl+FkUJ6z4D85PUMvESJWGQei4Ki9bJ2iY9PmQfDUi8QTX472+3d3d/3t39gXF9/dXajNKM38c2Wheq0v+xllEH709VqcehlZVaVMuiDBqCZfWp/QIYWbwnut/aIwAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox Developer Tools menu" title="" src="/static/7e201c1dea64888838c1bfc2a1f0fa5b/3684f/menu.png" srcset="/static/7e201c1dea64888838c1bfc2a1f0fa5b/3684f/menu.png 225w" sizes="(max-width: 225px) 100vw, 225px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="page-inspector" style="position:relative;"><a href="#page-inspector" aria-label="page inspector permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Page Inspector</h2> <p>There are many useful features in the page inspector (equivalent to Chrome DevTools inspect element), but there are a few which I use the most:</p> <h3 id="search-for-css-classes" style="position:relative;"><a href="#search-for-css-classes" aria-label="search for css classes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 for CSS classes</h3> <p>You can use the search box right below the inspector tab to search for elements, classes and other selectors. But I mostly use it to search for elements with a specific class. This is very useful if you have multiple elements which visually look similar but have specific class, or if you can’t see it because it is hidden.</p> <p><img src="/b874d25602de8b85fb5d72d8944e9c9c/css-class-search.gif" alt="CSS class search box"></p> <h3 id="filter-styles" style="position:relative;"><a href="#filter-styles" aria-label="filter styles permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Filter styles</h3> <p>In the section below, there is box for filtering styles which can be used to easily spot a particular style you might be looking for. The good thing is, it highlights the selectors and expands properties which lets you easily spot what you’re looking for.</p> <p><img src="/f5a3d6740361ac6d084301c7db987782/style-filter.gif" alt="Search for styles in filter box"></p> <h3 id="see-colour-codes-in-different-formats" style="position:relative;"><a href="#see-colour-codes-in-different-formats" aria-label="see colour codes in different formats permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>See colour codes in different formats</h3> <p>One of my favourites is this little nugget of gold. With this you can easily <kbd>Shift</kbd> + <kbd>click</kbd> and see all different types of colour representation including <code class="language-text">name</code>, <code class="language-text">hex</code>, <code class="language-text">rgb</code>, and <code class="language-text">hsl</code>. Of course not all colours have names, you in some cases you only see the other ones.</p> <p><img src="/519a544dca2564e2c5891ef89f254bbd/colourrep.gif" alt="Colour representation"></p> <p>Cool hah?</p> <h2 id="web-console" style="position:relative;"><a href="#web-console" aria-label="web console permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Web Console</h2> <p>Who doesn’t love the console in the browsers’s developer tools. It’s used for logging, calculation, evaluation and much more.</p> <h3 id="styling-console-messages" style="position:relative;"><a href="#styling-console-messages" aria-label="styling console messages permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Styling console messages</h3> <p>You can get fancy with the messages in the console by applying CSS styles to them. This becomes important when you have heaps of logs and want to highlight a specific part by a different style for example.</p> <p><img src="/c98852ac8be49189f2a44d6f1ac3bb27/console-style.gif" alt="Adding styles to console messages"></p> <p>Note that you already have <code class="language-text">console.info</code>, <code class="language-text">console.warn</code> and <code class="language-text">console.error</code> at your disposal. So this will be a level above what you can get with those.</p> <p><img src="/96fb71566bd9667b5a1ae0a9705c97da/console-msg.jpg" alt="console info, warning and error messages"></p> <h3 id="search-in-history-of-commands" style="position:relative;"><a href="#search-in-history-of-commands" aria-label="search in history of commands permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 in history of commands</h3> <p>This one is helpful if you have typed many commands and want to search between those commands. Simply type all or part of the command you’re looking for and it shows you all that matches that phrase.</p> <p>Press <kbd>F9</kbd> on windows or <kbd>CTRL</kbd> + <kbd>R</kbd> to open the search box. Then type your term and if the count on the right hand side shows you have results, you can move between those by pressing the <kbd>F9</kbd> and <kbd>SHIFT</kbd> + <kbd>F9</kbd> on windows. For Mac users, navigate between those using <kbd>CTRL</kbd> + <kbd>R</kbd> and <kbd>CTRL</kbd> + <kbd>S</kbd>.</p> <p><img src="/8efaad5bf616d8af11a6d08a4756be07/console-search.gif" alt="search in console history"></p> <p>PS: I am just using arrow keys because <kbd>F9</kbd> is mapped to pause and play on my recording software and I am just too lazy to change that 😁.</p> <h3 id="screenshot-of-the-whole-page" style="position:relative;"><a href="#screenshot-of-the-whole-page" aria-label="screenshot of the whole page permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Screenshot of the whole page</h3> <p>To get a screen shot of the whole page, view port, or just an element, all you need to do is type <code class="language-text">:screenshot</code> and pass the parameter you like. Combinations are:</p> <div class="gatsby-code-button-container" data-toaster-id="65072928512691175000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`:screenshot //the visible part of the page :screenshot --fullpage // whole page even invisible parts :screenshot --selector .css-selector // only one element (including its children)`, `65072928512691175000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">:screenshot //the visible part of the page :screenshot <span class="token parameter variable">--fullpage</span> // whole page even invisible parts :screenshot <span class="token parameter variable">--selector</span> .css-selector // only one element <span class="token punctuation">(</span>including its children<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p><img src="/98703d3a1343cc27253858545f50356e/screenshot.gif" alt="taking a screenshot"></p> <p>Find out more about other parameters you can pass to it <a href="https://developer.mozilla.org/en-US/docs/Tools/Taking_screenshots#Taking_screenshots_with_the_web_console" target="_blank" rel="nofollow noopener noreferrer">in the documentation</a>.</p> <p>And of course you can take the screenshots using photo icon on the left side of the console in the above picture too.</p> <h2 id="javascript-debugger" style="position:relative;"><a href="#javascript-debugger" aria-label="javascript debugger permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>JavaScript debugger</h2> <p>Apart from the above two sections, like any other developer tools, is the debugger section where you could look into source code to see why something is happening the way it shouldn’t or just simply test out something.</p> <h3 id="pretty-print-minified-code" style="position:relative;"><a href="#pretty-print-minified-code" aria-label="pretty print minified 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>Pretty print minified code</h3> <p>To prettify a minified file, click this icon: <code class="language-text">{}</code> in the source pane. The debugger will format the source and display it as a new file with a name like: ”{ } [original-name]“.</p> <p><img src="/612c8fa42b081fefac862d958bae7769/pretty-print.gif" alt="Pretty print minified code"></p> <h3 id="search-for-filesfunctions" style="position:relative;"><a href="#search-for-filesfunctions" aria-label="search for filesfunctions permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 for files/functions</h3> <p>To search for a specific file, simply press <kbd>CTRL</kbd> + <kbd>P</kbd> (or <kbd>CMD</kbd> + <kbd>P</kbd> on a Mac). The display panel shows a list of files matching the search term as you type which you can choose. Just press <kbd>Enter</kbd> to open the file.</p> <p><img src="/d896579b21ae48757fc069fe487aadcf/search-file.gif" alt="Searching for a file"></p> <h3 id="xhr-xmlhttprequest-breakpoint" style="position:relative;"><a href="#xhr-xmlhttprequest-breakpoint" aria-label="xhr xmlhttprequest breakpoint permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>XHR (XMLHttpRequest) breakpoint</h3> <p>Sometimes you need to figure out what happens when you visit/send a request to a particular URL. Once set and the URL is hit, the execution will stop so you can see the state of the application at that point.</p> <p>Just click on the <kbd>+</kbd> in the XHR breakpoint section or if you want to enable it for all URLs, just tick the ‘Pause on any URL’ checkbox.</p> <p><img src="/4bfcdd2487eb43d6146affb30b178147/urlbreakpoint.gif" alt="URL breakpoint"></p> <h2 id="performance-tool" style="position:relative;"><a href="#performance-tool" aria-label="performance tool permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Performance tool</h2> <p>The performance tool is where I usually spending most of my time in. As you might know, I’ve been actively working on web performance and also have a <a href="https://dev.to/yashints/improve-html-and-css-performance-4o08" target="_blank" rel="nofollow noopener noreferrer">series of posts</a> on some important aspects of it.</p> <p>However for the purpose of keeping this post short (pardon the pun 😁), I will only point to two of the ones I regularly use. You can find out more about the rest in <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance" target="_blank" rel="nofollow noopener noreferrer">the official docs</a>.</p> <h3 id="waterfall-tab" style="position:relative;"><a href="#waterfall-tab" aria-label="waterfall tab permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Waterfall tab</h3> <p>Before you get to see these tabs, you should record a page’s load by pressing the ⏱ icon. Once it’s done, you will see the waterfall tab by default. Along the <code class="language-text">X</code> axis is time.</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/3b8a6a63aa08aadf6d97da5d75f3261e/d2757/waterfall.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.074074074074076%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUBAv/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHibUlmiz//xAAYEAADAQEAAAAAAAAAAAAAAAABBBAAAv/aAAgBAQABBQJwHmvYT//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABkQAAIDAQAAAAAAAAAAAAAAAAEQAgMicf/aAAgBAQAGPwKGieut/wD/xAAbEAACAgMBAAAAAAAAAAAAAAABEQAQITFxwf/aAAgBAQABPyFbLr4gyK95oK//2gAMAwEAAgADAAAAEEgf/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8QJ//EAB8QAQACAQMFAAAAAAAAAAAAAAEAEVEQITFhcZGhwf/aAAgBAQABPxBzoGcNiiKlQusQDB4nPs+Z6Wn/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="waterfall tab in performance view of Firefox developer tools" title="" src="/static/3b8a6a63aa08aadf6d97da5d75f3261e/47311/waterfall.jpg" srcset="/static/3b8a6a63aa08aadf6d97da5d75f3261e/6f81f/waterfall.jpg 270w, /static/3b8a6a63aa08aadf6d97da5d75f3261e/09d21/waterfall.jpg 540w, /static/3b8a6a63aa08aadf6d97da5d75f3261e/47311/waterfall.jpg 1080w, /static/3b8a6a63aa08aadf6d97da5d75f3261e/0047d/waterfall.jpg 1620w, /static/3b8a6a63aa08aadf6d97da5d75f3261e/274e1/waterfall.jpg 2160w, /static/3b8a6a63aa08aadf6d97da5d75f3261e/d2757/waterfall.jpg 2701w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>As you can see, all sorts of the stuff which browser has done such as running JavaScript, updating layout, garbage collection, and so on is shown in the view. You can find out how your application is performing on load and what type of things take the most time to finish easily in this view.</p> <p>The good thing is that each category is coloured differently so you can spot them easily in each category.</p> <p>For a full reference of what each colour represents, refer to the <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Waterfall#Markers" target="_blank" rel="nofollow noopener noreferrer">markers table on the docs</a>.</p> <h3 id="call-tree" style="position:relative;"><a href="#call-tree" aria-label="call tree permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Call tree</h3> <p>You can see a call tree of all the functions which has been called from top to bottom in this view. The main purpose of this view is to show you which function has taken the most time executing. By analysing these calls, you can find bottlenecks in your code.</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/020af17329c63d208ed09d98ddd7bea8/b4088/calltree.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 54.074074074074076%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABynSyyAD/xAAZEAACAwEAAAAAAAAAAAAAAAAAAQIQETH/2gAIAQEAAQUCRhiI8r//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAaEAACAgMAAAAAAAAAAAAAAAAAARARITFR/9oACAEBAAE/Ic02U5BuKRR//9oADAMBAAIAAwAAABDsH//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/EGf/xAAWEQEBAQAAAAAAAAAAAAAAAAAAIQH/2gAIAQIBAT8Qyo//xAAdEAEAAgEFAQAAAAAAAAAAAAABABGhITFBUWGR/9oACAEBAAE/EGsAt8BBi3CeR8mZNLbMp1P/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="call tree" title="" src="/static/020af17329c63d208ed09d98ddd7bea8/47311/calltree.jpg" srcset="/static/020af17329c63d208ed09d98ddd7bea8/6f81f/calltree.jpg 270w, /static/020af17329c63d208ed09d98ddd7bea8/09d21/calltree.jpg 540w, /static/020af17329c63d208ed09d98ddd7bea8/47311/calltree.jpg 1080w, /static/020af17329c63d208ed09d98ddd7bea8/0047d/calltree.jpg 1620w, /static/020af17329c63d208ed09d98ddd7bea8/b4088/calltree.jpg 2143w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>You can see in the result table that each row represents one function and the order is highest to lowest by the number of samples which has been taken while the function was executing. From docos:</p> <blockquote> <p><em>Total Time</em> is that number translated into milliseconds, based on the total amount of time covered by the selected portion of the recording. These numbers should roughly be the same as the number of samples.<br> <em>Total Cost</em> is that number as a percentage of the total number of samples in the selected portion of the recording.<br> <em>Self Time</em> is calculated as the time spent in that particular function, excluding its children. This comes from the captured stacks where this function is the leafmost function.<br> <em>Self Cost</em> is calculated from Self Time as a percentage of the total number of samples in the selected portion of the recording.</p> </blockquote> <h2 id="miscellaneous" style="position:relative;"><a href="#miscellaneous" aria-label="miscellaneous permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Miscellaneous</h2> <p>There are heaps of other stuff which is outside of scope of a single post. But I want to point out a few of the other useful things you can do with Firefox Developer Tools.</p> <h3 id="accessibility-inspector" style="position:relative;"><a href="#accessibility-inspector" aria-label="accessibility inspector permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Accessibility Inspector</h3> <p>The <strong>Accessibility Inspector</strong> allows you to access important information exposed to assistive technologies on the current page via the accessibility tree, which lets you to check what’s missing or needs improvements.</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/853d434b15fecc13a6b2bbb64bfee1b4/06565/accessibility.jpg" 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/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIGBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHVwKObFGD/xAAZEAACAwEAAAAAAAAAAAAAAAAEEAIDETT/2gAIAQEAAQUCKjlCM5l//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFhABAQEAAAAAAAAAAAAAAAAAARBx/9oACAEBAAY/Amu3/8QAHRAAAQIHAAAAAAAAAAAAAAAAAAFBEBEhYYGhsf/aAAgBAQABPyFp1VGJWMGo7H//2gAMAwEAAgADAAAAELjv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8Qp//EABwQAQABBAMAAAAAAAAAAAAAAAEAESExURBh8P/aAAgBAQABPxAltWGApfqbosRGuU83SGeP/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Accessibility panel in Firefox Developer tools" title="" src="/static/853d434b15fecc13a6b2bbb64bfee1b4/47311/accessibility.jpg" srcset="/static/853d434b15fecc13a6b2bbb64bfee1b4/6f81f/accessibility.jpg 270w, /static/853d434b15fecc13a6b2bbb64bfee1b4/09d21/accessibility.jpg 540w, /static/853d434b15fecc13a6b2bbb64bfee1b4/47311/accessibility.jpg 1080w, /static/853d434b15fecc13a6b2bbb64bfee1b4/0047d/accessibility.jpg 1620w, /static/853d434b15fecc13a6b2bbb64bfee1b4/274e1/accessibility.jpg 2160w, /static/853d434b15fecc13a6b2bbb64bfee1b4/06565/accessibility.jpg 2694w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>On the left-hand side, there is a node tree representing all the items in the accessibility tree for the current page. Each item has two properties listed:</p> <ul> <li><em>Role</em> — the role this item has on the page (e.g., pushbutton, or footer, text leaf). This can be either a default role provided by the browser, or a role given to it via a <code class="language-text">WAI-ARIA</code> role attribute.</li> <li><em>Name</em> — the name this item has on the page. The name depends on the element; for example, the name of most text elements is simply their textContent, whereas form elements’ names are the contents of their associated <code class="language-text">&lt;label></code>.</li> </ul> <p>The cool thing here is that you can print the whole tree to <code class="language-text">JSON</code>. This will help you to parse this structure looking for any specific non compliant item. As an example, <a href="https://medium.com/myplanet-musings/making-the-web-more-accessible-using-machine-learning-8a32eaafdb3a" target="_blank" rel="nofollow noopener noreferrer">someone made an ML model</a> to validate accessibility and this JSON is ideal for data prep for those models.</p> <h3 id="eyedropper" style="position:relative;"><a href="#eyedropper" aria-label="eyedropper permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Eyedropper</h3> <p>If you want to select any particular colour in the current page, this tool is your friend. The fact that it works like a magnifying glass is really helpful to choose a colour in small areas of the page.</p> <p><img src="/c0943020253fa0f6845550187b7c8eaf/eyedropper.gif" alt="Eyedropper in Firefox developer tools"></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>Firefox has come a long way and the team are working furiously adding new features and improvements with every minor and major release. Plus, we should always test our applications with multiple browsers and make sure users will have the same experience in every major browser.</p> <p>Have fun exploring these tricks and happy debugging.</p> <h2 id="update" style="position:relative;"><a href="#update" aria-label="update permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Update</h2> <p><a href="https://dev.to/cecilelebleu" target="_blank" rel="nofollow noopener noreferrer">Cécile Lebleu</a> mentioned in comments that I’ve forgot about CSS Grid inspector and it’s true. So let me tell you about it.</p> <h3 id="grid-inspector" style="position:relative;"><a href="#grid-inspector" aria-label="grid inspector permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Grid inspector</h3> <p><a href="https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts" target="_blank" rel="nofollow noopener noreferrer">Grid inspector</a> is one of the unique tools in Firefox developer tools which allows you to examine <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout" target="_blank" rel="nofollow noopener noreferrer">CSS Grid Layouts</a>, discovering grids present on a page, examining and modifying them inline, debugging layout issues, and more.</p> <p>In the HTML Pane, elements laid out using a grid have a “grid” marker beside them:</p> <p><img src="/6bb4d1cccde2b27fe797566c55f88348/girdmarker.jpg" alt="Grid marker beside CSS grid element in Firefox developer tools"></p> <p>In addition to that, in the CSS pane’s Rules view, any instance of a <code class="language-text">display: grid</code> declaration gets a grid icon included within it: <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 24px; "> <a class="gatsby-resp-image-link" href="/static/c248ab782f6d8404d4d776ba9118c074/8f029/gridicon.png" 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/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAACZklEQVR42q2UTWtTURCG838EEURBxVoRwUW7Ehd+LPwF0or+AVfuXLgSxfpRxdpKoyC2tQtBrJaCttc2SW8aSUiM9iNtEtvU3OSe1/POvSc9+QIXPTAw951nJvfOTE4E+3wirYLS5tVVk1bzlZh9yKj/Kbhvb2h+bW3Hw925X/oNfKhQnEwVxYRTkBgZsnZuc8FQ/fZ7GyefLGI9hHmuv0+LmcMYGbJ2rhQ0rcmW/iK6vInbM3kce7yIe19XMRovYNzdxIVXrhh9aoyRIcsc5vKwVsQ0+11qC+dexHH2eQwHHzji971MoH80gaND38XoU2OMDFn6zDXDaxoKX/1DpoRTw0tIFirY9Xxp0LXJH2L0qTFGhqxSXYZiPn325x/0ajhXru71cCotZg5jZMjauR2HMpMNCmaK1YY2oIsNhAWpMUaGbNtQ6mH5T9kyLkeT6B9ZxiHdn/NjLi6OJ0U7rgdAo0+NMTJkr0RXdG5QmLX0lIOCiY2K7NbN6QyO6AHc+pjFndm8aH0jCTH61BgjQ5Yac4NPV+2fPK9368yzWNMe3phOi9l7SGa+0x62FvySC4dS2hvKoO7foD2UUtBDsm0FzUNxtwZndQdDzjpO6H/B25UtzOW3saC1q29SYvSpMUaGLHOYawo3Fvu1W5DG9zxdwuGHDnr0G/QOx3Bam1ls+tQYE0azzGFu22LXfB+Fioex+AYO3F/A51xZ/lLs16WoK0afGmNkyDKHuV1vGy7tI2cN5Wq9AU3om2YivG14GCNjll91u77sjTfPtmae7QKtz20XLIEqb2OL8rToWZVVyPgdrux/BFGyG+WTrA4AAAAASUVORK5CYII='); background-size: cover; display: block;"></span> <img class="gatsby-resp-image-image" alt="Grid icon" title="" src="/static/c248ab782f6d8404d4d776ba9118c074/8f029/gridicon.png" srcset="/static/c248ab782f6d8404d4d776ba9118c074/8f029/gridicon.png 24w" sizes="(max-width: 24px) 100vw, 24px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async"> </a> </span>:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; " > <a class="gatsby-resp-image-link" href="/static/450cd02e3f2705bbd5651062f8c974ee/65f94/gridicon.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 105.18518518518518%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAVABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAIBAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB8qOmEMFioEf/xAAYEAACAwAAAAAAAAAAAAAAAAAQEQABIP/aAAgBAQABBQLFhOIf/8QAFREBAQAAAAAAAAAAAAAAAAAAEAH/2gAIAQMBAT8BIf/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABQQAQAAAAAAAAAAAAAAAAAAADD/2gAIAQEABj8CH//EAB4QAAIBAwUAAAAAAAAAAAAAAAABERAhMUFhcZHw/9oACAEBAAE/IWuez2SROdLEKKwYE7H/2gAMAwEAAgADAAAAEAwAPP/EABgRAAIDAAAAAAAAAAAAAAAAAAEQESFR/9oACAEDAQE/EANVpX//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCEP//EAB8QAAIBAgcAAAAAAAAAAAAAAAERACFBEDFRgZGx0f/aAAgBAQABPxAiFSggC3ibuYYKmLnBB2PeCBNPOLUS2HE0T//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Grid icon next in css pane" title="" src="/static/450cd02e3f2705bbd5651062f8c974ee/65f94/gridicon.jpg" srcset="/static/450cd02e3f2705bbd5651062f8c974ee/6f81f/gridicon.jpg 270w, /static/450cd02e3f2705bbd5651062f8c974ee/65f94/gridicon.jpg 420w" sizes="(max-width: 420px) 100vw, 420px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>You can click on the icon and the layout will be toggled in the page for you to see the grid with lines separating each cell:</p> <p><img src="/550baee639c0fb6c3f4c624642b9f338/gridview.gif" alt="Toggle grid view"></p> <p>By default line numbers and area names are hidden. But you can check the two checkbox on the right to enable these.</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/01931c8aedc64c5f12f304eb90804274/38084/gridlinenumber.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 48.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABQAE/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAVinAJcVmqP/xAAcEAABAwUAAAAAAAAAAAAAAAAAAQIRBAUSEzL/2gAIAQEAAQUCiSrdg7a8UuHZ/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BZ//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/ASf/xAAcEAABAwUAAAAAAAAAAAAAAAAAAhAhEjJBUXH/2gAIAQEABj8CwJpiNFzI43//xAAcEAEAAgIDAQAAAAAAAAAAAAABABExUSGhsfD/2gAIAQEAAT8hRmOthGPQvKhufQICsTufY5n/2gAMAwEAAgADAAAAEEwv/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/EEZP/8QAFhEBAQEAAAAAAAAAAAAAAAAAERAx/9oACAECAQE/EG7P/8QAHBABAAICAwEAAAAAAAAAAAAAAQARITFxgZHw/9oACAEBAAE/EDBE1FeWRYG6CW9Ig5+XEEKHkwqg2T//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Line numbers and area names in grid view" title="" src="/static/01931c8aedc64c5f12f304eb90804274/47311/gridlinenumber.jpg" srcset="/static/01931c8aedc64c5f12f304eb90804274/6f81f/gridlinenumber.jpg 270w, /static/01931c8aedc64c5f12f304eb90804274/09d21/gridlinenumber.jpg 540w, /static/01931c8aedc64c5f12f304eb90804274/47311/gridlinenumber.jpg 1080w, /static/01931c8aedc64c5f12f304eb90804274/0047d/gridlinenumber.jpg 1620w, /static/01931c8aedc64c5f12f304eb90804274/274e1/gridlinenumber.jpg 2160w, /static/01931c8aedc64c5f12f304eb90804274/38084/gridlinenumber.jpg 2641w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p><![CDATA[JavaScript: useful features of ECMAScript 2019 reviewed]]>https://yashints.dev/blog/2019/08/06/es2019https://yashints.dev/blog/2019/08/06/es2019Tue, 06 Aug 2019 00:00:00 GMT<p>First of all let me apologise for not writing as frequent as I would’ve liked. It’s been a crazy busy couple of weeks and I had heaps of fun speaking at <a href="https://dddperth.com/agenda?sessionId=00311b92-6c21-47a8-b8d2-af325581d6f9" target="_blank" rel="nofollow noopener noreferrer">DDD Perth 2019</a>.</p> <p>That taken care of, this time I thought let’s go through the new features which are added into the <a href="https://www.ecma-international.org/ecma-262/10.0/index.html" target="_blank" rel="nofollow noopener noreferrer">ECMAScript 2019 (aka ES2019 or ES10)</a>, because they’re super exciting and make our lives much easier 😎.</p> <!--more--> <h2 id="tldr" style="position:relative;"><a href="#tldr" aria-label="tldr permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>TLDR;</h2> <p>At a glance, this version adds a few built-in functions on <code class="language-text">Array.prototype</code>, <code class="language-text">flat</code> and <code class="language-text">flatMap</code>. Then we have <code class="language-text">Object.fromEntries</code> for directly turning the return value of <code class="language-text">Object.entries</code> into a new <em>Object</em>.</p> <p>We also have <code class="language-text">trimStart</code> and <code class="language-text">trimEnd</code> on <code class="language-text">String.prototype</code> over the widely used non-standard versions <code class="language-text">String.prototype.trimLeft</code> and <code class="language-text">trimRight</code>.</p> <p>Another exciting feature is optional <code class="language-text">catch</code> binding parameters. In addition to those, there are some JSON improvements, addition of <code class="language-text">Symbol.prototype.description</code> which allows you to specify a description for your symbol, <code class="language-text">JSON.stringify</code> returns well-formed <strong>UTF-8</strong> regardless of input, and at last clarifying <code class="language-text">Function.prototype.toString</code> by requiring that it either return the corresponding original source text or a standard placeholder.</p> <p>So if you’re ready let’s dig in.</p> <h3 id="code-classlanguage-textarrayprototypeflat-flatmapcode" style="position:relative;"><a href="#code-classlanguage-textarrayprototypeflat-flatmapcode" aria-label="code classlanguage textarrayprototypeflat flatmapcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">Array.prototype.{flat, flatMap}</code></h3> <p><code class="language-text">flat()</code> is a new method which let’s you create a one-dimensional array from a multi-dimensional one.</p> <p>Imagine we have an array like below:</p> <div class="gatsby-code-button-container" data-toaster-id="82640519310720160000" data-toaster-class="gatsby-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 myArray = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]];`, `82640519310720160000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> myArray <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><span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</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 number">7</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 punctuation">[</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">11</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 punctuation">]</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Prior to <code class="language-text">flat</code> if you wanted to achieve this, you had to do something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="6866844418390716000" data-toaster-class="gatsby-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 myNewArray = [].concat.apply([], myArray) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`, `6866844418390716000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> myNewArray <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> myArray<span class="token punctuation">)</span> <span class="token comment">// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Or:</p> <div class="gatsby-code-button-container" data-toaster-id="12567113441868070000" data-toaster-class="gatsby-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 myNewArray = myArray.reduce( function(prev,curr) { return prev.concat(curr) } ) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`, `12567113441868070000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> myNewArray <span class="token operator">=</span> myArray<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">prev<span class="token punctuation">,</span>curr</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> prev<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>curr<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token comment">// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>With this new addition, it would be as simple as:</p> <div class="gatsby-code-button-container" data-toaster-id="94130536973308500000" data-toaster-class="gatsby-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 myNewArray = myArray.flat(4); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`, `94130536973308500000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> myNewArray <span class="token operator">=</span> myArray<span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>You can also chain multiple calls:</p> <div class="gatsby-code-button-container" data-toaster-id="55034689427970320000" data-toaster-class="gatsby-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 myNewArray = myArray.flat().flat().flat().flat(); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`, `55034689427970320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> myNewArray <span class="token operator">=</span> myArray<span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>The argument into the <code class="language-text">flat</code> function just specifies how deep it should look into the array. If you’re not sure how deep the array is, simply use <code class="language-text">Infinity</code> as input:</p> <div class="gatsby-code-button-container" data-toaster-id="36758567486104220000" data-toaster-class="gatsby-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 myNewArray = myArray.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`, `36758567486104220000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> myNewArray <span class="token operator">=</span> myArray<span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token number">Infinity</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>And if you don’t provide any input, by default it only goes one level deep:</p> <div class="gatsby-code-button-container" data-toaster-id="51434198828442270000" data-toaster-class="gatsby-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 myNewArray = myArray.flat(); // [1, 2, 3, 4, 5, 6, Array(4)];`, `51434198828442270000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> myNewArray <span class="token operator">=</span> myArray<span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 2, 3, 4, 5, 6, Array(4)];</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <hr/> <p><code class="language-text">flatMap</code> on the other hand, allows you to map each element using a mapping function and then flattens the result into a new array. Think of it as chaining a <code class="language-text">map</code> function with a single <code class="language-text">flat</code>. However, it can be really helpful both in terms of usage and efficiency of execution.</p> <div class="gatsby-code-button-container" data-toaster-id="60331300262467780000" data-toaster-class="gatsby-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 myArray = [1, 2, 3, 4, 5]; let mappedArray = myArray.map(x => [x, x * 2]); // [Array(2), Array(2), Array(2), Array(2), Array(2)] // 0: (2)[1, 2] // 1: (2)[2, 4] // 2: (2)[3, 6] // 3: (2)[4, 8] // 4: (2)[5, 10] let mappedFlattenedArr = mappedArray.flat(); // [1, 2, 2, 4, 3, 6, 4, 8, 5, 10] let myNewArray = myArray.flatMap(v => [v, v * 2]); // [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]`, `60331300262467780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> myArray <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 number">4</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 keyword">let</span> mappedArray <span class="token operator">=</span> myArray<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> <span class="token punctuation">[</span>x<span class="token punctuation">,</span> x <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [Array(2), Array(2), Array(2), Array(2), Array(2)]</span> <span class="token comment">// 0: (2)[1, 2]</span> <span class="token comment">// 1: (2)[2, 4]</span> <span class="token comment">// 2: (2)[3, 6]</span> <span class="token comment">// 3: (2)[4, 8]</span> <span class="token comment">// 4: (2)[5, 10]</span> <span class="token keyword">let</span> mappedFlattenedArr <span class="token operator">=</span> mappedArray<span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]</span> <span class="token keyword">let</span> myNewArray <span class="token operator">=</span> myArray<span class="token punctuation">.</span><span class="token function">flatMap</span><span class="token punctuation">(</span><span class="token parameter">v</span> <span class="token operator">=></span> <span class="token punctuation">[</span>v<span class="token punctuation">,</span> v <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="code-classlanguage-textstringprototypetrimstart-trimendcode" style="position:relative;"><a href="#code-classlanguage-textstringprototypetrimstart-trimendcode" aria-label="code classlanguage textstringprototypetrimstart trimendcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">String.prototype.{trimStart, .trimEnd}</code></h3> <p>These methods are fairly obvious as to what they will do for us. Just keep in mind that we had <code class="language-text">trimLeft</code> which will be replaced by <code class="language-text">trimStart</code> and <code class="language-text">trimRight</code> which will be replaced by <code class="language-text">trimEnd</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="82328078668042390000" data-toaster-class="gatsby-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 = ' This is a string with white space around '; message = message.trimStart(); // 'This is a string with white space around ' message = message.trimEnd(); // 'This is a string with white space around'`, `82328078668042390000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> message <span class="token operator">=</span> <span class="token string">' This is a string with white space around '</span><span class="token punctuation">;</span> message <span class="token operator">=</span> message<span class="token punctuation">.</span><span class="token function">trimStart</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'This is a string with white space around '</span> message <span class="token operator">=</span> message<span class="token punctuation">.</span><span class="token function">trimEnd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'This is a string with white space around'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="code-classlanguage-textobjectfromentriescode" style="position:relative;"><a href="#code-classlanguage-textobjectfromentriescode" aria-label="code classlanguage textobjectfromentriescode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">Object.fromEntries</code></h3> <p>This method get an <code class="language-text">Iterable</code> and transforms key-value pairs to an object. But let’s see what is an <code class="language-text">Iterable</code>:</p> <blockquote> <p>JavaScript supports a protocol by which objects such as arrays can be used by control structures such as <code class="language-text">for</code>…<code class="language-text">of</code> and the spread operator <code class="language-text">...</code> to loop through data sequentially. This is referred to as the iterable and the data structures that support this functionality are called iterables. While JavaScript provides maps, arrays and sets with an iterable property from the get-go, plain objects do not have this by default.</p> </blockquote> <p>To see this in action:</p> <div class="gatsby-code-button-container" data-toaster-id="85488385819496890000" data-toaster-class="gatsby-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 entries = new Map([[&quot;name&quot;, &quot;john&quot;], [&quot;age&quot;, 22]]); let newObj = Object.fromEntries(entries); // { name: 'john', age: 22 }`, `85488385819496890000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> entries <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"john"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">"age"</span><span class="token punctuation">,</span> <span class="token number">22</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">let</span> newObj <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">fromEntries</span><span class="token punctuation">(</span>entries<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// { name: 'john', age: 22 }</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>A real life use case is when parsing query strings:</p> <div class="gatsby-code-button-container" data-toaster-id="33627454845780980000" data-toaster-class="gatsby-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 query = Object.fromEntries(new URLSearchParams('foo=bar&baz=qux')); // { foo: 'bar', baz: 'qux' }`, `33627454845780980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> query <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">fromEntries</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span><span class="token string">'foo=bar&amp;baz=qux'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// { foo: 'bar', baz: 'qux' }</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="optional-catch-binding" style="position:relative;"><a href="#optional-catch-binding" aria-label="optional catch binding permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Optional Catch Binding</h3> <p>Optional catch binding allows us to use <code class="language-text">try/catch</code> without the <code class="language-text">error</code> parameter inside the catch block.</p> <p>Previously you had to use this syntax regardless of whether you cared about <code class="language-text">err</code> or not, such as when you had to fall back to feature to support older browsers:</p> <div class="gatsby-code-button-container" data-toaster-id="46281134835810250000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`try { // try to use a web feature which may not be implemented } catch (unused) { // fall back to a less desirable web feature with broader support }`, `46281134835810250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token comment">// try to use a web feature which may not be implemented</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>unused<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// fall back to a less desirable web feature with broader support</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>With <code class="language-text">ES2019</code> you can do:</p> <div class="gatsby-code-button-container" data-toaster-id="3952421734454381000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`try { // ... } catch { // ... }`, `3952421734454381000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="code-classlanguage-textsymboldescriptioncode" style="position:relative;"><a href="#code-classlanguage-textsymboldescriptioncode" aria-label="code classlanguage textsymboldescriptioncode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">Symbol.description</code></h3> <p>This new read-only description property is a string returning the optional description of <code class="language-text">Symbol</code> objects. This method is encouraged to be used instead of <code class="language-text">Symbol.prototype.toString</code> where it wasn’t obvious what will be returned.</p> <div class="gatsby-code-button-container" data-toaster-id="18500725329809020000" data-toaster-class="gatsby-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 description = 'This symbol represents an emoji 😁'; let mySym = Symbol(description); // Symbol('This symbol represents an emoji 😁') console.log(mySym.description); 'This symbol represents an emoji 😁'`, `18500725329809020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> description <span class="token operator">=</span> <span class="token string">'This symbol represents an emoji 😁'</span><span class="token punctuation">;</span> <span class="token keyword">let</span> mySym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span>description<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Symbol('This symbol represents an emoji 😁')</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>mySym<span class="token punctuation">.</span>description<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token string">'This symbol represents an emoji 😁'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="code-classlanguage-textfunctiontostringcode" style="position:relative;"><a href="#code-classlanguage-textfunctiontostringcode" aria-label="code classlanguage textfunctiontostringcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">Function.toString</code></h3> <p>This method is a really useful one which returns the source code of a function. Imagine doing a troubleshooting on a block of code which is using a third party function. This can potentially help you to see the implementation (given it’s got source maps).</p> <div class="gatsby-code-button-container" data-toaster-id="14443075737580347000" data-toaster-class="gatsby-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 myFn(emoji) { let msg = \`\${emoji} is hellav an emoji\`; console.log(msg); } console.log(myFn.toString()); // &quot;function myFn(emoji) { // let msg = \`\${emoji} is hellav an emoji\`; // console.log(msg); // }&quot;`, `14443075737580347000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">myFn</span><span class="token punctuation">(</span><span class="token parameter">emoji</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> msg <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>emoji<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is hellav an emoji</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>msg<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>myFn<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">// "function myFn(emoji) {</span> <span class="token comment">// let msg = `${emoji} is hellav an emoji`;</span> <span class="token comment">// console.log(msg);</span> <span class="token comment">// }"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Of course this doesn’t work for everything. If we try it for <code class="language-text">map</code> function on array:</p> <div class="gatsby-code-button-container" data-toaster-id="47346811861093550000" data-toaster-class="gatsby-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.prototype.map.toString(); // &quot;function map() { [native code] }&quot;`, `47346811861093550000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>map<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 comment">// "function map() { [native code] }"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Since the implementation is not written in JavaScript, it will just show you that this function is written in native code.</p> <h3 id="code-classlanguage-textjsonstringifycode" style="position:relative;"><a href="#code-classlanguage-textjsonstringifycode" aria-label="code classlanguage textjsonstringifycode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">JSON.stringify</code></h3> <p>The team have done an improvement with <strong>Unicode</strong> characters and now this method can’t return malformed data.</p> <div class="gatsby-code-button-container" data-toaster-id="22129349662782837000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// Non-BMP characters still serialize to surrogate pairs. JSON.stringify('𝌆') // → '&quot;𝌆&quot;' JSON.stringify('\uD834\uDF06') // → '&quot;𝌆&quot;' // Unpaired surrogate code units will serialize to escape sequences. JSON.stringify('\uDF06\uD834') // → '&quot;\\udf06\\ud834&quot;' JSON.stringify('\uDEAD') // → '&quot;\\udead&quot;'`, `22129349662782837000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// Non-BMP characters still serialize to surrogate pairs.</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token string">'𝌆'</span><span class="token punctuation">)</span> <span class="token comment">// → '"𝌆"'</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token string">'\uD834\uDF06'</span><span class="token punctuation">)</span> <span class="token comment">// → '"𝌆"'</span> <span class="token comment">// Unpaired surrogate code units will serialize to escape sequences.</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token string">'\uDF06\uD834'</span><span class="token punctuation">)</span> <span class="token comment">// → '"\\udf06\\ud834"'</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token string">'\uDEAD'</span><span class="token punctuation">)</span> <span class="token comment">// → '"\\udead"'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="code-classlanguage-textarraysortcode-stability" style="position:relative;"><a href="#code-classlanguage-textarraysortcode-stability" aria-label="code classlanguage textarraysortcode stability permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">Array.sort</code> Stability</h3> <p>The team has decided to change the sort implementation so that it would be stable (that is, elements that compare equal must remain in their original order).</p> <div class="gatsby-code-button-container" data-toaster-id="62219916230939500000" data-toaster-class="gatsby-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 grades = [ { topic: 'math', grade: 10 }, { topic: 'literacy', grade: 10 }, { topic: 'chemical', grade: 13 }, { topic: 'geography', grade: 12 }, { topic: 'modern history', grade: 12 }, { topic: 'art', grade: 13 }, { topic: 'computer basics', grade: 14 }, { topic: 'algebra', grade: 14 }, ]; grades.sort(a, b => a.grade - b.grade); // 0: {topic: &quot;math&quot;, grade: 10} // 1: {topic: &quot;literacy&quot;, grade: 10} // 2: {topic: &quot;geography&quot;, grade: 12} // 3: {topic: &quot;modern history&quot;, grade: 12} // 4: {topic: &quot;chemical&quot;, grade: 13} // 5: {topic: &quot;art&quot;, grade: 13} // 6: {topic: &quot;computer basics&quot;, grade: 14} // 7: {topic: &quot;algebra&quot;, grade: 14}`, `62219916230939500000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> grades <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'math'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</span><span class="token operator">:</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 literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'literacy'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</span><span class="token operator">:</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 literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'chemical'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</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 literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'geography'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</span><span class="token operator">:</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 literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'modern history'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</span><span class="token operator">:</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 literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'art'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</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 literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'computer basics'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</span><span class="token operator">:</span> <span class="token number">14</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">topic</span><span class="token operator">:</span> <span class="token string">'algebra'</span><span class="token punctuation">,</span> <span class="token literal-property property">grade</span><span class="token operator">:</span> <span class="token number">14</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> grades<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> <span class="token parameter">b</span> <span class="token operator">=></span> a<span class="token punctuation">.</span>grade <span class="token operator">-</span> b<span class="token punctuation">.</span>grade<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 0: {topic: "math", grade: 10}</span> <span class="token comment">// 1: {topic: "literacy", grade: 10}</span> <span class="token comment">// 2: {topic: "geography", grade: 12}</span> <span class="token comment">// 3: {topic: "modern history", grade: 12}</span> <span class="token comment">// 4: {topic: "chemical", grade: 13}</span> <span class="token comment">// 5: {topic: "art", grade: 13}</span> <span class="token comment">// 6: {topic: "computer basics", grade: 14}</span> <span class="token comment">// 7: {topic: "algebra", grade: 14}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 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</h3> <p>In general JavaScript is moving in the right direction for helping developers write more stable, reliable and consistent code. You can find more information on their <a href="https://github.com/tc39/proposals" target="_blank" rel="nofollow noopener noreferrer">GitHub repo here</a>.</p> <p>Hope to see more awesome features in JavaScript and see you soon with another article.</p><![CDATA[10 questions to ask in a technical interview]]>https://yashints.dev/blog/2019/07/17/interview-questionshttps://yashints.dev/blog/2019/07/17/interview-questionsWed, 17 Jul 2019 00:00:00 GMT<p>I’ve been sitting many interview sessions recently as part of our recruitment process and let me tell you it’s one of the hardest tasks I’ve ever had. In this post I wanted to share my findings and approach with you so we can all be more intelligent, inclusive and successful in our hiring process. And I am super keen to hear from you in comments 👇🏼.</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>The most important part of every interview is how to qualify a candidate without being too specific about a technology or framework. It’s about measuring their abilities and potentials rather than asking questions where any person can find somewhere and memorise the answer.</p> <p>We, at <a href="https://join.readify.net/" target="_blank" rel="nofollow noopener noreferrer">Readify</a>, have a very specific and complex (if I may say so, which I just did 😁) process for hiring great fits, not just technical, but also culturally.</p> <p>To be able to do this, we need to be very careful with what is being asked during our technical interviews which is reached after a coding challenge and live coding session.</p> <h2 id="what-do-we-ask" style="position:relative;"><a href="#what-do-we-ask" aria-label="what do we 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 do we ask</h2> <p>I don’t want to review our hiring process, more focus on what is being asked and how do we phrase them. There are plenty of sites which show you what to ask and unfortunately most of them have some predictable questions like:</p> <blockquote> <p>Where do you see yourself in 5 years?</p> </blockquote> <p>To be honest I don’t even know what happens for me in 5 months, let alone 5 years. So the question is what should we ask to be able to find out as much as we can about a candidate without falling into trap of asking fruitless questions.</p> <p>To determine whether someone is a good fit for the job, you want to draw them out, ask a mix of technical and situational questions, and listen closely to not only what they have to say but how they say it. The so called technical questions shouldn’t be around what, but about how. You want to evaluate how they perform in certain situations like solving a tough problem.</p> <p>So let’s begin.</p> <h2 id="1-what-challenging-problem-have-you-had-in-the-last-couple-of-months" style="position:relative;"><a href="#1-what-challenging-problem-have-you-had-in-the-last-couple-of-months" aria-label="1 what challenging problem have you had in the last couple of months permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. What challenging problem have you had in the last couple of months?</h2> <p>This question is like an ice breaker. It will put them at ease because they will be able to talk about something they’re comfortable with. This will also give you an opportunity to see how they go about solving a problem. You can go in more details in areas where you see value in, such as <em>why did you choose this specific way to solve it</em>, or <em>why didn’t you try blah</em>.</p> <p>You can get an overview of their team work too, did they collaborate on solving his problem, or did they help someone or get help from them.</p> <h2 id="2-what-resources-do-you-use-to-learn-or-sharpen-your-skills" style="position:relative;"><a href="#2-what-resources-do-you-use-to-learn-or-sharpen-your-skills" aria-label="2 what resources do you use to learn or sharpen your skills permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. What resources do you use to learn or sharpen your skills?</h2> <p>Many developers turn to websites such as <a href="https://stackoverflow.com/" target="_blank" rel="nofollow noopener noreferrer">StackOverflow</a>, <a href="https://medium.com" target="_blank" rel="nofollow noopener noreferrer">Medium</a>, or <a href="https://dev.to" target="_blank" rel="nofollow noopener noreferrer">Dev</a> when they need help with something. Serious professionals will have their own selection of websites, online communities, social media feeds and other resources specific to their interests. The answer to this question will give you an indication of how engaged the candidate is with the broader IT community.</p> <p>Apart from those, Meetups, conferences, YouTube Channels, taking online courses, joining hackathons, plugging away at personal IT projects and many more can be discussed to see how the candidate keep themselves up to date, or find answer to a problem.</p> <h2 id="3-how-do-you-explain-x-in-simple-terms" style="position:relative;"><a href="#3-how-do-you-explain-x-in-simple-terms" aria-label="3 how do you explain x in simple terms permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. How do you explain X in simple terms?</h2> <p>This is very good to see how they can simplify a technical term or subject. It’s very good to understand how deep they know something or how broad their knowledge is.</p> <p>Another aspect about this is to be able to communicate to stakeholders of a project. If you can explain a subject to your <em>Product Owner</em>, <em>BA</em>, <em>Tester</em> and so on, your whole team would be more successful delivering your project.</p> <h2 id="4-what-qualities-do-you-think-is-required-for-x" style="position:relative;"><a href="#4-what-qualities-do-you-think-is-required-for-x" aria-label="4 what qualities do you think is required for x permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4. What qualities do you think is required for X?</h2> <p>This questions will help you unravel some of the candidate’s expectations and also how they see the role. Some people may focus on certifications and technical abilities, while others may talk more about problem solving, attention to detail, communication and other general job skills. Look for candidates who give a nice balance of both.</p> <h2 id="5-what-are-x-words-your-colleagues-describe-you-with" style="position:relative;"><a href="#5-what-are-x-words-your-colleagues-describe-you-with" aria-label="5 what are x words your colleagues describe you with permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>5. What are X words your colleagues describe you with?</h2> <p>This might sound cliché, but it will help you find out about some of their aspects not found in resume or social media profiles. It also gives insight into how the individual perceives themselves and the role they’re applying for. For example, if their answer focuses on their creative side but the position is very analytical in nature, the job may not be a good fit.</p> <h2 id="6-tell-us-about-a-challenging-situation-you-had-which-resulted-in-failure-such-as-missing-a-deadline-or-a-promotion-being-rejected" style="position:relative;"><a href="#6-tell-us-about-a-challenging-situation-you-had-which-resulted-in-failure-such-as-missing-a-deadline-or-a-promotion-being-rejected" aria-label="6 tell us about a challenging situation you had which resulted in failure such as missing a deadline or a promotion being rejected permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>6. Tell us about a challenging situation you had which resulted in failure, such as missing a deadline or a promotion being rejected?</h2> <p>We all deals with professional setbacks at some point in our career. What you want to know is how people handled — and what they learned from — those situations. The best employees are resilient, using setbacks as a springboard toward positive changes. So listen to not only the problem they mention, but also what they did after the disappointment.</p> <h2 id="7-what-is-your-most-and-least-favourite-frameworkproduct" style="position:relative;"><a href="#7-what-is-your-most-and-least-favourite-frameworkproduct" aria-label="7 what is your most and least favourite frameworkproduct permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>7. What is your most and least favourite framework/product?</h2> <p>This question helps you evaluate enthusiasm and knowledge. Do candidates become animated when discussing the advantages and disadvantages of certain tools/framework/library? Do they admire solid engineering, sleek design, intuitive user experience or another aspect of good technology?</p> <p>What is their focus area in a tool, what they look for and what value they see in their favourite choice. These will give you great insight about them.</p> <h2 id="8-what-are-the-pros-and-cons-of-working-in-an-agile-environment" style="position:relative;"><a href="#8-what-are-the-pros-and-cons-of-working-in-an-agile-environment" aria-label="8 what are the pros and cons of working in an agile environment permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>8. What are the pros and cons of working in an agile environment?</h2> <p>This question can help you understand their perception of agile, how they operate in a fast pace environment which means lots of quick meetings and a steady stream of feedback from fellow team members. Most developers don’t like too many meetings especially if they’re doing SCRUM until they realise the benefit of each of those and how they help reduce the time waste.</p> <p>A candidate’s answer to this question can tell you not only their level of understanding of this popular environment, but also their attitudes toward collaboration and communication.</p> <h2 id="9-what-was-your-last-presentation" style="position:relative;"><a href="#9-what-was-your-last-presentation" aria-label="9 what was your last presentation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>9. What was your last presentation?</h2> <p>First of all, let me clear the fact that by presentation I don’t mean public speaking like conferences and meetups. However, having public speaking background is a bonus since it proves a couple of points.</p> <p>Today’s tech workers can’t be lone wolves. They have to discuss changes with colleagues, coordinate with other departments, advocate for platforms they prefer and much more. While not everyone has to love public speaking, your new hire should be able to conduct research, put together a solid presentation and persuade stakeholders why <code class="language-text">X</code> is better than <code class="language-text">Y</code>.</p> <h2 id="10-how-do-you-manage-your-work-life-balance" style="position:relative;"><a href="#10-how-do-you-manage-your-work-life-balance" aria-label="10 how do you manage your work life balance permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>10. How do you manage your work life balance?</h2> <p>There many scenarios where one has to work harder than usual. A pressing deadline, on-call duties (fortunately we don’t have this), or simply someone who is addicted to spend all their time working are examples where we need to be careful about.</p> <p>While you want dedicated team members, you should also seek employees who know how to relax and take care of themselves. Burnout is a very real problem in our industry, and top performers have good strategies in place to prevent it. As a follow up to their answer, you could talk about how your company supports a healthy work life balance (we do this via multiple ways) — something that can be very tempting for candidates with multiple offers.</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 many questions you can ask during an interview, but those who target intelligence, creativity, and learning abilities are the most helpful ones. When interviewing a candidate, always look for their strength and quick learning ability. Don’t ask technical questions which their answer wouldn’t help you uncover the candidate’s potential. People can spend a couple of days and find out those questions and their answers from many sources. But the questions mentioned here and those similar in nature would help you find a good fit for your team.</p> <p>And a final advice from truly yours, don’t be a jerk when interviewing a candidate. Don’t be biased on gender, background, appearance, and other factors which prevent you from finding good people.</p><![CDATA[JavaScript can do that?]]>https://yashints.dev/blog/2019/06/26/js-can-do-thathttps://yashints.dev/blog/2019/06/26/js-can-do-thatWed, 26 Jun 2019 00:00:00 GMT<p>You might be wondering why I am writing less these days. I assure you, it’s not because I am getting lazy (I am ATM 🤩), it’s just that I am on a long overdue holiday. But to keep my juices going, I thought now that I am having fun, let’s write a fun post 😊.</p> <!--more--> <p>In this post I will go through some of the funniest yet unbelievable JavaScript snippets ever. Are you ready?</p> <h2 id="code-classlanguage-textcode-is-equal-code-classlanguage-textcode" style="position:relative;"><a href="#code-classlanguage-textcode-is-equal-code-classlanguage-textcode" aria-label="code classlanguage textcode is equal code classlanguage textcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">[]</code> is equal <code class="language-text">![]</code></h2> <p>Array is equal to not array 😂:</p> <div class="gatsby-code-button-container" data-toaster-id="33284772565807200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`;[] == ![] // -> true`, `33284772565807200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">;</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token operator">!</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">// -> true</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p>The abstract equality operator converts both sides to numbers before comparing them, and both sides will be converted to <code class="language-text">0</code> for different reasons. Arrays are truthy, so the right hand side becomes false which then is coerced to <code class="language-text">0</code>. On the left however, the empty array is coerced to a number without becoming a boolean first, and empty arrays are coerced to <code class="language-text">0</code>, despite being truthy 🤯.</p> <h2 id="code-classlanguage-texttruecode-is-code-classlanguage-textfalsecode" style="position:relative;"><a href="#code-classlanguage-texttruecode-is-code-classlanguage-textfalsecode" aria-label="code classlanguage texttruecode is code classlanguage textfalsecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">true</code> is <code class="language-text">false</code></h2> <p>True is false:</p> <div class="gatsby-code-button-container" data-toaster-id="1268789768665334800" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`!!'false' == !!'true' // -> true !!'false' === !!'true' // -> true`, `1268789768665334800`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token operator">!</span><span class="token operator">!</span><span class="token string">'false'</span> <span class="token operator">==</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token string">'true'</span> <span class="token comment">// -> true</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token string">'false'</span> <span class="token operator">===</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token string">'true'</span> <span class="token comment">// -> true</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p><code class="language-text">true</code> is <code class="language-text">truthy</code> and is represented by value 1 (number), <code class="language-text">true</code> in string form, is <code class="language-text">NaN</code>. So:</p> <div class="gatsby-code-button-container" data-toaster-id="88534721204672270000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`true == 'true' // -> false false == 'false' // -> false`, `88534721204672270000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token boolean">true</span> <span class="token operator">==</span> <span class="token string">'true'</span> <span class="token comment">// -> false</span> <span class="token boolean">false</span> <span class="token operator">==</span> <span class="token string">'false'</span> <span class="token comment">// -> false</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p><code class="language-text">false</code> is not the empty string, so it’s a truthy value, so:</p> <div class="gatsby-code-button-container" data-toaster-id="23267911096847405000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`!!'false' // -> true !!'true' // -> true`, `23267911096847405000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token operator">!</span><span class="token operator">!</span><span class="token string">'false'</span> <span class="token comment">// -> true</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token string">'true'</span> <span class="token comment">// -> true</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Cool, ha? 😎</p> <h2 id="banana-" style="position:relative;"><a href="#banana-" aria-label="banana permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>baNaNa 🍌</h2> <p>Let’s create a banana:</p> <div class="gatsby-code-button-container" data-toaster-id="38958939655739200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`'b' + 'a' + +'a' + 'a' // -> baNaNa`, `38958939655739200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token string">'b'</span> <span class="token operator">+</span> <span class="token string">'a'</span> <span class="token operator">+</span> <span class="token operator">+</span><span class="token string">'a'</span> <span class="token operator">+</span> <span class="token string">'a'</span> <span class="token comment">// -> baNaNa</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p>This one is an old trick, remixed. The expression is converted to <code class="language-text">"ba" + (+"a") + "a"</code>, and since <code class="language-text">"a"</code> is converted to a number, it becomes <code class="language-text">NaN</code>.</p> <h2 id="lets-fail" style="position:relative;"><a href="#lets-fail" aria-label="lets fail permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Let’s fail</h2> <p>You wouldn’t believe this in your wildest dreams, but:</p> <div class="gatsby-code-button-container" data-toaster-id="61884114437368430000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`;(![] + [])[+[]] + (![] + [])[+!+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] // -> 'fail'`, `61884114437368430000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><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 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 operator">+</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 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 punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token operator">+</span><span class="token operator">!</span><span class="token operator">+</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 operator">!</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><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token operator">+</span><span class="token operator">!</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 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 operator">+</span> <span class="token punctuation">(</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 punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token operator">!</span><span class="token operator">+</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token operator">!</span><span class="token operator">+</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">// -> 'fail'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p>If we break this lot into smaller pieces, we notice that the following pattern occurs often:</p> <div class="gatsby-code-button-container" data-toaster-id="87708307679079700000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`![] + [] // -> 'false' ![] // -> false`, `87708307679079700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><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 punctuation">]</span> <span class="token comment">// -> 'false'</span> <span class="token operator">!</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">// -> false</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>We try adding <code class="language-text">[]</code> to <code class="language-text">false</code>, but because of a number of function calls internally, we’ll end up converting the right operand into a string:</p> <div class="gatsby-code-button-container" data-toaster-id="40883291806246410000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`![] + [].toString() // -> 'false'`, `40883291806246410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><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 punctuation">]</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// -> 'false'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Thinking of a string as an array we can access its first character via <code class="language-text">[0]</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="7338423789912806000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`'false'[0] // -> 'f'`, `7338423789912806000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token string">'false'</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token comment">// -> 'f'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The rest is obvious, but the <code class="language-text">i</code> is tricky. The <code class="language-text">i</code> in fail is grabbed by generating the string <code class="language-text">falseundefined</code> and taking the element on index <code class="language-text">['10']</code>.</p> <h2 id="array-equality-is-evil-" style="position:relative;"><a href="#array-equality-is-evil-" aria-label="array equality is evil permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Array equality is evil 👾</h2> <p>Array equality is evil in JavaScript, see below:</p> <div class="gatsby-code-button-container" data-toaster-id="87272627886484160000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[] == '' // -> true [] == 0 // -> true [''] == '' // -> true [0] == 0 // -> true [0] == '' // -> false [''] == 0 // -> true [null] == '' // true [null] == 0 // true [undefined] == '' // true [undefined] == 0 // true [[]] == 0 // true [[]] == '' // true [[[[[[]]]]]] == '' // true [[[[[[]]]]]] == 0 // true [[[[[[ null ]]]]]] == 0 // true [[[[[[ null ]]]]]] == '' // true [[[[[[ undefined ]]]]]] == 0 // true [[[[[[ undefined ]]]]]] == '' // true`, `87272627886484160000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">''</span> <span class="token comment">// -> true</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token comment">// -> true</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">''</span> <span class="token comment">// -> true</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token comment">// -> true</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">''</span> <span class="token comment">// -> false</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token comment">// -> true</span> <span class="token punctuation">[</span><span class="token keyword">null</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">''</span> <span class="token comment">// true</span> <span class="token punctuation">[</span><span class="token keyword">null</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token comment">// true</span> <span class="token punctuation">[</span><span class="token keyword">undefined</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">''</span> <span class="token comment">// true</span> <span class="token punctuation">[</span><span class="token keyword">undefined</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token comment">// 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 operator">==</span> <span class="token number">0</span> <span class="token comment">// 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 operator">==</span> <span class="token string">''</span> <span class="token comment">// 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 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 operator">==</span> <span class="token string">''</span> <span class="token comment">// 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 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 operator">==</span> <span class="token number">0</span> <span class="token comment">// 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 punctuation">[</span> <span class="token keyword">null</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 operator">==</span> <span class="token number">0</span> <span class="token comment">// 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 punctuation">[</span> <span class="token keyword">null</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 operator">==</span> <span class="token string">''</span> <span class="token comment">// 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 punctuation">[</span> <span class="token keyword">undefined</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 operator">==</span> <span class="token number">0</span> <span class="token comment">// 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 punctuation">[</span> <span class="token keyword">undefined</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 operator">==</span> <span class="token string">''</span> <span class="token comment">// true</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p>The explanation behind this is rather long. So I introduce you to <a href="https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison" target="_blank" rel="nofollow noopener noreferrer">section 7.2.13 Abstract Equality Comparison</a> of the specification.</p> <h2 id="code-classlanguage-textparseintcode-is-just-bad" style="position:relative;"><a href="#code-classlanguage-textparseintcode-is-just-bad" aria-label="code classlanguage textparseintcode is just bad permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">parseInt</code> is just bad</h2> <p><code class="language-text">parseInt</code> is famous by its quirks, I just mention one of the most famous ones:</p> <div class="gatsby-code-button-container" data-toaster-id="29718667348738560000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`parseInt('f**k') // -> NaN parseInt('f**k', 16) // -> 15`, `29718667348738560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token function">parseInt</span><span class="token punctuation">(</span><span class="token string">'f**k'</span><span class="token punctuation">)</span> <span class="token comment">// -> NaN</span> <span class="token function">parseInt</span><span class="token punctuation">(</span><span class="token string">'f**k'</span><span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span> <span class="token comment">// -> 15</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p>This happens because <code class="language-text">parseInt</code> will continue parsing character by character until it hits one it doesn’t know. The <code class="language-text">f</code> in <code class="language-text">f**k</code> is the hexadecimal digit <code class="language-text">15</code>.</p> <h2 id="code-classlanguage-textnancode-is-not-a-number" style="position:relative;"><a href="#code-classlanguage-textnancode-is-not-a-number" aria-label="code classlanguage textnancode is not a number permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">NaN</code> is <del>not</del> a number</h2> <p>Type of <code class="language-text">NaN</code> is a <code class="language-text">number</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="42613017484839660000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`typeof NaN // -> 'number'`, `42613017484839660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">typeof</span> <span class="token number">NaN</span> <span class="token comment">// -> 'number'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p>Explanations of how <code class="language-text">typeof</code> and <code class="language-text">instanceof</code> operators work:</p> <ul> <li><a href="https://www.ecma-international.org/ecma-262/#sec-typeof-operator" target="_blank" rel="nofollow noopener noreferrer">12.5.5 The <code class="language-text">typeof</code> Operator</a></li> <li><a href="https://www.ecma-international.org/ecma-262/#sec-instanceofoperator" target="_blank" rel="nofollow noopener noreferrer">12.10.4 Runtime Semantics: <code class="language-text">InstanceofOperator(O,C)</code></a></li> </ul> <h2 id="comparison-of-three-numbers" style="position:relative;"><a href="#comparison-of-three-numbers" aria-label="comparison of three numbers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Comparison of three numbers</h2> <p>This one is gold:</p> <div class="gatsby-code-button-container" data-toaster-id="72231097236362490000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`1 < 2 < 3 // -> true 3 > 2 > 1 // -> false`, `72231097236362490000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token number">1</span> <span class="token operator">&lt;</span> <span class="token number">2</span> <span class="token operator">&lt;</span> <span class="token number">3</span> <span class="token comment">// -> true</span> <span class="token number">3</span> <span class="token operator">></span> <span class="token number">2</span> <span class="token operator">></span> <span class="token number">1</span> <span class="token comment">// -> false</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p><strong>💡 What’s happening?</strong></p> <p>Why does this work that way? Well, the problem is in the first part of an expression. Here’s how it works:</p> <div class="gatsby-code-button-container" data-toaster-id="34101480371344260000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`1 < 2 < 3 // 1 < 2 -> true true < 3 // true -> 1 1 < 3 // -> true 3 > 2 > 1 // 3 > 2 -> true true > 1 // true -> 1 1 > 1 // -> false`, `34101480371344260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token number">1</span> <span class="token operator">&lt;</span> <span class="token number">2</span> <span class="token operator">&lt;</span> <span class="token number">3</span> <span class="token comment">// 1 &lt; 2 -> true</span> <span class="token boolean">true</span> <span class="token operator">&lt;</span> <span class="token number">3</span> <span class="token comment">// true -> 1</span> <span class="token number">1</span> <span class="token operator">&lt;</span> <span class="token number">3</span> <span class="token comment">// -> true</span> <span class="token number">3</span> <span class="token operator">></span> <span class="token number">2</span> <span class="token operator">></span> <span class="token number">1</span> <span class="token comment">// 3 > 2 -> true</span> <span class="token boolean">true</span> <span class="token operator">></span> <span class="token number">1</span> <span class="token comment">// true -> 1</span> <span class="token number">1</span> <span class="token operator">></span> <span class="token number">1</span> <span class="token comment">// -> false</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can fix this with greater than or equal operator (<code class="language-text">>=</code>):</p> <div class="gatsby-code-button-container" data-toaster-id="95701338134543160000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`3 > 2 >= 1 // true`, `95701338134543160000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token number">3</span> <span class="token operator">></span> <span class="token number">2</span> <span class="token operator">>=</span> <span class="token number">1</span> <span class="token comment">// true</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Read more about Relational operators in the specification:</p> <ul> <li><a href="https://www.ecma-international.org/ecma-262/#sec-relational-operators" target="_blank" rel="nofollow noopener noreferrer">12.10 Relational Operators</a></li> </ul> <p>And that’s just some of the fun we can have with JavaScript. No wonder some people do not like it, since they don’t understand how it works 😂.</p><![CDATA[Boost your ranking with these 10 tips]]>https://yashints.dev/blog/2019/06/11/seo-tipshttps://yashints.dev/blog/2019/06/11/seo-tipsTue, 11 Jun 2019 00:00:00 GMT<p>For most companies, ranking #1 is like a blessing to their business. However, most of the web developers are not aware of what should be done to reach to that point.</p> <p>In this article we go through 10 simple steps to increase the ranking organically rather than paying search engines to do that for us. So, are you ready 🧐?</p> <!--more--> <h2 id="what-does-html-tags-tell-search-engines" style="position:relative;"><a href="#what-does-html-tags-tell-search-engines" aria-label="what does html tags tell 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>What does HTML tags tell search engines?</h2> <p>Certain HTML tags tell search engines how to read your document properly and index it against specific keywords. In other words, when they crawl web, they will categorise your page with some keywords which then is surfaced when a user searches for them.</p> <p>Some of these tags also improve how visitors view your content in those search engines. And this is in addition to how social media uses content tags to show your articles like this for example 👇🏽.</p> <blockquote class="twitter-tweet"><p lang="en" dir="ltr">Just a reminder to not miss my talk on micro apps and web components <a href="https://twitter.com/NDC_Conferences?ref_src=twsrc%5Etfw">@NDC_Conferences</a> <a href="https://twitter.com/hashtag/NDCOslo?src=hash&amp;ref_src=twsrc%5Etfw">#NDCOslo</a> 👇🏽<a href="https://t.co/JjBDfpAhmd">https://t.co/JjBDfpAhmd</a></p>&mdash; Yaser A Mehraban👨🏽‍💻🎤☕️😴 (@yashints) <a href="https://twitter.com/yashints/status/1138194205912707073?ref_src=twsrc%5Etfw">June 10, 2019</a></blockquote> <p>So let’s see what are these tags.</p> <h2 id="1-title-tag" style="position:relative;"><a href="#1-title-tag" aria-label="1 title tag permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Title tag</h2> <p>Perhaps one the most important tags is title. This is used as a label for your page and defines how search engines like Google and Bing see your page and show it in their search result.</p> <p>In most cases, this tag reflects the title of the article/page itself. This isn’t exactly a bad practice, but you’ll miss out on a few opportunities to score big in search engines like Google.</p> <p>The question which comes up is, does it have to be the same as keywords. And the answer is absolutely not. However, it’s good to make sure you’re not confusing the reader 😉. But this gives opportunity to expand on what your page is relevant to for the search engine. Title should be short anyway, so having different but related tags makes it accessible to a wider range of searches.</p> <p>A normal title tag is shown below:</p> <div class="gatsby-code-button-container" data-toaster-id="88406092090876760000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<title>Your Title Text for Search Engines</title>`, `88406092090876760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Your Title Text for Search Engines<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>It sounds very simple right? Well as simple as it looks, below are the points you have to consider when writing your title:</p> <ul> <li>Use only one title tag</li> <li>Try to create a unique title</li> <li>Don’t use your title keywords as your meta tags too (read further on tags)</li> <li>Make it relevant to content</li> <li>It’s good to keep it under 60 characters</li> <li>Try to not use stop words</li> <li>Show the branding last</li> <li>Make it readable</li> <li>Use dates, numbers and questions if relevant</li> </ul> <p>Here is an example of one of my articles being the first result on Google 😍:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 792px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 33.33333333333333%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAHABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3QUD/8QAFhAAAwAAAAAAAAAAAAAAAAAAABAR/9oACAEBAAEFAir/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAYEAACAwAAAAAAAAAAAAAAAAAAARAhYf/aAAgBAQABPyF0LEf/2gAMAwEAAgADAAAAEIAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGRAAAwEBAQAAAAAAAAAAAAAAAAERITGR/9oACAEBAAE/ENolUaRN6LVeH//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Title helping SEO" title="" src="/static/e45ad815cf29e452ee3cdf555fcd8531/4dfa3/nestedfg.jpg" srcset="/static/e45ad815cf29e452ee3cdf555fcd8531/6f81f/nestedfg.jpg 270w, /static/e45ad815cf29e452ee3cdf555fcd8531/09d21/nestedfg.jpg 540w, /static/e45ad815cf29e452ee3cdf555fcd8531/4dfa3/nestedfg.jpg 792w" sizes="(max-width: 792px) 100vw, 792px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <h2 id="2-meta-description-tags" style="position:relative;"><a href="#2-meta-description-tags" aria-label="2 meta description tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Meta description tags</h2> <p>As I mentioned above, having description tags is really helpful to expose your page to a wider range of searches in addition to title.</p> <div class="gatsby-code-button-container" data-toaster-id="31451401467523076000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<meta name=&quot;description&quot; content=&quot;Key HTML tags to have better SEO.&quot; />`, `31451401467523076000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>description<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Key HTML tags to have better SEO.<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>For example, above is a tag where someone tried to highlight “Key HTML tags” and “better SEO” phrases and also to be displayed in search results.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> As of 2019, <a href="https://webmasters.googleblog.com/2017/06/better-snippets-for-your-users.html" target="_blank" rel="nofollow noopener noreferrer">Google has announced</a> that you shouldn’t focus too much on these as they will consider content first.</div></div> <h2 id="3-header-tags" style="position:relative;"><a href="#3-header-tags" aria-label="3 header tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Header tags</h2> <p>You should not underestimate header tags. They are often used to break up the content to make it easier to read. Imagine reading my article in one giant paragraph rather than these nicely separated pieces.</p> <p>It’s been discovered that about %55 of the users will spend <a href="https://blog.bufferapp.com/55-visitors-read-articles-15-seconds-less-focus-attention-not-clicks" target="_blank" rel="nofollow noopener noreferrer">15 seconds at most skimming your text</a>. In terms of SEO, header tags are what most search engines use to help determine segments of content and create <a href="https://www.greengeeks.com/blog/2017/02/14/why-should-you-want-your-site-to-be-in-the-google-featured-snippet/" target="_blank" rel="nofollow noopener noreferrer">featured rich snippets</a>.</p> <p>These tags are as follows:</p> <ul> <li><code class="language-text">&lt;h1>&lt;/h1></code> – Usually is used for webpage titles.</li> <li><code class="language-text">&lt;h2>&lt;/h2></code> – Highlights the topic of the content following it.</li> <li><code class="language-text">&lt;h3>&lt;/h3></code> – Reflects points in regards to the topic.</li> <li><code class="language-text">&lt;h4>&lt;/h4></code> – Supports points from <code class="language-text">&lt;h3></code>.</li> <li><code class="language-text">&lt;h5>&lt;/h5></code> – Not often used, but great for supporting points of <code class="language-text">&lt;h4></code></li> </ul> <h2 id="4-alt-tags-for-images" style="position:relative;"><a href="#4-alt-tags-for-images" aria-label="4 alt tags for images permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4. Alt tags for images</h2> <p>This is often the most important part of an image tag not just for SEO but also for accessibility. Unfortunately, search engines cannot determine what images are showing. That’s when the <code class="language-text">alt</code> tag comes handy.</p> <p>For example:</p> <div class="gatsby-code-button-container" data-toaster-id="46225020499777590000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img src=&quot;cute-puppy.jpg&quot; />`, `46225020499777590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>cute-puppy.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Search engines wouldn’t know whether this image is showing a cute puppy or a cat. So adding <code class="language-text">alt</code> tag would help them understand it and use it for categorisation.</p> <div class="gatsby-code-button-container" data-toaster-id="56309422429166100000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img src=&quot;cute-puppy.jpg&quot; alt=&quot;Such a cute puppy&quot; />`, `56309422429166100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>cute-puppy.jpg<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>Such a cute puppy<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Above tag will correctly help search engines identify what the image is about. This will help to show this image when someone is trying to search for a cute puppy using Google images for example.</p> <h2 id="5-hyperlinks" style="position:relative;"><a href="#5-hyperlinks" aria-label="5 hyperlinks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>5. Hyperlinks</h2> <p>Although it doesn’t look like it, hyperlinks are vital, not only to external content, but also to your own content. To give you an example, when I posted my first of series on web performance on <a href="dev.to">Dev community</a>, I had links to other articles on my site. That resulted in a spike of traffic to my site which was basically helping my natural traffic to go up and also help the search engine link these articles together.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1066px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 64.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQBAgMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAe6k9RNCBf/EABkQAQACAwAAAAAAAAAAAAAAAAECEAMRE//aAAgBAQABBQKTohkelEQr/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAABECIDH/2gAIAQEABj8CZJ5X/8QAGhABAAIDAQAAAAAAAAAAAAAAEQAQASFRof/aAAgBAQABPyFHiMmvK3Mglf/aAAwDAQACAAMAAAAQk8//xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8QTUZ//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8Qp//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESExQVGBkaH/2gAIAQEAAT8QBjQvELcFMcdK8TDBZs9QYMi/rcKNE//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Sharing my article with links" title="" src="/static/62b5c673343759d87225a05f229b7ee9/f8402/htmlshare.jpg" srcset="/static/62b5c673343759d87225a05f229b7ee9/6f81f/htmlshare.jpg 270w, /static/62b5c673343759d87225a05f229b7ee9/09d21/htmlshare.jpg 540w, /static/62b5c673343759d87225a05f229b7ee9/f8402/htmlshare.jpg 1066w" sizes="(max-width: 1066px) 100vw, 1066px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <p>In its core, they are like you’re voting for other content, so use it in your benefit and make sure the linked content is relevant.</p> <div class="gatsby-code-button-container" data-toaster-id="16010758958198590000" data-toaster-class="gatsby-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://dev.to/yashints/pet-projects-the-secret-to-keep-yourself-updated-51e0&quot; > My previous post about pet projects </a>`, `16010758958198590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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://dev.to/yashints/pet-projects-the-secret-to-keep-yourself-updated-51e0<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> My previous post about pet projects <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If for some reason you didn’t want the search engine to make a connection with what you’re linking to, consider using <code class="language-text">rel=nofollow</code>. This tells the search engine to not link your current article with the link destination. In other words, you won’t help improve the domain authority of an external site.</p> <div class="gatsby-code-button-container" data-toaster-id="78279953484876640000" data-toaster-class="gatsby-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://dev.to/yashints/pet-projects-the-secret-to-keep-yourself-updated-51e0&quot; rel=&quot;nofollow&quot; > My previous post about pet projects </a>`, `78279953484876640000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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://dev.to/yashints/pet-projects-the-secret-to-keep-yourself-updated-51e0<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nofollow<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> My previous post about pet projects <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="6-open-graph-tags" style="position:relative;"><a href="#6-open-graph-tags" aria-label="6 open graph tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>6. Open graph tags</h2> <p>These tags are great for showing nicely formatted version of your page on social media. You might have seen it before, but here is how my post appears on LinkedIn 👇🏽:</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: 67.03703703703704%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIEAQP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAG56MEOwf/EABsQAAIBBQAAAAAAAAAAAAAAAAIRAQADEBIT/9oACAEBAAEFArz1HEg45ilX/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGRAAAgMBAAAAAAAAAAAAAAAAECEAAREx/9oACAEBAAY/AleToZ//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhMRBBUXH/2gAIAQEAAT8hoLgO5ftP3gGMhmIVryVn/9oADAMBAAIAAwAAABADD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQACAgMBAAAAAAAAAAAAAAERIQAxEEGhcf/aAAgBAQABPxCcKyjz3DKU24hXEEVJE2Y6TEJpZ8wPqc//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="open graph tags" title="" src="/static/97ab6576fd915e1371c9cbc01b57d569/47311/ndc.jpg" srcset="/static/97ab6576fd915e1371c9cbc01b57d569/6f81f/ndc.jpg 270w, /static/97ab6576fd915e1371c9cbc01b57d569/09d21/ndc.jpg 540w, /static/97ab6576fd915e1371c9cbc01b57d569/47311/ndc.jpg 1080w, /static/97ab6576fd915e1371c9cbc01b57d569/40cc6/ndc.jpg 1119w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <p>Here is an example of an open graph tag:</p> <div class="gatsby-code-button-container" data-toaster-id="97878111621018030000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<meta name=&quot;og:title&quot; property=&quot;og:title&quot; content=&quot;The Title of Your Article&quot; />`, `97878111621018030000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>og:title<span class="token punctuation">"</span></span> <span class="token attr-name">property</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>og:title<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>The Title of Your Article<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now if this article is shared on something like Facebook, the social site will pull the title directly from this tag. As you saw from the tweet I showed above, open graph supports things like descriptions and images as well. It simply gives you customization options if your webpage is shared on social media.</p> <h2 id="7-robots-tag" style="position:relative;"><a href="#7-robots-tag" aria-label="7 robots tag permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>7. Robots Tag</h2> <p>This tag is useful if you want to prevent your page/article from being indexed. These can stop crawlers from sites like Google or Bing from accessing the content. You might now ask why would you want that?</p> <p>Some articles might not be the most influencing for rankings. There are veraity of reasons why you might want this, but let’s say you have an article which lacks quality and you want to get some user’s opinion before it appears on any search engine results.</p> <div class="gatsby-code-button-container" data-toaster-id="5878069902374183000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<meta name=&quot;robots&quot; content=&quot;noindex, nofollow&quot; />`, `5878069902374183000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>robots<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>noindex, nofollow<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h2 id="8-canonical-tags" style="position:relative;"><a href="#8-canonical-tags" aria-label="8 canonical tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>8. Canonical tags</h2> <p>A <a href="https://moz.com/learn/seo/canonicalization" target="_blank" rel="nofollow noopener noreferrer">canonical tag</a> is great for organizing your content and prioritizing one web page over a duplicate web page. Just to give you an example, I always like to post my posts on <a href="https://yashints.dev" target="_blank" rel="nofollow noopener noreferrer">my website</a> first before I post it somewhere else.</p> <p>I do it because of a couple of reasons. The most important one is that the reach might be higher on those platforms like <a href="dev.to">Dev.to</a>. However, I want search engines to know that this post is not a separate one, and in fact it is a copy of what is published on my website first. In other words, it is a way of telling search engines that a specific URL represents the master copy of a page.</p> <p>Another reason why you should use this tag is that search engines might crawl your website using any of these URL forms:</p> <ul> <li><a href="http://www.yashints.dev" target="_blank" rel="nofollow noopener noreferrer">http://www.yashints.dev</a></li> <li><a href="https://www.yashints.dev" target="_blank" rel="nofollow noopener noreferrer">https://www.yashints.dev</a></li> <li><a href="http://yashints.dev" target="_blank" rel="nofollow noopener noreferrer">http://yashints.dev</a></li> <li><a href="http://yashints.dev/index.html" target="_blank" rel="nofollow noopener noreferrer">http://yashints.dev/index.html</a></li> <li><a href="http://yashints.dev/index.html?param=value" target="_blank" rel="nofollow noopener noreferrer">http://yashints.dev/index.html?param=value</a></li> </ul> <p>To a human, all of these URLs represent a single page. To a crawler, though, every single one of these URLs is a unique <code class="language-text">page</code>. Even in this limited example, we can see there are five copies of the homepage in play. In reality, though, this is just a small sample of the variations you might encounter.</p> <div class="gatsby-code-button-container" data-toaster-id="54952734391655465000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<link rel=&quot;canonical&quot; href=&quot;http://yashints.dev/index.html?param=value&quot; />`, `54952734391655465000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>canonical<span class="token punctuation">"</span></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>http://yashints.dev/index.html?param=value<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>So by putting above tag on my home page, I can tell search engines that this URL is representing the same and not a separate page.</p> <p><a href="https://yoast.com/rel-canonical/" target="_blank" rel="nofollow noopener noreferrer">Here is a good article</a> going more deep into canonical tags.</p> <h2 id="9-responsive-site-meta-tags" style="position:relative;"><a href="#9-responsive-site-meta-tags" aria-label="9 responsive site meta tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>9. Responsive site meta tags</h2> <p>Let’s first go through the fact that more than %80 of traffic in China comes through mobile devices. In Australia this number is %56. These numbers show us how important it is to pay attention to responsive design.</p> <p>For the same reason it’s important to let the search engines know that this site has responsive design available. This will ensure that the page is surfaces if a user is searching through a mobile device.</p> <div class="gatsby-code-button-container" data-toaster-id="58861983802871490000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; />`, `58861983802871490000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Above tag is the minimum you will need to let search engines know your site is mobile friendly. It’s important to note that <strong>Google</strong> puts emphasis on websites that are mobile-friendly. And if you don’t have something readily available that people can view from a hand-held device, it will reflect your rankings in search.</p> <h2 id="10-twitter-cards" style="position:relative;"><a href="#10-twitter-cards" aria-label="10 twitter cards permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>10. Twitter cards</h2> <p>Apart from open graph tags, <a href="twitter.com">Twitter</a> has <a href="https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/markup" target="_blank" rel="nofollow noopener noreferrer">its own tags</a>. Now that tweets can exceed historic 140 characters, these cards are a nice extension that allows your tweets to stand out in the crowd of common text.</p> <h3 id="here-are-a-few-of-them" style="position:relative;"><a href="#here-are-a-few-of-them" aria-label="here are a few of them permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Here are a few of them:</h3> <h4 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</h4> <div class="gatsby-code-button-container" data-toaster-id="30114773991602782000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<meta name=&quot;twitter:card&quot; content=&quot;summary&quot; /> <meta name=&quot;twitter:site&quot; content=&quot;@flickr&quot; /> <meta name=&quot;twitter:title&quot; content=&quot;Small Island Developing States Photo Submission&quot; /> <meta name=&quot;twitter:description&quot; content=&quot;View the album on Flickr.&quot; /> <meta name=&quot;twitter:image&quot; content=&quot;https://farm6.staticflickr.com/5510/14338202952_93595258ff_z.jpg&quot; />`, `30114773991602782000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:card<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>summary<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:site<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@flickr<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:title<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Small Island Developing States Photo Submission<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:description<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>View the album on Flickr.<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:image<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://farm6.staticflickr.com/5510/14338202952_93595258ff_z.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Example:</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: 80.37037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAQABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQBAgX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHauLjRAf/EABsQAAIBBQAAAAAAAAAAAAAAAAABAxASISIx/9oACAEBAAEFAnqYoyWO9Ln/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAABEAAREiJR/9oACAEBAAY/ApT1OJ6v/8QAGRABAQEBAQEAAAAAAAAAAAAAAREAIRBR/9oACAEBAAE/IZji1mIeu/PBUzRbIQG//9oADAMBAAIAAwAAABDTD//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ECf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPxBn/8QAGxABAQEAAwEBAAAAAAAAAAAAEQEAITFBUaH/2gAIAQEAAT8QN5oi83VCEKL5g3EInb83DiKTbL+d5uWSLW7/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Twitter card" title="" src="/static/7c234f437192878835a8f86a4386c653/47311/twittercard.jpg" srcset="/static/7c234f437192878835a8f86a4386c653/6f81f/twittercard.jpg 270w, /static/7c234f437192878835a8f86a4386c653/09d21/twittercard.jpg 540w, /static/7c234f437192878835a8f86a4386c653/47311/twittercard.jpg 1080w, /static/7c234f437192878835a8f86a4386c653/e4b8a/twittercard.jpg 1207w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <h4 id="player" style="position:relative;"><a href="#player" aria-label="player permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Player</h4> <div class="gatsby-code-button-container" data-toaster-id="63157230340786240000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<meta name=&quot;twitter:card&quot; content=&quot;player&quot; /> <meta name=&quot;twitter:title&quot; content=&quot;Bison in Yellowstone&quot; /> <meta name=&quot;twitter:site&quot; content=&quot;@BrightcoveLearn&quot; /> <meta name=&quot;twitter:description&quot; content=&quot;Bison walking in Yellowstone National Park.&quot; /> <meta name=&quot;twitter:player&quot; content=&quot;https://solutions.brightcove.com/bcls/twittercards/bison.html&quot; /> <meta name=&quot;twitter:player:width&quot; content=&quot;360&quot; /> <meta name=&quot;twitter:player:height&quot; content=&quot;200&quot; /> <meta name=&quot;twitter:image&quot; content=&quot;https://solutions.brightcove.com/bcls/twittercards/bison.jpg&quot; />`, `63157230340786240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:card<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>player<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:title<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Bison in Yellowstone<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:site<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@BrightcoveLearn<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:description<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Bison walking in Yellowstone National Park.<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:player<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://solutions.brightcove.com/bcls/twittercards/bison.html<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:player:width<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>360<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:player:height<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<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>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:image<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://solutions.brightcove.com/bcls/twittercards/bison.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Example:</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: 38.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQC/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABuvDQP//EABcQAQADAAAAAAAAAAAAAAAAAAEDEBT/2gAIAQEAAQUCGTRX/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAARIQEXL/2gAIAQEABj8CWimZ/8QAGhAAAgIDAAAAAAAAAAAAAAAAADEBIUFRYf/aAAgBAQABPyGMqrBbL4Qf/9oADAMBAAIAAwAAABCAD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABsQAQACAgMAAAAAAAAAAAAAAAEAIRExQVGR/9oACAEBAAE/EE5JESDApv3A4HqBC5//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Twitter player card" title="" src="/static/3aa47f126fab179a7c066a24da93a5c1/47311/video.jpg" srcset="/static/3aa47f126fab179a7c066a24da93a5c1/6f81f/video.jpg 270w, /static/3aa47f126fab179a7c066a24da93a5c1/09d21/video.jpg 540w, /static/3aa47f126fab179a7c066a24da93a5c1/47311/video.jpg 1080w, /static/3aa47f126fab179a7c066a24da93a5c1/62f39/video.jpg 1202w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <p>For more info on these tags, visit their <a href="https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/markup" target="_blank" rel="nofollow noopener noreferrer">official documentation</a>.</p> <h2 id="so-no-keyword-tags" style="position:relative;"><a href="#so-no-keyword-tags" aria-label="so no keyword tags permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 no keyword tags?</h2> <p>You might wondering why I didn’t mention keyword tags. That’s because most search engines like Google use content to categorise the page. So having them doesn’t add any value that much and in fact to many of them just adds extra weight to your pages.</p> <h2 id="summary-1" style="position:relative;"><a href="#summary-1" aria-label="summary 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>You now know 10 tips to improve your SEO organically and save some money. So head to a bar or coffee shop and spend it responsibly 😉.</p> <p>Another tip I forgot to mention was around people who use a SPA framework. If you want to have SEO for your site, you will need to define some critical paths (i.e. homepage) and create a server side rendered of that page which gets replaced by the normal route on client side. This way crawlers would be able to index your statically generated file while your end users still have the benefit of fast interactions on client side.</p> <p>Till next post 👋🏼.</p><![CDATA[A world without passwords]]>https://yashints.dev/blog/2019/06/05/webauthnhttps://yashints.dev/blog/2019/06/05/webauthnWed, 05 Jun 2019 00:00:00 GMT<p>Let’s face the reality, we can’t live without passwords these days. In fact our entire online life is depending on them. But with passwords, comes heaps of problems not only for users, but also for us developers.</p> <!--more--> <h1 id="a-bitter-fact" style="position:relative;"><a href="#a-bitter-fact" aria-label="a bitter fact permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>A bitter fact</h1> <p>Most people have a weak password (and probably the same) used for many websites they’re member of. Social media, email, productivity tools, you name it, they all have different policies around passwords and majority of users find a way to bypass it using a weak password, or a strong one written on a post it 🤷🏽‍♂️.</p> <p>In fact 81% of all data breaches that happen due to hacking, <a href="https://www.verizonenterprise.com/resources/reports/2017_dbir_en_xg.pdf" target="_blank" rel="nofollow noopener noreferrer">leverage stolen or weak passwords</a>.</p> <h1 id="there-is-a-better-way" style="position:relative;"><a href="#there-is-a-better-way" aria-label="there is a better way permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>There is a better way</h1> <p>But thanks to great efforts from <a href="https://www.w3.org/" target="_blank" rel="nofollow noopener noreferrer">W3C</a> and <a href="https://fidoalliance.org" target="_blank" rel="nofollow noopener noreferrer">FIDO</a>, we’re not bound to use passwords for everything. Web Authentication API, aka <code class="language-text">WebAuthn</code> is a fairly <a href="https://w3c.github.io/webauthn/" target="_blank" rel="nofollow noopener noreferrer">new specification</a> which is introducing a new way of authentication without passwords, and also alongside them.</p> <p>Google, Microsoft, Yubico and other big names in the industry are all part of the contributors to get this spec widespread. This API allows servers to register and authenticate users using public key cryptography instead of passwords.</p> <p>Windows Hello, Apple’s Touch ID, Yubikey devices, are all examples of a different type of authentication mechanism which doesn’t require passwords. They use biometrics or hardware devices to be able to achieve this.</p> <h1 id="how-it-works" style="position:relative;"><a href="#how-it-works" aria-label="how it works permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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</h1> <p>From 1000ft, instead of using a password, you will use a <a href="https://en.wikipedia.org/wiki/Public-key_cryptography" target="_blank" rel="nofollow noopener noreferrer">key pair (public and private)</a> which is generated for a website.</p> <p>The private key is stored securely on user’s device, whereas the public key along with a randomly generated credential ID is sent to a web server to be stored and used later for authenticating that particular user.</p> <p>Overall, WebAuthn relies on three major parties:</p> <ul> <li>Authenticator (the device which is doing the authentication and verification)</li> <li>Relying party (the web application owner)</li> <li>Browser’s Web Authentication API</li> </ul> <p>The flow is fairly simple, first step is registration, then it would be authentication.</p> <h2 id="registration-a-credential" style="position:relative;"><a href="#registration-a-credential" aria-label="registration a credential permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Registration a credential</h2> <p>Same as password authentication flows where the web server usually provides a form for user to enter their password which is sent back to the server for verification.</p> <p>With WebAuthn, it’s fairly similar, but instead of asking for a password, the relying party asks for a public key.</p> <table> <thead> <tr> <th align="center"><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 368px; " > <a class="gatsby-resp-image-link" href="/static/124aae1c593680a7f43623f2843b9cb3/7d8cb/registration.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 94.81481481481482%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAATABQDASIAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAAAAECAwQF/8QAFwEAAwEAAAAAAAAAAAAAAAAAAAEDAv/aAAwDAQACEAMQAAAB7MKudwzFYg9gU1//xAAZEAACAwEAAAAAAAAAAAAAAAAAAQISMRH/2gAIAQEAAQUCt0syrZPSz7HBZ//EABcRAAMBAAAAAAAAAAAAAAAAAAAQESH/2gAIAQMBAT8Bpj//xAAYEQACAwAAAAAAAAAAAAAAAAAAARARIf/aAAgBAgEBPwGmbP8A/8QAHRAAAQMFAQAAAAAAAAAAAAAAABExQQEQIXGhsf/aAAgBAQAGPwLHg/BVJJGK7v8A/8QAHRAAAgEEAwAAAAAAAAAAAAAAAAERMUFRYYGR8f/aAAgBAQABPyGs2aScDYMx3DxEaLnK0XJyI2+ymf/aAAwDAQACAAMAAAAQYN+D/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAEQETH/2gAIAQMBAT8QbXNYf//EABgRAAMBAQAAAAAAAAAAAAAAAAABMRGh/9oACAECAQE/EFheCCFD/8QAHhABAQEAAgEFAAAAAAAAAAAAAREAIUExUWHR4fH/2gAIAQEAAT8QvmUA23fsNAGDoI8YUnp68aEDxt7wBUKDHnUu+Xtp+384wPbf/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Registration using WebAuthn" title="" src="/static/124aae1c593680a7f43623f2843b9cb3/7d8cb/registration.jpg" srcset="/static/124aae1c593680a7f43623f2843b9cb3/6f81f/registration.jpg 270w, /static/124aae1c593680a7f43623f2843b9cb3/7d8cb/registration.jpg 368w" sizes="(max-width: 368px) 100vw, 368px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></th> </tr> </thead> <tbody> <tr> <td align="center"><em>Image from WebAuthn.io</em></td> </tr> </tbody> </table> <p>When prompting the user for a credential, the <code class="language-text">navigator.credentials.create()</code> is used:</p> <div class="gatsby-code-button-container" data-toaster-id="59681143243123330000" data-toaster-class="gatsby-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 credential = await navigator.credentials.create( { publicKey: publicKeyCredentialCreationOptions, } )`, `59681143243123330000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> credential <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>credentials<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> publicKey<span class="token operator">:</span> publicKeyCredentialCreationOptions<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In case you’re wondering what does the <code class="language-text">publicKeyCredentialCreationOptions</code> looks like, it contains a bunch of mandatory and optional fields:</p> <div class="gatsby-code-button-container" data-toaster-id="48313745169784170000" data-toaster-class="gatsby-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 publicKeyCredentialCreationOptions = { challenge: Uint8Array.from( randomStringFromServer, c => c.charCodeAt(0) ), rp: { name: 'Google', id: 'accounts.google.com', }, user: { id: Uint8Array.from('5T9AFCUZSL8', c => c.charCodeAt(0) ), name: 'me@yashints.dev', displayName: 'Yaser', }, pubKeyCredParams: [ { alg: -7, type: 'public-key' }, ], authenticatorSelection: { authenticatorAttachment: 'cross-platform', }, timeout: 60000, attestation: 'direct', }`, `48313745169784170000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> publicKeyCredentialCreationOptions <span class="token operator">=</span> <span class="token punctuation">{</span> challenge<span class="token operator">:</span> Uint8Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span> randomStringFromServer<span class="token punctuation">,</span> c <span class="token operator">=></span> c<span class="token punctuation">.</span><span class="token function">charCodeAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> rp<span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'Google'</span><span class="token punctuation">,</span> id<span class="token operator">:</span> <span class="token string">'accounts.google.com'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> user<span class="token operator">:</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> Uint8Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">'5T9AFCUZSL8'</span><span class="token punctuation">,</span> c <span class="token operator">=></span> c<span class="token punctuation">.</span><span class="token function">charCodeAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">'me@yashints.dev'</span><span class="token punctuation">,</span> displayName<span class="token operator">:</span> <span class="token string">'Yaser'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> pubKeyCredParams<span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> alg<span class="token operator">:</span> <span class="token operator">-</span><span class="token number">7</span><span class="token punctuation">,</span> type<span class="token operator">:</span> <span class="token string">'public-key'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> authenticatorSelection<span class="token operator">:</span> <span class="token punctuation">{</span> authenticatorAttachment<span class="token operator">:</span> <span class="token string">'cross-platform'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> timeout<span class="token operator">:</span> <span class="token number">60000</span><span class="token punctuation">,</span> attestation<span class="token operator">:</span> <span class="token string">'direct'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><code class="language-text">challenge</code>: The most important part in the options is the challenge. It is a randomly generated bytes on the server which is used to prevent reply attacks.</p> <p><code class="language-text">rp</code>: Which stands for relying party, is the web server which user is trying to register to.</p> <p><code class="language-text">user</code>: This is the end user who is registering to a service. The <code class="language-text">id</code> is used to associate the public key to that user, but is suggested not be a personally identifying information.</p> <p><code class="language-text">pubKeyCredPrams</code>: Specifies which types of public key are acceptable by the server.</p> <p><code class="language-text">authenticatorSelection</code>: Is an optional field which helps relying parties to put further restrictions on authenticators allowed for registration. The possible values (<code class="language-text">platform</code> like Windows Hello, or <code class="language-text">cross-platform</code> like Yubikey) can be found <a href="https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-authenticatorselection" target="_blank" rel="nofollow noopener noreferrer">on the spec</a>.</p> <p><code class="language-text">timeout</code>: The time in millisecond that the user has to respond to the registration prompt.</p> <p><code class="language-text">attestation</code>: This is returned from the authenticator and contains information that can used to track the user. It indicates how important the attestation is to this registration event. For example, if <code class="language-text">none</code> is used, it means server doesn’t care about it. <code class="language-text">indirect</code> means server will allow for anonymised attestation data. <code class="language-text">direct</code> means that server requires the data from authenticator. In general this is regarding privacy of users when registration is happening.</p> <p>The object which is returned from the <code class="language-text">create()</code> call, contains a public key and other attributes which are used to validate the user:</p> <div class="gatsby-code-button-container" data-toaster-id="33035298807264678000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`console.log(credential); PublicKeyCredential { id: 'ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...', rawId: ArrayBuffer(59), response: AuthenticatorAttestationResponse { clientDataJSON: ArrayBuffer(121), attestationObject: ArrayBuffer(306), }, type: 'public-key' }`, `33035298807264678000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>credential<span class="token punctuation">)</span><span class="token punctuation">;</span> PublicKeyCredential <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token string">'ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...'</span><span class="token punctuation">,</span> rawId<span class="token operator">:</span> <span class="token function">ArrayBuffer</span><span class="token punctuation">(</span><span class="token number">59</span><span class="token punctuation">)</span><span class="token punctuation">,</span> response<span class="token operator">:</span> AuthenticatorAttestationResponse <span class="token punctuation">{</span> clientDataJSON<span class="token operator">:</span> <span class="token function">ArrayBuffer</span><span class="token punctuation">(</span><span class="token number">121</span><span class="token punctuation">)</span><span class="token punctuation">,</span> attestationObject<span class="token operator">:</span> <span class="token function">ArrayBuffer</span><span class="token punctuation">(</span><span class="token number">306</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> type<span class="token operator">:</span> <span class="token string">'public-key'</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="verifying-the-registration-data-by-relying-party" style="position:relative;"><a href="#verifying-the-registration-data-by-relying-party" aria-label="verifying the registration data by relying party permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Verifying the registration data by relying party</h2> <p>Once the public key is received along with other properties of registration data to the server, <a href="https://w3c.github.io/webauthn/#registering-a-new-credential" target="_blank" rel="nofollow noopener noreferrer">there is a procedure</a> to validate this data.</p> <p>Of course the implementation depends on what language you’re using, but, there are some examples out there if you want to have an idea how to implement these steps. Duo Labs has provided full implementation in <a href="https://github.com/duo-labs/webauthn" target="_blank" rel="nofollow noopener noreferrer">Go</a> and <a href="https://github.com/duo-labs/py_webauthn" target="_blank" rel="nofollow noopener noreferrer">Python</a>.</p> <h2 id="authenticating-with-webauthn" style="position:relative;"><a href="#authenticating-with-webauthn" aria-label="authenticating with webauthn permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Authenticating with WebAuthn</h2> <p>After completing the registration, the user is able to be to authenticate to the site. During registration user has obtained an assertion which indicates they have the private key. This contains a signature using the mentioned private key. Web server uses the public key during registration to verify this.</p> <p>The authentication flow looks something like this:</p> <table> <thead> <tr> <th align="center"><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 352px; " > <a class="gatsby-resp-image-link" href="/static/ce5d7c2c1ccf85c8876d19bd52b9d5f7/e5a29/auth.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 143.33333333333334%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAdABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAgADBf/EABYBAQEBAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQAAAB7JRM3Oqs89TmOdb/AP/EABoQAAIDAQEAAAAAAAAAAAAAAAABAhESMQP/2gAIAQEAAQUCcjQkT6Wj0EZQ4soXP//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPwFsJLC//8QAGBEBAQADAAAAAAAAAAAAAAAAABEBISL/2gAIAQIBAT8B6bXKv//EABsQAAIBBQAAAAAAAAAAAAAAAAAxEQEQICEy/9oACAEBAAY/AtVGTIhY9Dt//8QAHBABAAMBAAMBAAAAAAAAAAAAAQARIUExUXGR/9oACAEBAAE/IT+LTkL9fkVvpstQA9gPTAShMlClv5cRmMG3d2aNa3L+88E//9oADAMBAAIAAwAAABDswY//xAAZEQACAwEAAAAAAAAAAAAAAAAAARARIVH/2gAIAQMBAT8QbYLGLkf/xAAYEQADAQEAAAAAAAAAAAAAAAAAAREhQf/aAAgBAgEBPxCcQoaXgmh//8QAHRABAQADAAIDAAAAAAAAAAAAAREAITEQQVFhgf/aAAgBAQABPxDffUBUcfS34Mijjj6wQM617xUJHunIKjSXmCid1EGaYOvbcMbp1vAGzpU4fB4UoS1Duf/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Authentication process" title="" src="/static/ce5d7c2c1ccf85c8876d19bd52b9d5f7/e5a29/auth.jpg" srcset="/static/ce5d7c2c1ccf85c8876d19bd52b9d5f7/6f81f/auth.jpg 270w, /static/ce5d7c2c1ccf85c8876d19bd52b9d5f7/e5a29/auth.jpg 352w" sizes="(max-width: 352px) 100vw, 352px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></th> </tr> </thead> <tbody> <tr> <td align="center"><em>Image from WebAuthn.io</em></td> </tr> </tbody> </table> <p>The <code class="language-text">navigator.credentials.get()</code> method is called to generate an assertion to prove the user own the private key. This will retrieve the credential generated during registration with a signature included.</p> <div class="gatsby-code-button-container" data-toaster-id="3227319172583365000" data-toaster-class="gatsby-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 credential = await navigator.credentials.get( { publicKey: publicKeyCredentialRequestOptions, } )`, `3227319172583365000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> credential <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>credentials<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> publicKey<span class="token operator">:</span> publicKeyCredentialRequestOptions<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The <code class="language-text">publicKeyCredentialRequestOptions</code> object contains a number of mandatory and optional properties which is specified by the server:</p> <div class="gatsby-code-button-container" data-toaster-id="44957890351128830000" data-toaster-class="gatsby-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 publicKeyCredentialRequestOptions = { challenge: Uint8Array.from( randomStringFromServer, c => c.charCodeAt(0) ), allowCredentials: [ { id: Uint8Array.from(credentialId, c => c.charCodeAt(0) ), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }, ], timeout: 60000, }`, `44957890351128830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> publicKeyCredentialRequestOptions <span class="token operator">=</span> <span class="token punctuation">{</span> challenge<span class="token operator">:</span> Uint8Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span> randomStringFromServer<span class="token punctuation">,</span> c <span class="token operator">=></span> c<span class="token punctuation">.</span><span class="token function">charCodeAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> allowCredentials<span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> Uint8Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>credentialId<span class="token punctuation">,</span> c <span class="token operator">=></span> c<span class="token punctuation">.</span><span class="token function">charCodeAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> type<span class="token operator">:</span> <span class="token string">'public-key'</span><span class="token punctuation">,</span> transports<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'usb'</span><span class="token punctuation">,</span> <span class="token string">'ble'</span><span class="token punctuation">,</span> <span class="token string">'nfc'</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> timeout<span class="token operator">:</span> <span class="token number">60000</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The most interesting part in this object is the transport property. The server can optionally indicate what transports it prefers, like USB, NFC, and Bluetooth.</p> <p>The returned object is a <code class="language-text">PublicKeyCredential</code> object, but slightly different from the previous one from registration.</p> <div class="gatsby-code-button-container" data-toaster-id="62212310922015780000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`console.log(assertion); PublicKeyCredential { id: 'SSX9lKQmbqdGtbcHDTBsvpu4sjseh4cg2TxSvr4ADSUlN...', rawId: ArrayBuffer(59), response: AuthenticatorAssertionResponse { authenticatorData: ArrayBuffer(191), clientDataJSON: ArrayBuffer(118), signature: ArrayBuffer(70), userHandle: ArrayBuffer(10), }, type: 'public-key' }`, `62212310922015780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>assertion<span class="token punctuation">)</span><span class="token punctuation">;</span> PublicKeyCredential <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token string">'SSX9lKQmbqdGtbcHDTBsvpu4sjseh4cg2TxSvr4ADSUlN...'</span><span class="token punctuation">,</span> rawId<span class="token operator">:</span> <span class="token function">ArrayBuffer</span><span class="token punctuation">(</span><span class="token number">59</span><span class="token punctuation">)</span><span class="token punctuation">,</span> response<span class="token operator">:</span> AuthenticatorAssertionResponse <span class="token punctuation">{</span> authenticatorData<span class="token operator">:</span> <span class="token function">ArrayBuffer</span><span class="token punctuation">(</span><span class="token number">191</span><span class="token punctuation">)</span><span class="token punctuation">,</span> clientDataJSON<span class="token operator">:</span> <span class="token function">ArrayBuffer</span><span class="token punctuation">(</span><span class="token number">118</span><span class="token punctuation">)</span><span class="token punctuation">,</span> signature<span class="token operator">:</span> <span class="token function">ArrayBuffer</span><span class="token punctuation">(</span><span class="token number">70</span><span class="token punctuation">)</span><span class="token punctuation">,</span> userHandle<span class="token operator">:</span> <span class="token function">ArrayBuffer</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 punctuation">,</span> type<span class="token operator">:</span> <span class="token string">'public-key'</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For more info around this object <a href="https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-userhandle" target="_blank" rel="nofollow noopener noreferrer">refer to spec</a>.</p> <h3 id="validating-authentication-data" style="position:relative;"><a href="#validating-authentication-data" aria-label="validating authentication data permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Validating authentication data</h3> <p>After the assertion is acquired, it is sent to server for verification. After being validated, the signature is verified with the stored public key.</p> <div class="gatsby-code-button-container" data-toaster-id="53115396745338675000" data-toaster-class="gatsby-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 storedCredential = await getCredentialFromDatabase( userHandle, credentialId ) const signedData = authenticatorDataBytes + hashedClientDataJSON const signatureIsValid = storedCredential.publicKey.verify( signature, signedData ) if (signatureIsValid) { return 'Hooray! User is authenticated! 🎉' } else { return 'Verification failed. 😭' }`, `53115396745338675000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> storedCredential <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getCredentialFromDatabase</span><span class="token punctuation">(</span> userHandle<span class="token punctuation">,</span> credentialId <span class="token punctuation">)</span> <span class="token keyword">const</span> signedData <span class="token operator">=</span> authenticatorDataBytes <span class="token operator">+</span> hashedClientDataJSON <span class="token keyword">const</span> signatureIsValid <span class="token operator">=</span> storedCredential<span class="token punctuation">.</span>publicKey<span class="token punctuation">.</span><span class="token function">verify</span><span class="token punctuation">(</span> signature<span class="token punctuation">,</span> signedData <span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>signatureIsValid<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'Hooray! User is authenticated! 🎉'</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 string">'Verification failed. 😭'</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h1 id="further-reading-and-resources" style="position:relative;"><a href="#further-reading-and-resources" aria-label="further reading and resources permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Further reading and resources</h1> <p>Following resources are a good starting point for any further reading:</p> <ul> <li><a href="https://webauthn.io" target="_blank" rel="nofollow noopener noreferrer">Webauthn.io</a>: Due Labs has created this useful resource which contains all the source code and sample use cases with beautiful illustrations.</li> <li><a href="https://duo.com/blog/developments-to-webauthn-and-the-fido2-framework" target="_blank" rel="nofollow noopener noreferrer">Developments to WebAuthn and the FIDO2 Framework</a>: An informative blog post which goes through some of the progress and shows the compatibility of each major browser and contributors to this area.</li> <li><a href="https://github.com/duo-labs/webauthn.io" target="_blank" rel="nofollow noopener noreferrer">Source Code</a>: This GitHub repo contains all the source code Due Labs have created to demonstrate the capability.</li> <li>A Big Day for the Internet: <a href="https://www.yubico.com/2019/03/w3c-standardizes-webauthn/" target="_blank" rel="nofollow noopener noreferrer">W3C Standardizes WebAuthn</a></li> <li><a href="https://demo.yubico.com/webauthn" target="_blank" rel="nofollow noopener noreferrer">Demo site by Yubico</a>: Demonstrates the process in the end user perspective</li> </ul> <h1 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</h1> <p>We saw how simple and straight forward is to implement this amazing feature and I highly recommend if you’re working on a green field project definitely consider having this implemented and give users ability to live passwordless 🔥👊🏻. For the current products, this can be a turning point to gain more users into system by simplifying the most important part of their flow 😊.</p><![CDATA[What`s new in Angular 8]]>https://yashints.dev/blog/2019/05/30/angular-8-featureshttps://yashints.dev/blog/2019/05/30/angular-8-featuresThu, 30 May 2019 00:00:00 GMT<p>You might already know that <a href="https://angular.io" target="_blank" rel="nofollow noopener noreferrer">Angular</a> 8 is out now, but what it means for you or your organisation is described below.</p> <!--more--> <h1 id="ivy" style="position:relative;"><a href="#ivy" aria-label="ivy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Ivy</h1> <p>To put your mind at rest, Ivy is not here <strong>yet</strong>. If you don’t know what is Ivy, it’s the Angular’s new renderer which promises a ton of improvements in term of how Angular renders the view. It is radically different from anything we have seen in mainstream frameworks, because it uses incremental <code class="language-text">DOM</code>. Stay tuned for more news on this in coming weeks.</p> <h1 id="differential-loading" style="position:relative;"><a href="#differential-loading" aria-label="differential loading permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Differential loading</h1> <p>Differential loading is a feature in which browser decides to use modern vs legacy JavaScript based on its own capabilities.</p> <p>This is really important not just because we can use modern JavaScript but because we can get rid of all of those polyfills we’ve had to ship with our applications previously.</p> <p>In short it takes advantage of the <code class="language-text">es2015</code> flag in the TypeScript config and creates two bundles one for modern browsers and one for older ones.</p> <div class="gatsby-code-button-container" data-toaster-id="86081203552618120000" data-toaster-class="gatsby-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;compilerOptions&quot;: { … &quot;module&quot;: &quot;esnext&quot;, &quot;moduleResolution&quot;: &quot;node&quot;, … &quot;target&quot;: &quot;es2015&quot;, … },`, `86081203552618120000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"compilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span> … <span class="token property">"module"</span><span class="token operator">:</span> <span class="token string">"esnext"</span><span class="token punctuation">,</span> <span class="token property">"moduleResolution"</span><span class="token operator">:</span> <span class="token string">"node"</span><span class="token punctuation">,</span> … <span class="token property">"target"</span><span class="token operator">:</span> <span class="token string">"es2015"</span><span class="token punctuation">,</span> … <span class="token punctuation">}</span><span class="token punctuation">,</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>At runtime, Angular generates two script tags in your HTML:</p> <div class="gatsby-code-button-container" data-toaster-id="27803917545526580000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script type=&quot;module&quot; src=&quot;…&quot;> // Modern JS <script nomodule src=&quot;…&quot;> // Legacy JS`, `27803917545526580000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>module<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>…<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> // Modern JS <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">nomodule</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>…<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> // Legacy JS</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Browsers that can handle modern JavaScript will load the first bundle and ignores the second whereas the older ones ignore the first and load the first one.</p> <p>This will give you some massive reduction in bundle size when the application is more than a hello world 😉.</p> <h1 id="dynamic-imports-in-route-configurations" style="position:relative;"><a href="#dynamic-imports-in-route-configurations" aria-label="dynamic imports in route configurations permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Dynamic imports in route configurations</h1> <p>Angular team have now changed the way you used to lazy load child modules in route configuration. Previously you had:</p> <div class="gatsby-code-button-container" data-toaster-id="43465077328203325000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{path: '/about', loadChildren: './about/about.module#AboutModule'}`, `43465077328203325000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token punctuation">{</span>path<span class="token operator">:</span> <span class="token string">'/about'</span><span class="token punctuation">,</span> loadChildren<span class="token operator">:</span> <span class="token string">'./about/about.module#AboutModule'</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>With the new syntax, it leverages the dynamic import which is a huge advantage over the old syntax:</p> <div class="gatsby-code-button-container" data-toaster-id="47459927997184200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{path: \`/about\`, loadChildren: () => import(\`./about/about.module\`).then(m => m.AboutModule)}`, `47459927997184200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token punctuation">{</span>path<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/about</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token function-variable function">loadChildren</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">./about/about.module</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>m <span class="token operator">=></span> m<span class="token punctuation">.</span>AboutModule<span class="token punctuation">)</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Why is this better I hear you ask. The main reason is that you can get errors during development from your editor. If you misspelled the module name or the file name previously, it wouldn’t throw error until you trued to bundle the app because it was just a string.</p> <p>Now you get squiggly lines under file name or module name if you make a mistake.</p> <h1 id="builders" style="position:relative;"><a href="#builders" aria-label="builders permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Builders</h1> <p>You might know that you can tap into CLI commands like <code class="language-text">ng new</code>, <code class="language-text">ng generate</code>, <code class="language-text">ng add</code>, and <code class="language-text">ng update</code> using Schematics. Angular team now allow you to tap into more commands using the new builders for CLI like <code class="language-text">ng build</code>, <code class="language-text">ng test, and</code>ng run`.</p> <p>What this allowed the team to achieve is huge because now you can run your custom build or test flows. One of the good examples is the new version of <a href="https://github.com/angular/angularfire2" target="_blank" rel="nofollow noopener noreferrer">AngularFire</a> which adds a <code class="language-text">deploy</code> command to make the build and deploy seamless when working on a project which uses Firebase for deployment. As if, you can now run:</p> <div class="gatsby-code-button-container" data-toaster-id="32121291943095366000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng run hellow-world:deploy`, `32121291943095366000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng run hellow-world:deploy</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This command will both build the project and deploys it to Firebase, how good is this?</p> <h1 id="workspace-apis" style="position:relative;"><a href="#workspace-apis" aria-label="workspace apis permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Workspace APIs</h1> <p>Up until now, you had to manually open your <code class="language-text">angular.json</code> and modify it to make changes to workspace config. With this new API you can now read and modify these configurations much more conveniently. <a href="https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/core/README.md#workspaces" target="_blank" rel="nofollow noopener noreferrer">Read more here</a>.</p> <h1 id="web-worker-support" style="position:relative;"><a href="#web-worker-support" aria-label="web worker support permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Web Worker Support</h1> <p>Web workers are great for adding support to offload a heavy operation in a different thread and speed up your application’s performance. Imagine image or video manipulation, or finding the optimum path between two points on a map and how they can impact the application’s speed.</p> <p>Now you can add a web worker easily by running:</p> <div class="gatsby-code-button-container" data-toaster-id="16156435110322030000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng generate webWorker awesome-worker`, `16156435110322030000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng generate webWorker awesome-worker</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once finished you will have a web worker and you can use it in your application. The CLI will take care of the bundling for you, so all you need to do, is leverage the power it brings to you:</p> <div class="gatsby-code-button-container" data-toaster-id="46409035365257380000" data-toaster-class="gatsby-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 worker = new Worker( \`./awesome-worker.worker\`, { type: \`module\` } )`, `46409035365257380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> worker <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Worker</span><span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">./awesome-worker.worker</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">module</span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span> <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>To make this even more interesting, CLI will also correctly handle the code splitting and bundling.</p> <p>In your worker file which is located in <code class="language-text">src/app/awesome.worker.ts</code>, you will have a scaffolded method to receive a message from your application as a starter which you can expand however you like:</p> <div class="gatsby-code-button-container" data-toaster-id="58836743657224380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`addEventListener('message', ({ data }) => { const response = \`worker response to \${data}\` postMessage(response) })`, `58836743657224380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'message'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> data <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">worker response to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token function">postMessage</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>In your <code class="language-text">app.component.ts</code> you can then interact with the worker and send a message:</p> <div class="gatsby-code-button-container" data-toaster-id="89020574265562050000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if (typeof Worker !== 'undefined') { // Create a new const worker = new Worker('./awesome.worker', { type: 'module', }) worker.onmessage = ({ data }) => { console.log('page got message: \${data}') } worker.postMessage('hello') } else { // Web Workers are not supported in this environment. // You should add a fallback so that your program still executes correctly. }`, `89020574265562050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> Worker <span class="token operator">!==</span> <span class="token string">'undefined'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Create a new</span> <span class="token class-name"><span class="token keyword">const</span></span> worker <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Worker</span><span class="token punctuation">(</span><span class="token string">'./awesome.worker'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">'module'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> worker<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> data <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'page got message: ${data}'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> worker<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// Web Workers are not supported in this environment.</span> <span class="token comment">// You should add a fallback so that your program still executes correctly.</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h1 id="angularjs-migration" style="position:relative;"><a href="#angularjs-migration" aria-label="angularjs migration permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>AngularJS migration</h1> <p>If you were using <code class="language-text">$location</code> service in your AngularJS application, now you will get <code class="language-text">LocationUpgradeModule</code> which puts the responsibilities of <code class="language-text">$location</code> service to <code class="language-text">Location</code> service in Angular.</p> <p>This means if you’re use <code class="language-text">ngUpgrade</code>, your life is a bit easier having routes in both AngularJS and Angular apps.</p> <p>Documentation around best practices for lazy loading parts of AngularJS app into your Angular app is also happened in this version which gives you insight on how to upgrade most used features first, and only load AngularJS for the remaining subset.</p> <p>Read more around the <a href="https://v8.angular.io/guide/upgrade#create-a-service-to-lazy-load-angularjs" target="_blank" rel="nofollow noopener noreferrer">best practices here</a>.</p> <h1 id="new-guide-around-deprecated-features" style="position:relative;"><a href="#new-guide-around-deprecated-features" aria-label="new guide around deprecated 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>New guide around deprecated features</h1> <p>They also release a new guide around deprecations and removals. They claimed they are committed to support features in <code class="language-text">N + 2</code> in major releases. For example if you’re using a deprecated feature in Angular 7, it will be available in 8 and 9, but not 10.</p> <p>One of the features which is now deprecated in 8 is <code class="language-text">platform-webworker</code>. To find out about all deprecated and removals check out <a href="https://v8.angular.io/guide/deprecations" target="_blank" rel="nofollow noopener noreferrer">their deprecation guide</a>.</p> <h1 id="breaking-changes" style="position:relative;"><a href="#breaking-changes" aria-label="breaking changes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Breaking changes</h1> <p>This version came with some breaking changes. The most important one is that <code class="language-text">@bazel/typescript</code> is now a <code class="language-text">peerDependency</code> of <code class="language-text">@angular/bazel</code> so its users must add <code class="language-text">@bazel/typescript</code> to their <code class="language-text">package.json</code>.</p> <p>From core perspective, it’s now required that all <code class="language-text">@ViewChild</code> and <code class="language-text">@ContentChild</code> queries have a <em>static</em> flag specifying whether the query is <em>static</em> or <em>dynamic</em>. The compiler previously sorted queries automatically, but in 8.0 developers are required to explicitly specify which behaviour they have in mind. This is a temporary requirement as part of a migration; see <a href="https://v8.angular.io/guide/static-query-migration" target="_blank" rel="nofollow noopener noreferrer">https://v8.angular.io/guide/static-query-migration</a> for more details.</p> <p>To read more refer to <a href="https://github.com/angular/angular/blob/master/CHANGELOG.md" target="_blank" rel="nofollow noopener noreferrer">their change log</a>.</p> <h1 id="how-to-update" style="position:relative;"><a href="#how-to-update" aria-label="how to update permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 to update</h1> <p>Simply run this command from your terminal and have fun exploring these new hot features.</p> <div class="gatsby-code-button-container" data-toaster-id="47445333565386980000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng update @angular/cli @angular/core`, `47445333565386980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng update @angular/cli @angular/core</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The rest is taken care of by the CLI.</p><![CDATA[Write faster JavaScript]]>https://yashints.dev/blog/2019/05/20/write-faster-jshttps://yashints.dev/blog/2019/05/20/write-faster-jsMon, 20 May 2019 00:00:00 GMT<p>Most of the times, we write code which is being copy pasted from all over internet. <a href="https://stackoverflow.com/" target="_blank" rel="nofollow noopener noreferrer">StackOverflow</a> is the main source these days for finding solutions to all sort of problems. But is it OK to blindly copy paste code without really knowing what’s happening behind the scenes?</p> <!--more--> <h1 id="a-bit-of-context" style="position:relative;"><a href="#a-bit-of-context" aria-label="a bit of 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>A bit of context</h1> <p>Don’t get me wrong when I say <strong>StackOverflow</strong> should not be used blindly. It’s a great source of information for most of the day to day issues and bugs developers face all around the world. It’s just that we should be a bit more proactive and decide the best way out of all the available options out there.</p> <p>Let me show you some examples where a piece of code can be written in multiple ways, and the most obvious choice is not necessarily the best one.</p> <h2 id="chaining-array-loop-chaining" style="position:relative;"><a href="#chaining-array-loop-chaining" aria-label="chaining array loop chaining permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chaining array loop chaining</h2> <p>Let’s assume we have an array with <code class="language-text">200,000</code> objects which include name and age properties. We want to have the name of all people under age of 22 (assume we have <code class="language-text">100,000</code> of them). This the solution most people might use:</p> <div class="gatsby-code-button-container" data-toaster-id="6213752638853353000" data-toaster-class="gatsby-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 under22People = originalList .filter(x => x.age < 22) .map(x => x.name)`, `6213752638853353000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> under22People <span class="token operator">=</span> originalList <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> x<span class="token punctuation">.</span>age <span class="token operator">&lt;</span> <span class="token number">22</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> x<span class="token punctuation">.</span>name<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Since <code class="language-text">ES5</code> and <code class="language-text">ES6</code> were introduced, a nice set of array methods emerged. <code class="language-text">ES6s</code> cleaner syntax makes it painless to chain methods in order to produce our desired results. The problem lies in how we use these nice methods without realising how they’re performed.</p> <p>In the first glance, this looks to be a really nice code, but if we look closer, we have a loop which runs <code class="language-text">200,000</code> times when doing the filtering, and another <code class="language-text">100,000</code> times when selecting the name.</p> <p>This is where we just need to loop through these items once. So let’s have a look at how can we rewrite this code:</p> <div class="gatsby-code-button-container" data-toaster-id="84738177513439300000" data-toaster-class="gatsby-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 under22People = [] originalList.forEach(({ age, name }) => { age >= 18 && under22People.push(name) })`, `84738177513439300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> under22People <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> originalList<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> age<span class="token punctuation">,</span> name <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> age <span class="token operator">>=</span> <span class="token number">18</span> <span class="token operator">&amp;&amp;</span> under22People<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Now this code runs only <code class="language-text">200,000</code> times. It doesn’t look as nice as the chained methods, but it sure has much better performance.</p> <p>You can even use the <code class="language-text">reduce</code> method to do the same:</p> <div class="gatsby-code-button-container" data-toaster-id="17377435950436305000" data-toaster-class="gatsby-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 under22People = originalList.reduce( (acc, { age, name }) => { return age >= 18 ? [...ac, name] : acc }, [] )`, `17377435950436305000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> under22People <span class="token operator">=</span> originalList<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> <span class="token punctuation">{</span> age<span class="token punctuation">,</span> name <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> age <span class="token operator">>=</span> <span class="token number">18</span> <span class="token operator">?</span> <span class="token punctuation">[</span><span class="token operator">...</span>ac<span class="token punctuation">,</span> name<span class="token punctuation">]</span> <span class="token operator">:</span> acc <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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It sure looks much less readable, but it does the exact same job for us.</p> <h2 id="abusing-arrow-functions" style="position:relative;"><a href="#abusing-arrow-functions" aria-label="abusing arrow 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>Abusing arrow functions</h2> <p>One of the good questions you could ask yourself when writing <code class="language-text">JavaScript</code> is whether you know the difference between a traditional function and an arrow function (aka fat function).</p> <p>From MDN Web Docs:</p> <blockquote> <p>An arrow function expression is a syntactically compact alternative to a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function" target="_blank" rel="nofollow noopener noreferrer">regular function expression</a>, although without its own bindings to the <code class="language-text">this</code>, <code class="language-text">arguments</code>, <code class="language-text">super</code>, or <code class="language-text">new.target</code> keywords. Arrow function expressions are ill suited as methods, and they cannot be used as constructors.</p> </blockquote> <p>Before you ask, no they are not JavaScript equivalent of anonymous functions in languages like <code class="language-text">C#</code>. But for now the only thing you need to care about is that they don’t have scope.</p> <p>Once of the many of their use cases is using them in class field. Consider in <code class="language-text">React</code> you don’t need to manually bind your functions anymore like:</p> <div class="gatsby-code-button-container" data-toaster-id="82008101296893380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`this.handleClick = this.handleClick.bind(this)`, `82008101296893380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">this</span><span class="token punctuation">.</span>handleClick <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">handleClick</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Instead you will write your class like:</p> <div class="gatsby-code-button-container" data-toaster-id="36528976264425263000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class MyComponent extends Component { handleClick = () => { // ... } render() { // ... } }`, `36528976264425263000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">MyComponent</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span> <span class="token function-variable function">handleClick</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 comment">// ...</span> <span class="token punctuation">}</span> <span class="token function">render</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> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you might know, usual functions are defined in the prototype and will be shared across all instances. If we have a list of <code class="language-text">N</code> components, these components will share the same method. So, if our components get clicked we still call our method <code class="language-text">N</code> times, but it will call the same prototype. As we’re calling the same method multiple times across the prototype, the <code class="language-text">JavaScript</code> engine can optimize it.</p> <p>On the other hand, for the arrow functions in class properties, if we’re creating <code class="language-text">N</code> components, these <code class="language-text">N</code> components will also create <code class="language-text">N</code> functions. You can see by looking at the transpiled version, that class properties are initialised in the constructor. Which means if we click on <code class="language-text">N</code> components, <code class="language-text">N</code> different functions will be called.</p> <p>So consider this approach next time you are writing your new shiny <code class="language-text">React</code> component.</p> <h2 id="nested-functions-vs-iifes" style="position:relative;"><a href="#nested-functions-vs-iifes" aria-label="nested functions vs iifes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Nested functions VS IIFEs</h2> <p>Nesting a function inside another function seems like a good idea to isolate some logic from outside world. Consider below code:</p> <div class="gatsby-code-button-container" data-toaster-id="99844222698240340000" data-toaster-class="gatsby-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 doSomething(arg1, arg2) { function nestedHelper(arg) { return process(arg) } return nestedHelper(arg1) + nestedHelper(arg2) }`, `99844222698240340000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token parameter">arg1<span class="token punctuation">,</span> arg2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">nestedHelper</span><span class="token punctuation">(</span><span class="token parameter">arg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">process</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">nestedHelper</span><span class="token punctuation">(</span>arg1<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">nestedHelper</span><span class="token punctuation">(</span>arg2<span class="token punctuation">)</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The problem with above code is that every time you call <code class="language-text">doSomething</code>, the <code class="language-text">nestedHeler</code> is recreated. In order to prevent that you can use an <code class="language-text">IIFE</code> (Immediately invoked function):</p> <div class="gatsby-code-button-container" data-toaster-id="14155823278850898000" data-toaster-class="gatsby-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 result = (function() { function privateHelper(arg) { var result = process(arg) return result } return function(arg1, arg2) { return ( privateHelper(arg1) + privateHelper(arg2) ) } })()`, `14155823278850898000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">privateHelper</span><span class="token punctuation">(</span><span class="token parameter">arg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token function">process</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span> <span class="token keyword">return</span> result <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">arg1<span class="token punctuation">,</span> arg2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token function">privateHelper</span><span class="token punctuation">(</span>arg1<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">privateHelper</span><span class="token punctuation">(</span>arg2<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>When this code gets executed, the nested method will be created only once 🤷‍♂️.</p> <h1 id="use-sets-over-arrays-where-possible" style="position:relative;"><a href="#use-sets-over-arrays-where-possible" aria-label="use sets over arrays where possible permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 Sets over Arrays where possible</h1> <p>The most obvious difference between an <code class="language-text">array</code> and a <code class="language-text">Set</code> is that <code class="language-text">array</code> is an <em>indexed</em> collection, whereas, a <code class="language-text">Set</code> is key based.</p> <p>So why you should be using a <code class="language-text">Set</code>?</p> <h3 id="searching-for-an-item" style="position:relative;"><a href="#searching-for-an-item" aria-label="searching for an item permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Searching for an Item</h3> <p>Using <code class="language-text">indexOf()</code> or <code class="language-text">includes()</code> to check whether an item exists in an array is slow. In a <code class="language-text">Set</code> you can find an item really easy using <code class="language-text">has()</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="39889046443752310000" data-toaster-class="gatsby-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 mySet = new Set([1, 1, 2]) console.log(mySet.has(2)) // true`, `39889046443752310000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> mySet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</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">1</span><span class="token punctuation">,</span> <span class="token number">2</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>mySet<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="deleting-an-item" style="position:relative;"><a href="#deleting-an-item" aria-label="deleting an item permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Deleting an Item</h3> <p>In a <code class="language-text">Set</code>, you can delete an item by its value. In an array, the equivalent is using <code class="language-text">splice()</code> based on an element’s <code class="language-text">index</code>. As in the previous point, depending on indices is slow.</p> <div class="gatsby-code-button-container" data-toaster-id="74454116668966110000" data-toaster-class="gatsby-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 mySet = new Set([1, 2, 3, 4, 5]) mySet.delete(1)`, `74454116668966110000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> mySet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</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">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span> mySet<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="insert-an-item" style="position:relative;"><a href="#insert-an-item" aria-label="insert an item permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Insert an Item</h3> <p>It is much faster to add an item to a <code class="language-text">Set</code> than to an array using <code class="language-text">push()</code> or <code class="language-text">unshift()</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="49145670483977445000" data-toaster-class="gatsby-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 mySet = new Set([1, 2]) mySet.add(3) // Successfully added`, `49145670483977445000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> mySet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</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">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> mySet<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token comment">// Successfully added</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="storing-nan" style="position:relative;"><a href="#storing-nan" aria-label="storing nan permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Storing NaN</h3> <p>You cannot use <code class="language-text">indexOf()</code> or <code class="language-text">includes()</code> to find the value <code class="language-text">NaN</code>, while a <code class="language-text">Set</code> is able to store this value.</p> <h3 id="removing-duplicates" style="position:relative;"><a href="#removing-duplicates" aria-label="removing duplicates permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Removing Duplicates</h3> <p><code class="language-text">Set</code> objects only store unique values. If you want to avoid storing duplicates, this is a significant advantage over arrays, where additional code would be required to deal with duplicates.</p> <div class="gatsby-code-button-container" data-toaster-id="32470674083332194000" data-toaster-class="gatsby-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 mySet = new Set([1, 1, 2]) mySet.add(3) // Successfully added console.log(mySet.values()) // 1,2,3`, `32470674083332194000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> mySet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</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">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> mySet<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token comment">// Successfully added</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>mySet<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 1,2,3</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h1 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</h1> <p>There are many of these examples where you might want to be careful when writing code in a real world business application. Speed is one of the most important part of every web application and considering some items like above points, will increase your code’s performance which can result in happier users 😊.</p> <p>Hope this has helped you to start thinking about what other ways there are to solve the same issue rather than the first solution you’ll find on the web.</p><![CDATA[OffscreenCanvas - Render your graphics off the main thread]]>https://yashints.dev/blog/2019/05/11/offscreen-canvashttps://yashints.dev/blog/2019/05/11/offscreen-canvasSat, 11 May 2019 00:00:00 GMT<p>Rendering images on a web page can be a very compute heavy operation. This makes it harder to run these kind of operations on the main thread since it might slow down the rendering or affect the user experience.</p> <!--more--> <h1 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</h1> <p><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas" target="_blank" rel="nofollow noopener noreferrer">Canvas</a> is one of the most interesting HTML elements in my opinion. The most popular reasons of using it are drawing graphics or animations.</p> <p>From Google Developers site:</p> <blockquote> <p>It is often used to create beautiful user experiences in media-rich web applications and online games.</p> </blockquote> <p>The fact that you can script it, raises the bar even higher and makes the element even more interesting. This gives you great flexibility in so many situations, but we’re going to focus on animations or rendering in general today.</p> <h1 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</h1> <p>At the same time, executing JavaScript is one of the most frequent <a href="https://yashints.dev/blog/2018/10/12/web-perf-3" target="_blank" rel="nofollow noopener noreferrer">sources of user experience</a> issues. Because all the JavaScript code <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop" target="_blank" rel="nofollow noopener noreferrer">runs on the same thread</a> as user interaction, these sort of heavy compute operations can affect the user experience in addition to real and perceived performance.</p> <h1 id="example" style="position:relative;"><a href="#example" aria-label="example permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Example</h1> <p>To give you an example of how easy it is to use canvas, consider the following code:</p> <div class="gatsby-code-button-container" data-toaster-id="43239678613464875000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<canvas id=&quot;canvas&quot; width=&quot;300&quot; height=&quot;300&quot;> An alternative text describing what your canvas displays. </canvas>`, `43239678613464875000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>canvas</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>canvas<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>300<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>300<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> An alternative text describing what your canvas displays. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>canvas</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And in your JavaScript file:</p> <div class="gatsby-code-button-container" data-toaster-id="81244647321073680000" data-toaster-class="gatsby-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 mainCanvas = document.getElementById( 'myCanvas' ) var mainContext = mainCanvas.getContext('2d') var canvasWidth = mainCanvas.width var canvasHeight = mainCanvas.height var angle = 0 var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame function drawCircle() { mainContext.clearRect( 0, 0, canvasWidth, canvasHeight ) // color in the background mainContext.fillStyle = '#EEEEEE' mainContext.fillRect( 0, 0, canvasWidth, canvasHeight ) // draw the circle mainContext.beginPath() var radius = 25 + 150 * Math.abs(Math.cos(angle)) mainContext.arc( 225, 225, radius, 0, Math.PI * 2, false ) mainContext.closePath() // color in the circle mainContext.fillStyle = '#006699' mainContext.fill() angle += Math.PI / 64 requestAnimationFrame(drawCircle) } drawCircle()`, `81244647321073680000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> mainCanvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span> <span class="token string">'myCanvas'</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> mainContext <span class="token operator">=</span> mainCanvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">'2d'</span><span class="token punctuation">)</span> <span class="token keyword">var</span> canvasWidth <span class="token operator">=</span> mainCanvas<span class="token punctuation">.</span>width <span class="token keyword">var</span> canvasHeight <span class="token operator">=</span> mainCanvas<span class="token punctuation">.</span>height <span class="token keyword">var</span> angle <span class="token operator">=</span> <span class="token number">0</span> <span class="token keyword">var</span> requestAnimationFrame <span class="token operator">=</span> window<span class="token punctuation">.</span>requestAnimationFrame <span class="token operator">||</span> window<span class="token punctuation">.</span>mozRequestAnimationFrame <span class="token operator">||</span> window<span class="token punctuation">.</span>webkitRequestAnimationFrame <span class="token operator">||</span> window<span class="token punctuation">.</span>msRequestAnimationFrame <span class="token keyword">function</span> <span class="token function">drawCircle</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> mainContext<span class="token punctuation">.</span><span class="token function">clearRect</span><span class="token punctuation">(</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> canvasWidth<span class="token punctuation">,</span> canvasHeight <span class="token punctuation">)</span> <span class="token comment">// color in the background</span> mainContext<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> <span class="token string">'#EEEEEE'</span> mainContext<span class="token punctuation">.</span><span class="token function">fillRect</span><span class="token punctuation">(</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> canvasWidth<span class="token punctuation">,</span> canvasHeight <span class="token punctuation">)</span> <span class="token comment">// draw the circle</span> mainContext<span class="token punctuation">.</span><span class="token function">beginPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">var</span> radius <span class="token operator">=</span> <span class="token number">25</span> <span class="token operator">+</span> <span class="token number">150</span> <span class="token operator">*</span> Math<span class="token punctuation">.</span><span class="token function">abs</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">cos</span><span class="token punctuation">(</span>angle<span class="token punctuation">)</span><span class="token punctuation">)</span> mainContext<span class="token punctuation">.</span><span class="token function">arc</span><span class="token punctuation">(</span> <span class="token number">225</span><span class="token punctuation">,</span> <span class="token number">225</span><span class="token punctuation">,</span> radius<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> Math<span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> mainContext<span class="token punctuation">.</span><span class="token function">closePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// color in the circle</span> mainContext<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> <span class="token string">'#006699'</span> mainContext<span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token punctuation">)</span> angle <span class="token operator">+=</span> Math<span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">/</span> <span class="token number">64</span> <span class="token function">requestAnimationFrame</span><span class="token punctuation">(</span>drawCircle<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">drawCircle</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This is how it looks like:</p> <iframe height="220" style="width: 100%;" scrolling="no" title="CanvasAnimation" src="//codepen.io/yashints/embed/wbWppN/?height=265&theme-id=0&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/wbWppN/'>CanvasAnimation</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <p>Now let’s add a twist to this code. Let’s run a bit of code at the same time as the animation is running. We add a button and a handler that calls a function to calculate the Fibonacci number sequence 🤷‍♂️. So let’s get into it and add the button:</p> <div class="gatsby-code-button-container" data-toaster-id="13690203533337920000" data-toaster-class="gatsby-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 type=&quot;button&quot; id=&quot;make-busy&quot;> Hit the main thread! </button>`, `13690203533337920000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>make-busy<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Hit the main thread! <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>And let’s implement the Fibonacci series with a recursive function. Then we will use the <code class="language-text">requestAnimationFrame</code> to make sure this code is run on the next available repaint. For more info on <code class="language-text">requestAnimationFrame</code>, make sure to check out <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame" target="_blank" rel="nofollow noopener noreferrer">the documentation</a>.</p> <div class="gatsby-code-button-container" data-toaster-id="69010047444752010000" data-toaster-class="gatsby-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 fibonacci(num) { if (num <= 1) return 1 return fibonacci(num - 1) + fibonacci(num - 2) } document .querySelector('#make-busy') .addEventListener('click', () => { document.querySelector('#busy').innerText = 'Main thread working...' requestAnimationFrame(() => { requestAnimationFrame(() => { fibonacci(40) document.querySelector( '#busy' ).innerText = 'Done!' }) }) })`, `69010047444752010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">fibonacci</span><span class="token punctuation">(</span><span class="token parameter">num</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>num <span class="token operator">&lt;=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token number">1</span> <span class="token keyword">return</span> <span class="token function">fibonacci</span><span class="token punctuation">(</span>num <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">fibonacci</span><span class="token punctuation">(</span>num <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</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">'#make-busy'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</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> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#busy'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>innerText <span class="token operator">=</span> <span class="token string">'Main thread working...'</span> <span class="token function">requestAnimationFrame</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 function">requestAnimationFrame</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 function">fibonacci</span><span class="token punctuation">(</span><span class="token number">40</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">'#busy'</span> <span class="token punctuation">)</span><span class="token punctuation">.</span>innerText <span class="token operator">=</span> <span class="token string">'Done!'</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now if you click on the button, you will see that the animation will stop and resume after the call to <code class="language-text">fibonacci</code> function is returned.</p> <iframe height="265" style="width: 100%;" scrolling="no" title="CanvasAnimation" src="//codepen.io/yashints/embed/QREBrx/?height=265&theme-id=0&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/QREBrx/'>CanvasAnimation</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <p>You can clearly see how users might feel if they face a similar situation on your web application. And this is when the <code class="language-text">OffscreenCanvas</code> can help.</p> <h1 id="offscreencanvas" style="position:relative;"><a href="#offscreencanvas" aria-label="offscreencanvas permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>OffscreenCanvas</h1> <p>Up until recently, the drawing capabilities of canvas was directly dependent on the <code class="language-text">&lt;canvas></code> element which meant it would depend on DOM (Document Object Model). <code class="language-text">OffscreenCanvas</code> on the other hand, decouples DOM and Canvas API by moving it’s operations off screen.</p> <p>To make it even more interesting, the rendering operations can now be run inside a worker, thanks to the aforementioned decoupling. This alone opens the doors of possibilities to all sorts of performance improvements.</p> <h2 id="using-it-in-a-worker" style="position:relative;"><a href="#using-it-in-a-worker" aria-label="using it in a worker permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 it in a worker</h2> <p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" target="_blank" rel="nofollow noopener noreferrer">Web Workers</a> are the web’s version of multi threading. They allow you to run code/tasks in a separate thread (aka background 😁). Now that the decoupling between DOM and Canvas API has landed, we can run it inside a worker.</p> <p>By expanding our previous example, we will add another copy of the same animation, but this time we’ll do the rendering in an <code class="language-text">OffscreenCanvas</code> in a web worker.</p> <p>We need to setup our worker code in a script (I’ve named <code class="language-text">animation.js</code>) which we can use later. First we need to move our animation code to its own file. Then let’s create our worker code:</p> <div class="gatsby-code-button-container" data-toaster-id="8372110444288183000" data-toaster-class="gatsby-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 animationWorker = null self.onmessage = function(e) { switch (e.data.msg) { case 'start': if (!animationWorker) { importScripts( e.data.origin + '/animation.js' ) animationWorker = new ThemedAnimation( e.data.canvas.getContext('2d') ) } animationWorker.start() break case 'stop': if (!animationWorker) { return } animationWorker.stop() break } }`, `8372110444288183000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> animationWorker <span class="token operator">=</span> <span class="token keyword">null</span> self<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>data<span class="token punctuation">.</span>msg<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token string">'start'</span><span class="token operator">:</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>animationWorker<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">importScripts</span><span class="token punctuation">(</span> e<span class="token punctuation">.</span>data<span class="token punctuation">.</span>origin <span class="token operator">+</span> <span class="token string">'/animation.js'</span> <span class="token punctuation">)</span> animationWorker <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ThemedAnimation</span><span class="token punctuation">(</span> e<span class="token punctuation">.</span>data<span class="token punctuation">.</span>canvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">'2d'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> animationWorker<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">break</span> <span class="token keyword">case</span> <span class="token string">'stop'</span><span class="token operator">:</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>animationWorker<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> animationWorker<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">break</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>No you can create two canvas elements side by side:</p> <div class="gatsby-code-button-container" data-toaster-id="99525748359084770000" data-toaster-class="gatsby-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> <section class=&quot;support&quot;> Your browser does not support OffscreenCanvas. </section> <div> <h1>Canvas on main thread</h1> <p> Interaction is blocked when a theme is loading </p> <canvas id=&quot;canvas-window&quot; width=&quot;400&quot; height=&quot;400&quot; ></canvas> </div> <div> <h1>Canvas on worker thread</h1> <p> Interaction works even if a theme is loading </p> <canvas id=&quot;canvas-worker&quot; width=&quot;400&quot; height=&quot;400&quot; ></canvas> </div> </main>`, `99525748359084770000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><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>section</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>support<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Your browser does not support OffscreenCanvas. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</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>h1</span><span class="token punctuation">></span></span>Canvas on main thread<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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> Interaction is blocked when a theme is loading <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>canvas</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>canvas-window<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<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>canvas</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>h1</span><span class="token punctuation">></span></span>Canvas on worker thread<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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> Interaction works even if a theme is loading <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>canvas</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>canvas-worker<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<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>canvas</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And finally create the worker from the script tag above, request an animation frame (we used <code class="language-text">setTimeOut</code> previously), and run the animation in both canvases at the same time.</p> <div class="gatsby-code-button-container" data-toaster-id="21191738314328633000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`document .querySelector('main') .classList.toggle( 'supported', 'OffscreenCanvas' in window ) document .querySelector('#make-busy') .addEventListener('click', () => { document.querySelector('#busy').innerText = 'Main thread working...' requestAnimationFrame(() => { requestAnimationFrame(() => { Animation.fibonacci(40) document.querySelector( '#busy' ).innerText = 'Done!' }) }) }) const canvas = document.querySelector('#case1') const animationWindow = new Animation( document .querySelector('#canvas-window') .getContext('2d') ) animationWindow.start() const workerCode = document.querySelector( '#workerCode' ).textContent const blob = new Blob([workerCode], { type: 'text/javascript', }) const url = URL.createObjectURL(blob) const worker = new Worker(url) const offscreen = document .querySelector('#canvas-worker') .transferControlToOffscreen() const urlParts = location.href.split('/') if ( urlParts[urlParts.length - 1].indexOf('.') !== -1 ) { urlParts.pop() } worker.postMessage( { msg: 'start', origin: urlParts.join('/'), canvas: offscreen, }, [offscreen] ) URL.revokeObjectURL(url) // cleanup`, `21191738314328633000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">document <span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'main'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">toggle</span><span class="token punctuation">(</span> <span class="token string">'supported'</span><span class="token punctuation">,</span> <span class="token string">'OffscreenCanvas'</span> <span class="token keyword">in</span> window <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">'#make-busy'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</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> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#busy'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>innerText <span class="token operator">=</span> <span class="token string">'Main thread working...'</span> <span class="token function">requestAnimationFrame</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 function">requestAnimationFrame</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> Animation<span class="token punctuation">.</span><span class="token function">fibonacci</span><span class="token punctuation">(</span><span class="token number">40</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">'#busy'</span> <span class="token punctuation">)</span><span class="token punctuation">.</span>innerText <span class="token operator">=</span> <span class="token string">'Done!'</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">const</span> canvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#case1'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> animationWindow <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Animation</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">'#canvas-window'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">'2d'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> animationWindow<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> workerCode <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span> <span class="token string">'#workerCode'</span> <span class="token punctuation">)</span><span class="token punctuation">.</span>textContent <span class="token keyword">const</span> blob <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Blob</span><span class="token punctuation">(</span><span class="token punctuation">[</span>workerCode<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text/javascript'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token constant">URL</span><span class="token punctuation">.</span><span class="token function">createObjectURL</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span> <span class="token keyword">const</span> worker <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Worker</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span> <span class="token keyword">const</span> offscreen <span class="token operator">=</span> document <span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#canvas-worker'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">transferControlToOffscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> urlParts <span class="token operator">=</span> location<span class="token punctuation">.</span>href<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 keyword">if</span> <span class="token punctuation">(</span> urlParts<span class="token punctuation">[</span>urlParts<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'.'</span><span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> urlParts<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> worker<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token literal-property property">msg</span><span class="token operator">:</span> <span class="token string">'start'</span><span class="token punctuation">,</span> <span class="token literal-property property">origin</span><span class="token operator">:</span> urlParts<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">canvas</span><span class="token operator">:</span> offscreen<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>offscreen<span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token constant">URL</span><span class="token punctuation">.</span><span class="token function">revokeObjectURL</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span> <span class="token comment">// cleanup</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Let’s see what’s happening here. First we need to detect the feature (OffscreenCanvas is not fully supported yet). Next we hook an event handler for our button to put some load on the main thread. This will put some stress on our animation rendering in the main thread.</p> <p>Afterwards, we get our canvas and run the animation code in the main thread, after which, we do the same in our worker. Except that we have to send a message to our worker to get that started (pay attention to the switch case in the worker code).</p> <p>And last but not least, make sure you don’t miss the most important part of the code which is call to <code class="language-text">transferControlToOffscreen</code> on the canvas. This is where the magic of <code class="language-text">OffscreenCanvas</code> happens. This method converts our regular canvas into an OffscreenCanvas instance.</p> <p>Below you can see the whole code in action:</p> <iframe height="500" style="width: 100%;" scrolling="no" title="CanvasAnimation" src="https://yashints.github.io/offscreencanvas/" frameborder="no" allowtransparency="false" allowfullscreen="false"> See the full code <a href='https://github.com/yashints/offscreencanvas/'>OffscreenCanvas</a> by Yaser Adel Mehraban (<a href='https://yashints.dev'>@yashints</a>) on <a href='https://yashints.github.io/offscreencanvas/'>GitHub Pages</a>. </iframe> <h1 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</h1> <p>We saw the difference in rendering smoothness when using an <code class="language-text">OffscreenCanvas</code> in comparison with running the same on the main thread. This amazing feature can be used alongside all of the other techniques in <a href="https://yashints.dev/blog/2018/09/29/web-perf-1" target="_blank" rel="nofollow noopener noreferrer">my previous posts on web performance</a> to help you have a faster website and happier customers 😊.</p><![CDATA[How do I keep up with frontend world]]>https://yashints.dev/blog/2019/05/09/keeping-up-with-frontendhttps://yashints.dev/blog/2019/05/09/keeping-up-with-frontendThu, 09 May 2019 00:00:00 GMT<p>I’ve been in web development for a long time and not until four or five years ago did I had to keep up with this light speed moving train.</p> <!--more--> <h1 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</h1> <p>There has been so many times when I heard some phrase from somewhere be it at a conference, talking to a colleague, or simply surfing the web, that I realised oh, I didn’t even know this exists.</p> <p><em>Angular</em>, <em>React</em>, <em>Vue</em>, <em>RxJs</em>, <em>NgRx</em>, <em>TensorflowJs</em>, <em>CSS Houdini</em>, <em>Webpack</em>, <em>Parcel</em>, <em>Gulp</em>, <em>Grunt</em>, <em>npm</em>, <em>npx</em>, <em>CSS Grid</em>, <em>Flex box</em>, <em>Meteor</em>, <em>SASS</em>, <em>LESS</em>, and the list goes on and on and on 😵.</p> <p>Those moments can be terrifying, especially if suddenly everyone is talking about it. So finally, on a Sunday afternoon, I sat on our balcony thinking I can’t continue like this and always be behind of what’s happening.</p> <p>I decided to talk to some of the people I knew (face to face, on Twitter, LinkedIn, conferences and meetups) were ahead of the game most of the times and see what they do in order to be where they are.</p> <p>Since that afternoon where I was sitting on my balcony sipping a lukewarm coffee, I’ve learnt a few tips and tricks around what do to be able to feel you know enough to be able to keep up with what’s happening. So I decided to share my learnings (and hear yours in the comments) with you all.</p> <h1 id="1-reading" style="position:relative;"><a href="#1-reading" aria-label="1 reading permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Reading</h1> <p>The most important part of learning is reading (at least for me). I always keep some time and read (I will share some sources later 👇🏽) about what’s happening. I don’t usually go too deep into something when I read, just to learn the background and story of what the topic is about.</p> <p>You are probably wondering when, and I know for most people this is the most critical part. I do not drive to work although I live in a suburb. I take the bus and spend the whole time reading. I will also spend some time before going to bed or after waking up early in the morning to catch up with what’s happening in the wild.</p> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> I usually see articles and posts on social media and use <a href="https://www.instapaper.com/" target="_blank" rel="nofollow noopener noreferrer">Instapaper</a> to keep track of where I am with my reading list. It’s got an iOS app which gives you a nice option when you share your links from basically anywhere.</div></div> <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/41455efbda2e12db287b6a8b9e763774/07679/instapaper.jpg" 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/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgP/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHuzIoDgXE//8QAHBAAAgICAwAAAAAAAAAAAAAAAQIDBBITABEz/9oACAEBAAEFAnVWsa0x2hednORiJ7Hp/8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8Bh//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EAB0QAAIBBAMAAAAAAAAAAAAAAAABAhESMUEQUWH/2gAIAQEABj8CcU/SnZbLKyTe7kRVd8f/xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhMUFR/9oACAEBAAE/IaKSmIEmcVfsNw84SK4EYFEGKhrPyf/aAAwDAQACAAMAAAAQSx//xAAXEQEBAQEAAAAAAAAAAAAAAAABABEh/9oACAEDAQE/EHttL//EABYRAQEBAAAAAAAAAAAAAAAAAAARIf/aAAgBAgEBPxC4j//EAB8QAQABBAEFAAAAAAAAAAAAAAERACExQWFRgZGxwf/aAAgBAQABPxAKksBedx780J4mUpPM662oGFzQspuec96fqbohLYpzRkGyKHILcKTdPlf/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Instapaper add to reading list on iPhone" title="" src="/static/41455efbda2e12db287b6a8b9e763774/47311/instapaper.jpg" srcset="/static/41455efbda2e12db287b6a8b9e763774/6f81f/instapaper.jpg 270w, /static/41455efbda2e12db287b6a8b9e763774/09d21/instapaper.jpg 540w, /static/41455efbda2e12db287b6a8b9e763774/47311/instapaper.jpg 1080w, /static/41455efbda2e12db287b6a8b9e763774/0047d/instapaper.jpg 1620w, /static/41455efbda2e12db287b6a8b9e763774/274e1/instapaper.jpg 2160w, /static/41455efbda2e12db287b6a8b9e763774/07679/instapaper.jpg 2596w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="enough-talking-tell-me-what-do-you-read" style="position:relative;"><a href="#enough-talking-tell-me-what-do-you-read" aria-label="enough talking tell me what do you read permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 talking, tell me what do you read?</h2> <p>Your next question is probably what do you read. I have these as my reading sources:</p> <h3 id="blogs-and-feeds" style="position:relative;"><a href="#blogs-and-feeds" aria-label="blogs and feeds permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Blogs and Feeds</h3> <p>I have an <a href="/fb3fee510db4412fd2f3d3be2994eee6/feedbro-subscriptions.opml">RSS feed</a> for you to download which I’ve borrowed from <a href="https://www.paulirish.com/2011/web-browser-frontend-and-standards-feeds-to-follow/" target="_blank" rel="nofollow noopener noreferrer">Paul Irish</a> and customised it.</p> <p>In addition to that, I check below sources regularly:</p> <ul> <li><a href="https://developers.google.com/web/" target="_blank" rel="nofollow noopener noreferrer">Google’s Web Fundamentals</a></li> <li><a href="https://www.google.com/search?q=%22Open+Web+Platform+Weekly+Summary%22+site%3Aw3.org" target="_blank" rel="nofollow noopener noreferrer">Open web platform weekly summary</a></li> <li><a href="https://dev.to" target="_blank" rel="nofollow noopener noreferrer">Our very own Dev Community</a></li> <li><a href="https://css-tricks.com/" target="_blank" rel="nofollow noopener noreferrer">CSS-TRICKS</a></li> <li><a href="http://csswizardry.com/" target="_blank" rel="nofollow noopener noreferrer">CSS Wizardry</a></li> <li><a href="https://www.smashingmagazine.com/" target="_blank" rel="nofollow noopener noreferrer">Smashing Magazine</a></li> <li>And recently less of <a href="https://medium.com/front-end-weekly" target="_blank" rel="nofollow noopener noreferrer">frontend weekly on Medium</a></li> </ul> <h3 id="social-media-mostly-twitter-and-linkedin" style="position:relative;"><a href="#social-media-mostly-twitter-and-linkedin" aria-label="social media mostly twitter and linkedin permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Social media (mostly Twitter and LinkedIn)</h3> <p>Most days, 45 minutes to an hour of my time is spent on Twitter and about half of that on LinkedIn. I don’t spend more than a few second on anything. If something catches my eyes, it will be added to my <em>Instapaper</em> list.</p> <h3 id="official-documentation-tools-and-frameworks" style="position:relative;"><a href="#official-documentation-tools-and-frameworks" aria-label="official documentation tools and frameworks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Official documentation (tools and frameworks)</h3> <p>Official documentation is where I go deep into something. If want to learn everything about a subject, whether it’s a framework, library, tool, I start with their documentation. more than 80% of the time, I find what I’m after.</p> <h3 id="books" style="position:relative;"><a href="#books" aria-label="books permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Books</h3> <p>This one is a tricky one. I haven’t had a situation where I finished the whole of a technical books. I use them as reference material and refer to them whenever I need to know a very specific detail of a subject. But I would never spend that much time reading a whole book, things are changing faster than I can finish the book, trust me on that 😉.</p> <h3 id="weeklymonthly-news-feeds" style="position:relative;"><a href="#weeklymonthly-news-feeds" aria-label="weeklymonthly news feeds permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Weekly/Monthly news feeds</h3> <p>Weekly newsletters and feeds are awesome sources of new information. The maintainer spend a lot of time researching and sharing information and I have to say kudus to them.</p> <p>Here are a few I use:</p> <ul> <li><a href="https://web-design-weekly.com/" target="_blank" rel="nofollow noopener noreferrer">Web Design Weekly</a></li> <li><a href="https://frontendfoc.us/" target="_blank" rel="nofollow noopener noreferrer">Frontend Focus</a></li> <li><a href="https://javascriptweekly.com/" target="_blank" rel="nofollow noopener noreferrer">JavaScript Weekly</a></li> <li><a href="https://wdrl.info/" target="_blank" rel="nofollow noopener noreferrer">Web Development Reading List</a></li> <li><a href="https://webopsweekly.com/" target="_blank" rel="nofollow noopener noreferrer">Web Operations Weekly</a></li> <li><a href="https://react.statuscode.com/" target="_blank" rel="nofollow noopener noreferrer">React Status</a></li> <li><a href="http://www.angular-weekly.com/" target="_blank" rel="nofollow noopener noreferrer">Angular Weekly</a></li> <li><a href="https://vuejsdevelopers.com/newsletter" target="_blank" rel="nofollow noopener noreferrer">Newsletter - Vue.js Developers</a></li> </ul> <h1 id="2-following-cool-people" style="position:relative;"><a href="#2-following-cool-people" aria-label="2 following cool people permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Following cool people</h1> <p>I follow a well-curated list of people on social media who are active and produce new things. This is a tricky situation because sometimes you realise how much you don’t know. But I love it and it’s a great thing for me personally to know what’s missing from my knowledge. It helps me form a plan for my learnings.</p> <p>Are you still wondering why?</p> <blockquote> <p>If you feel like you are the smartest person in the room, you’re in the wrong room.</p> <p>Confucius</p> </blockquote> <p>These are some of the people I follow:</p> <ul> <li><a href="https://twitter.com/addyosmani" target="_blank" rel="nofollow noopener noreferrer">Addy Osmani</a> - Web and mostly performance</li> <li><a href="https://twitter.com/paul_irish" target="_blank" rel="nofollow noopener noreferrer">Paul Irish</a> - Web</li> <li><a href="https://twitter.com/jaffathecake" target="_blank" rel="nofollow noopener noreferrer">Jake Archibald</a> - Web, mostly standards</li> <li><a href="https://twitter.com/davidwalshblog" target="_blank" rel="nofollow noopener noreferrer">David Walsh</a> - JavaScript</li> <li><a href="https://twitter.com/codepo8" target="_blank" rel="nofollow noopener noreferrer">Christian Heilmann</a> - Web</li> <li><a href="https://twitter.com/dan_abramov" target="_blank" rel="nofollow noopener noreferrer">Dan Abramov</a> - React</li> <li><a href="https://twitter.com/stephenfluin" target="_blank" rel="nofollow noopener noreferrer">Stephen Fluin</a> - Angular</li> <li><a href="https://twitter.com/sarah_edo" target="_blank" rel="nofollow noopener noreferrer">Sarah Drasner</a> - Vue</li> <li><a href="https://twitter.com/jawache" target="_blank" rel="nofollow noopener noreferrer">Asim Hussain</a> - JavaScript, AI, TensorflowJs</li> <li><a href="https://github.com/TheLarkInn" target="_blank" rel="nofollow noopener noreferrer">Sean Larkin</a> - Webpack</li> </ul> <p>And the list continues with another 800 or so amazing people, but you might have noticed a theme here. I follow specific people in different categories to find out what’s happening.</p> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> I do follow people from all sorts of different backgrounds and not only ffrontend. A good frontend engineer should know enough about the backend and considering I am consultant, it’s a must for me.</div></div> <br/> <h1 id="3-conferences-and-meetups" style="position:relative;"><a href="#3-conferences-and-meetups" aria-label="3 conferences and meetups permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Conferences and Meetups</h1> <p>Conferences are the most fascinating place to meet smart people, learn a few things and get an idea of where the industry moving to. It give you a breadth (and sometimes even depths) in multiple topics that you didn’t even knew they are a thing.</p> <p>Apart from attending, I usually speak as well. This is also a really good way of learning. You should know a topic well enough to be able to present it to your audience. To see when and where I’ll be speaking, have a look at <a href="/speaking">my speaking schedule</a>.</p> <p>There are thousands of conferences out there. But I usually use these sites to find out what’s happening when:</p> <ul> <li><a href="https://github.com/Readify/DevEvents/" target="_blank" rel="nofollow noopener noreferrer">Australia’s Dev Events</a></li> <li><a href="https://confs.tech/" target="_blank" rel="nofollow noopener noreferrer">Confs.tech</a></li> <li><a href="https://www.papercall.io/events" target="_blank" rel="nofollow noopener noreferrer">Papercall.io</a></li> <li><a href="https://angularconferences.com/" target="_blank" rel="nofollow noopener noreferrer">Angular conferences</a></li> <li><a href="https://jsconf.com/" target="_blank" rel="nofollow noopener noreferrer">JSConf</a></li> <li><a href="https://frontendfront.com/conferences/" target="_blank" rel="nofollow noopener noreferrer">Frontend conferences</a></li> <li><a href="https://www.meetup.com/" target="_blank" rel="nofollow noopener noreferrer">Meetup.com</a></li> </ul> <h1 id="4-videos-online-courses-and-podcasts" style="position:relative;"><a href="#4-videos-online-courses-and-podcasts" aria-label="4 videos online courses and podcasts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4. Videos, online courses and Podcasts</h1> <p>Some people like to watch videos and online courses. This is how they learn, however, for me that’s not the case. But I don’t exclude them from my sources, especially recorded conference talks. Below is a list of YouTube channels and online courses I use occasionally:</p> <ul> <li><a href="https://www.youtube.com/channel/UCnUYZLuoy1rq1aVMwx4aTzw" target="_blank" rel="nofollow noopener noreferrer">Google Chrome Developers</a> - This is super useful for me since they have pretty much short clips teaching something useful and frequently</li> <li><a href="https://www.youtube.com/channel/UCsMica-v34Irf9KVTh6xx-g" target="_blank" rel="nofollow noopener noreferrer">Microsoft Developer</a></li> <li><a href="https://www.youtube.com/channel/UCTdw38Cw6jcm0atBPA39a0Q" target="_blank" rel="nofollow noopener noreferrer">NDC Conferences</a></li> <li><a href="https://www.youtube.com/channel/UCm9iiIfgmVODUJxINecHQkA" target="_blank" rel="nofollow noopener noreferrer">ng-conf</a></li> <li><a href="https://www.youtube.com/channel/UCTZ3O2cZo1b4JSwvhgBnAbw" target="_blank" rel="nofollow noopener noreferrer">Nordic.js</a></li> <li><a href="https://www.youtube.com/channel/UCX4w2P-M4cuWQG0WKgU3TTQ" target="_blank" rel="nofollow noopener noreferrer">Vue NYC</a></li> <li><a href="https://www.youtube.com/channel/UCz5vTaEhvh7dOHEyd1efcaQ" target="_blank" rel="nofollow noopener noreferrer">React conf</a></li> <li><a href="https://www.youtube.com/channel/uczrsktit_obak3xbkvxmz5g" target="_blank" rel="nofollow noopener noreferrer">Angular Connect</a></li> <li><a href="https://www.youtube.com/channel/UCbn1OgGei-DV7aSRo_HaAiw" target="_blank" rel="nofollow noopener noreferrer">Angular channel</a></li> </ul> <p>If you’re looking at online courses, these are my favourite:</p> <ul> <li><a href="https://www.pluralsight.com" target="_blank" rel="nofollow noopener noreferrer">Pluralsight</a></li> <li><a href="https://frontendmasters.com/" target="_blank" rel="nofollow noopener noreferrer">Frontend Masters</a></li> <li><a href="https://egghead.io/" target="_blank" rel="nofollow noopener noreferrer">egghead.io</a></li> </ul> <p>Another good source of information are podcasts. They are so good if you ride/drive to work everyday. You can just listen to become aware of the latest news or learn about a technology.</p> <p>Below are a few I use:</p> <ul> <li><a href="https://hanselminutes.com/" target="_blank" rel="nofollow noopener noreferrer">The Hanselminutes</a></li> <li><a href="https://devchat.tv/js-jabber/" target="_blank" rel="nofollow noopener noreferrer">JavaScript Jabber</a></li> <li><a href="https://developertea.com/" target="_blank" rel="nofollow noopener noreferrer">Developer Tea</a></li> <li><a href="https://egghead.io/podcasts" target="_blank" rel="nofollow noopener noreferrer">egghead.io developer chats</a></li> <li><a href="https://frontendhappyhour.com/" target="_blank" rel="nofollow noopener noreferrer">frontend Happy Hour</a></li> <li><a href="https://freecodecamp.libsyn.com/" target="_blank" rel="nofollow noopener noreferrer">The freeCodeCamp Podcast</a></li> <li><a href="https://frontside.io/podcast" target="_blank" rel="nofollow noopener noreferrer">The Frontside Podcast</a></li> <li><a href="https://www.fullstackradio.com/" target="_blank" rel="nofollow noopener noreferrer">Full Stack Radio</a></li> <li><a href="https://changelog.com/jsparty" target="_blank" rel="nofollow noopener noreferrer">JS Party</a></li> <li><a href="https://www.thisdot.co/modern-web" target="_blank" rel="nofollow noopener noreferrer">Modern Web</a></li> <li><a href="https://syntax.fm/" target="_blank" rel="nofollow noopener noreferrer">Syntax</a></li> <li><a href="https://twitter.com/toolsday" target="_blank" rel="nofollow noopener noreferrer">Toolsday</a></li> <li><a href="https://www.orbit.fm/weboftomorrow" target="_blank" rel="nofollow noopener noreferrer">Web of Tomorrow</a></li> </ul> <h1 id="5-pet-projects" style="position:relative;"><a href="#5-pet-projects" aria-label="5 pet projects permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>5. Pet projects</h1> <p>Many people, including myself, learn the best by doing the actual thing. I need to code to learn about something whether it’s a new technology or a library or simply a new API.</p> <p>Side projects (aka pet projects) are a great way to grow as a developer, both personally and professionally. They let you get out of your comfort zone, learn new skills, and exercise your creative muscles. But it can be hard to get anything done while juggling a day job, kids, friends, family, and countless other commitments.</p> <p>In the past, I’ve tried to cram side project work into the cracks between other items in my calendar. It was frustrating at best; completely ineffective at worst. I constantly felt like I was shortchanging the projects I was most passionate about. So what should we do?</p> <h2 id="start-with-something-small-but-keep-doing-it" style="position:relative;"><a href="#start-with-something-small-but-keep-doing-it" aria-label="start with something small but keep doing 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>Start with something small but keep doing it</h2> <p>It is definitely hard to start a project, harder to get back to it after some time and re-start it when you’ve been working on something completely different.</p> <p>So working on it a bit everyday keeps you on track while not bored or tired. If you keep doing it everyday it will be very easy to pick it where you left off since it is still in your mind.</p> <h2 id="no-deadlines-or-pressure" style="position:relative;"><a href="#no-deadlines-or-pressure" aria-label="no deadlines or pressure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>No deadlines or pressure</h2> <p>Don’t put deadlines or pressure on yourself for a side project. It is not a client engagement and you don’t want to loose your excitement about it really soon. Keep focusing on one or two task a week and finish it in a relaxed atmosphere.</p> <p>Take your time, have a juice (or beer, or coffee 😂) or fresh fruit handy and let the feeling of small holiday overcome the daily agile mindset. Close the Facebook, stop scrolling your Twitter feed and focus on what you promised yourself doing everyday.</p> <p>Once the habit is formed, the pressure is off and you start feeling the joy about doing something you feel passionate about.</p> <h2 id="shift-the-project-time-to-time" style="position:relative;"><a href="#shift-the-project-time-to-time" aria-label="shift the project time to time permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Shift the project time to time</h2> <p>Don’t work on something for too long. as we see new languages and technologies introduced everyday, we should shift our pet project to use different languages/technologies accordingly.</p> <p>I love frontend specifically, however try to keep track of security, azure, IoT, Hololens, etc. to be a bit more across other areas.</p> <p>My approach to this is to complete a project I start working on and then create a new one using the new tech I want to get familiar with.</p> <h2 id="talk-about-it-with-someone" style="position:relative;"><a href="#talk-about-it-with-someone" aria-label="talk about it with someone permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Talk about it with someone</h2> <p>This one doesn’t have to do anything with your pet project, but helps you find the weakness points and new challenges since it is exposed to people who love asking questions and learn new things.</p> <p>Even if it is an internal brown bag session, or presentation, or you are talking on an external event like meetups or conferences that project helps you gather the contents easily and demo something which even demo gods cannot prevent it (since you’ve played with it enough previously).</p> <h1 id="6-writing" style="position:relative;"><a href="#6-writing" aria-label="6 writing permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>6. Writing</h1> <p>There are a few reasons why writing an article helps you learn new things and put the subject into your long term memory.</p> <p>In short writing helps you:</p> <ul> <li>Slow down a little bit and focus on a topic.</li> <li>Think a little differently about something as you figure out how to explain it.</li> <li>Consider issues conceptually rather than in a more narrow or applied perspective.</li> <li>Research things more clearly, and document your research with links.</li> <li>Be more likely to remember things later.</li> <li>Have a good place to search when you can’t remember things later.</li> </ul> <p>I always consider this to myself (which I’ve learnt from a colleague of mine), do not write for others. Write for yourself and make sure you detail down everything you need to know at a later point in time. This then will help others too.</p> <h1 id="having-discipline" style="position:relative;"><a href="#having-discipline" aria-label="having discipline permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Having discipline</h1> <p>According to many philosophers, self disciple is like muscle, the more you train it, the more you enjoy the result. Even if you follow all the points I’ve mentioned so far, but don’t get yourself a good daily habit, it’s not going to help you.</p> <p>Think of how many times you started something and let it go half way through, or never finished it. It’s very important that you stick to a schedule and follow it no matter what.</p> <p>Here are a few tips I’ve learnt:</p> <ul> <li>Have a goal for yourself. Set milestones to reach that goal and evaluate your progress regularly.</li> <li>Do not compare yourself with others. There will be always people who are smarter than you. So try to be reasonable and consider your capabilities. At the same time don’t set your goals too low, stretch yourself a bit and push for a better self than what you were yesterday.</li> <li>Have self motivation, praise yourself for your big achievement and have a little punishment for when you fail to do something.</li> </ul> <h1 id="never-give-up-learn-to-wind-down" style="position:relative;"><a href="#never-give-up-learn-to-wind-down" aria-label="never give up learn to wind down permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Never give up, learn to wind down</h1> <p>At times you might feel frustrated about your progress. Or simply think you would never be able to keep up like other people around you.</p> <p>Let me tell you something, when that happens, you need to wind down. This is one of the many signs of a burn out. You might have pushed yourself too much and spent more than your body could have tolerated.</p> <p>This is probably good time for a break, a holiday or a change of direction. Never be afraid of a telling yourself you need a rest. The world never stops, so you should stop trying to chase it constantly.</p> <h1 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</h1> <p>I think I’ve covered most of the tricks I use to keep up with what’s happening in the frontend world. Please, please share your awesome ideas in the comments and I will try to keep updating this post with those to have a far better plan together 🖐.</p> <p>Another point is that these tricks will help you regardless of whether you’re a frontend developer or not 🔥.</p><![CDATA[Knock out your unused CSS]]>https://yashints.dev/blog/2019/05/07/unused-csshttps://yashints.dev/blog/2019/05/07/unused-cssTue, 07 May 2019 00:00:00 GMT<p>Unused CSS is a one of the issues most web applications suffer when it comes to performance and page load time.</p> <!--more--> <h2 id="disclaimer" style="position:relative;"><a href="#disclaimer" aria-label="disclaimer permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Disclaimer</h2> <p>Apart from option one in this post, most of the time you will need a tool and some manual intervention to be able to safely eliminate unused CSS. These tools are great in a sense that they will let you know what you don’t know; which classes in your template files are not used.</p> <p>These tools can’t work with complex scenarios like when you have JavaScript adding a DOM element in the template.</p> <p>They will have problems with dynamic templates in Single Page Applications (SPA) or when your template changes based on a state on your server side code.</p> <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>As I said, Unused CSS is a one of the issues most web applications suffer when it comes to performance and page load time.</p> <p>This even gets worst when you use a CSS library like Tailwind, or an older versions of CSS frameworks like <a href="https://getbootstrap.com/" target="_blank" rel="nofollow noopener noreferrer">Bootstrap</a> or <a href="https://material.io/design/" target="_blank" rel="nofollow noopener noreferrer">Material Design</a>.</p> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> most CSS frameworks have moved to modular structure where you could import only the part you need without having to include the whole bundle.</div></div> <h2 id="best-and-safest-approach" style="position:relative;"><a href="#best-and-safest-approach" aria-label="best and safest approach permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Best and safest approach</h2> <p>To my opinion, the best and safest approach is to be careful and get rid of any CSS file or part you remove from your HTML or template files. Do not be lazy or ignorance when it comes to tech debts like this. If you’re involved in a green field project, make sure you do not copy paste large chunks of CSS from somewhere you’re looking into without realising which parts are actually used.</p> <p>You can manually find your unused CSS using the <a href="https://developers.google.com/web/tools/chrome-devtools/" target="_blank" rel="nofollow noopener noreferrer">DevTools</a> in <a href="https://www.google.com/chrome/" target="_blank" rel="nofollow noopener noreferrer">Google Chrome</a> with following these steps:</p> <ol> <li>Open the Chrome DevTools using <kbd>F12</kbd> or <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>J</kbd> on Windows or <kbd>Command</kbd> <kbd>Option</kbd> <kbd>J</kbd> on Mac.</li> <li>Open the command menu by pressing <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>P</kbd> on Windows or <kbd>Command</kbd> <kbd>Shift</kbd> <kbd>J</kbd> on Mac.</li> <li>Type in “Coverage” and click on the “Show Coverage” option</li> <li>Click on reload button at the coverage tab.</li> <li>Select a CSS file from the Coverage tab which will open the file up in the Sources tab.</li> </ol> <p>Any CSS rule which has a solid green line on the left side is used. Those with a red line are not:</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: 63.33333333333333%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAgADBf/EABQBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAevoiijD/8QAGBAAAgMAAAAAAAAAAAAAAAAAABEBEiD/2gAIAQEAAQUCrOEI/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8Bp//EABYQAAMAAAAAAAAAAAAAAAAAAAEgMv/aAAgBAQAGPwKy3//EABkQAAMBAQEAAAAAAAAAAAAAAAABESFR0f/aAAgBAQABPyG78xcek4SMht4NT//aAAwDAQACAAMAAAAQhM//xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8QDJ//xAAWEQEBAQAAAAAAAAAAAAAAAAABEDH/2gAIAQIBAT8QU7P/xAAbEAEBAAIDAQAAAAAAAAAAAAABEQAhMUFx0f/aAAgBAQABPxAI0iXj4wpEY1XvF3QnuaAPWFUOctIATP/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Unused CSS" title="" src="/static/699d167c408e183c1938a4a412aa6a32/47311/csscoverage.jpg" srcset="/static/699d167c408e183c1938a4a412aa6a32/6f81f/csscoverage.jpg 270w, /static/699d167c408e183c1938a4a412aa6a32/09d21/csscoverage.jpg 540w, /static/699d167c408e183c1938a4a412aa6a32/47311/csscoverage.jpg 1080w, /static/699d167c408e183c1938a4a412aa6a32/0047d/csscoverage.jpg 1620w, /static/699d167c408e183c1938a4a412aa6a32/274e1/csscoverage.jpg 2160w, /static/699d167c408e183c1938a4a412aa6a32/be310/csscoverage.jpg 3227w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <div class="custom-block warning"><div class="custom-block-body"> <strong>Warning:</strong> Just because a rule isn’t used on this page doesn’t mean it’s not used elsewhere. You would ideally check the coverage on all pages and combine the result for a better overview. <br/></div></div> <h2 id="tools" style="position:relative;"><a href="#tools" aria-label="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>Tools</h2> <p>Some times you cannot adhere to ☝🏼 point because of various reasons. Such as you got involved in a brown field project or the code base is to large to be able to refactor and fix the issue in a timely fashion.</p> <p>In this case you might be looking at some tool to automate the process and do the clean-up systematically during build time. Fortunately there are many tools available which help you with this. I will cover some famous ones and mention a short list at the end for good measure 😉.</p> <h2 id="1-purifycss" style="position:relative;"><a href="#1-purifycss" aria-label="1 purifycss permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. PurifyCSS</h2> <p><a href="https://github.com/purifycss/purifycss" target="_blank" rel="nofollow noopener noreferrer">PurifyCSS</a> is tool that can analyse your files, go through code, and figure out what classes are not used. Most of the time when you have static HTML files this tool can eliminate nearly all your unused CSS.</p> <p>Apart from that, it can also work to a degree with Single Page Applications (SPA).</p> <h3 id="setup" style="position:relative;"><a href="#setup" aria-label="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>Setup</h3> <p><strong>Standalone</strong></p> <p>You can install this package via <code class="language-text">npm</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="48450462512372420000" data-toaster-class="gatsby-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 i -D purify-css`, `48450462512372420000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i <span class="token parameter variable">-D</span> purify-css</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And some basic usage:</p> <div class="gatsby-code-button-container" data-toaster-id="5409772508163835000" data-toaster-class="gatsby-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 purify from 'purify-css' const purify = require('purify-css') let content = '' let css = '' let options = { output: 'filepath/output.css', } purify(content, css, options)`, `5409772508163835000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> purify <span class="token keyword">from</span> <span class="token string">'purify-css'</span> <span class="token keyword">const</span> purify <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'purify-css'</span><span class="token punctuation">)</span> <span class="token keyword">let</span> content <span class="token operator">=</span> <span class="token string">''</span> <span class="token keyword">let</span> css <span class="token operator">=</span> <span class="token string">''</span> <span class="token keyword">let</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token string">'filepath/output.css'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token function">purify</span><span class="token punctuation">(</span>content<span class="token punctuation">,</span> css<span class="token punctuation">,</span> options<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you’re wondering well, this is not gonna help me, you might be right. But this is the simplest form. In fact in the <code class="language-text">purify</code> command, <code class="language-text">content</code> and <code class="language-text">css</code> parameters can be an <code class="language-text">Array</code> of <a href="https://github.com/isaacs/node-glob" target="_blank" rel="nofollow noopener noreferrer">glob</a> file patterns. Now you see the bigger picture and how this can help.</p> <p>Now let’s make it a bit more complex.</p> <p><strong>via Grunt</strong></p> <p>First you need to install the grunt package:</p> <div class="gatsby-code-button-container" data-toaster-id="93415005456593520000" data-toaster-class="gatsby-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 grunt-purifycss --save-dev`, `93415005456593520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> grunt-purifycss --save-dev</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And then use it:</p> <div class="gatsby-code-button-container" data-toaster-id="25041718915970535000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`grunt.initConfig({ purifycss: { options: {}, target: { src: ['path/to/*.html', 'path/to/*.js'], css: ['path/to/*.css'], dest: 'tmp/purestyles.css', }, }, })`, `25041718915970535000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">grunt<span class="token punctuation">.</span><span class="token function">initConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">purifycss</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'path/to/*.html'</span><span class="token punctuation">,</span> <span class="token string">'path/to/*.js'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'path/to/*.css'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">dest</span><span class="token operator">:</span> <span class="token string">'tmp/purestyles.css'</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This will handle even scenarios when you have a class added using JavaScript 😍. So this will be picked up:</p> <div class="gatsby-code-button-container" data-toaster-id="97484223110989870000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!-- html --> <!-- class directly on element --> <div class=&quot;button-active&quot;>click</div>`, `97484223110989870000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token comment">&lt;!-- html --></span> <span class="token comment">&lt;!-- class directly on element --></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>button-active<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>click<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Or in JavaScript:</p> <div class="gatsby-code-button-container" data-toaster-id="18577737645559144000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// javascript // Anytime your class name is together in your files, it will find it. \$(button).addClass('button-active')`, `18577737645559144000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// javascript</span> <span class="token comment">// Anytime your class name is together in your files, it will find it.</span> <span class="token function">$</span><span class="token punctuation">(</span>button<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addClass</span><span class="token punctuation">(</span><span class="token string">'button-active'</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Or even a bit more complex scenario:</p> <div class="gatsby-code-button-container" data-toaster-id="75414789796903830000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// Can detect if class is split. var half = 'button-'; \$(button).addClass(half + 'active'); // Can detect if class is joined. var dynamicClass = ['button', 'active'].join('-'); \$(button).addClass(dynamicClass); // Can detect various more ways, including all Javascript frameworks. // A React example. var classes = classNames({ 'button-active': this.state.buttonActive }); return ( <button className={classes}>Submit</button>; );`, `75414789796903830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// Can detect if class is split.</span> <span class="token keyword">var</span> half <span class="token operator">=</span> <span class="token string">'button-'</span><span class="token punctuation">;</span> <span class="token function">$</span><span class="token punctuation">(</span>button<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addClass</span><span class="token punctuation">(</span>half <span class="token operator">+</span> <span class="token string">'active'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Can detect if class is joined.</span> <span class="token keyword">var</span> dynamicClass <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'button'</span><span class="token punctuation">,</span> <span class="token string">'active'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">$</span><span class="token punctuation">(</span>button<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addClass</span><span class="token punctuation">(</span>dynamicClass<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Can detect various more ways, including all Javascript frameworks.</span> <span class="token comment">// A React example.</span> <span class="token keyword">var</span> classes <span class="token operator">=</span> <span class="token function">classNames</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token string-property property">'button-active'</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>buttonActive <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>button className<span class="token operator">=</span><span class="token punctuation">{</span>classes<span class="token punctuation">}</span><span class="token operator">></span>Submit<span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block warning"><div class="custom-block-body"> <strong>Warning</strong>: The Webpack plugin for purifycss is deprecated. You will need to use Purgecss which I will go through later on.</div></div> <p><strong>CLI</strong></p> <p>Install the CLI:</p> <div class="gatsby-code-button-container" data-toaster-id="72548929938250840000" data-toaster-class="gatsby-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 purify-css`, `72548929938250840000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> purify-css</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And you can see the help using <code class="language-text">-h</code> param:</p> <div class="gatsby-code-button-container" data-toaster-id="19050196206623846000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`purifycss -h purifycss <css> <content> [option] Options: -m, --min Minify CSS [boolean] [default: false] -o, --out Filepath to write purified css to [string] -i, --info Logs info on how much css was removed [boolean] [default: false] -r, --rejected Logs the CSS rules that were removed [boolean] [default: false] -w, --whitelist List of classes that should not be removed [array] [default: []] -h, --help Show help [boolean] -v, --version Show version number [boolean]`, `19050196206623846000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">purifycss <span class="token parameter variable">-h</span> purifycss <span class="token operator">&lt;</span>css<span class="token operator">></span> <span class="token operator">&lt;</span>content<span class="token operator">></span> <span class="token punctuation">[</span>option<span class="token punctuation">]</span> Options: -m, <span class="token parameter variable">--min</span> Minify CSS <span class="token punctuation">[</span>boolean<span class="token punctuation">]</span> <span class="token punctuation">[</span>default: false<span class="token punctuation">]</span> -o, <span class="token parameter variable">--out</span> Filepath to <span class="token function">write</span> purified css to <span class="token punctuation">[</span>string<span class="token punctuation">]</span> -i, <span class="token parameter variable">--info</span> Logs info on how much css was removed <span class="token punctuation">[</span>boolean<span class="token punctuation">]</span> <span class="token punctuation">[</span>default: false<span class="token punctuation">]</span> -r, <span class="token parameter variable">--rejected</span> Logs the CSS rules that were removed <span class="token punctuation">[</span>boolean<span class="token punctuation">]</span> <span class="token punctuation">[</span>default: false<span class="token punctuation">]</span> -w, <span class="token parameter variable">--whitelist</span> List of classes that should not be removed <span class="token punctuation">[</span>array<span class="token punctuation">]</span> <span class="token punctuation">[</span>default: <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">]</span> -h, <span class="token parameter variable">--help</span> Show <span class="token builtin class-name">help</span> <span class="token punctuation">[</span>boolean<span class="token punctuation">]</span> -v, <span class="token parameter variable">--version</span> Show version number <span class="token punctuation">[</span>boolean<span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="stats" style="position:relative;"><a href="#stats" aria-label="stats permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Stats</h3> <p>This library can help you big time. It’s pretty effective and works on complex scenarios. But as I mentioned before you will need to have good tests to able to find out if anything is messed up after clean-up.</p> <blockquote> <p>In terms of Boostrap, PurifyCSS can reduce up to ~ 33.8% of unused CSS.</p> </blockquote> <h2 id="2-purgecss" style="position:relative;"><a href="#2-purgecss" aria-label="2 purgecss permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Purgecss</h2> <p><a href="https://github.com/FullHuman/Purgecss" target="_blank" rel="nofollow noopener noreferrer">Purgecss</a> is another powerful tool to remove unused CSS. It can be used as part of your development workflow. It comes with a JavaScript API, a CLI, and plugins for popular build tools.</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>You can install <code class="language-text">Purgecss</code> globally or using <code class="language-text">npx</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="85649172321126450000" data-toaster-class="gatsby-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 i -g Purgecss`, `85649172321126450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i <span class="token parameter variable">-g</span> Purgecss</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And use it:</p> <div class="gatsby-code-button-container" data-toaster-id="69830266817772780000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`Purgecss --css <css> --content <content> [option]`, `69830266817772780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">Purgecss <span class="token parameter variable">--css</span> <span class="token operator">&lt;</span>css<span class="token operator">></span> <span class="token parameter variable">--content</span> <span class="token operator">&lt;</span>content<span class="token operator">></span> <span class="token punctuation">[</span>option<span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>As you can see, the API is very similar to <code class="language-text">PurifyCSS</code>, but of course options would be different.</p> <h3 id="via-webpack" style="position:relative;"><a href="#via-webpack" aria-label="via webpack permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Via Webpack</h3> <p>You should install the plugin first:</p> <div class="gatsby-code-button-container" data-toaster-id="58634412270189530000" data-toaster-class="gatsby-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 i -D Purgecss-webpack-plugin`, `58634412270189530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i <span class="token parameter variable">-D</span> Purgecss-webpack-plugin</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And the add it to your Webpack config:</p> <div class="gatsby-code-button-container" data-toaster-id="31711273918163775000" data-toaster-class="gatsby-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 path = require('path') const glob = require('glob') const ExtractTextPlugin = require('extract-text-webpack-plugin') const PurgecssPlugin = require('Purgecss-webpack-plugin') const PATHS = { src: path.join(__dirname, 'src'), } module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.join(__dirname, 'dist'), }, module: { rules: [ { test: /\.css\$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader?sourceMap', }), }, ], }, plugins: [ new ExtractTextPlugin('[name].css?[hash]'), new PurgecssPlugin({ paths: glob.sync(\`\${PATHS.src}/**/*\`, { nodir: true, }), }), ], }`, `31711273918163775000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> glob <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'glob'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> ExtractTextPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'extract-text-webpack-plugin'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> PurgecssPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'Purgecss-webpack-plugin'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token constant">PATHS</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">src</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'src'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">entry</span><span class="token operator">:</span> <span class="token string">'./src/index.js'</span><span class="token punctuation">,</span> <span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token string">'bundle.js'</span><span class="token punctuation">,</span> <span class="token literal-property property">path</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'dist'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">rules</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.css$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">use</span><span class="token operator">:</span> ExtractTextPlugin<span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">fallback</span><span class="token operator">:</span> <span class="token string">'style-loader'</span><span class="token punctuation">,</span> <span class="token literal-property property">use</span><span class="token operator">:</span> <span class="token string">'css-loader?sourceMap'</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 literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token keyword">new</span> <span class="token class-name">ExtractTextPlugin</span><span class="token punctuation">(</span><span class="token string">'[name].css?[hash]'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">PurgecssPlugin</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">paths</span><span class="token operator">:</span> glob<span class="token punctuation">.</span><span class="token function">sync</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><span class="token constant">PATHS</span><span class="token punctuation">.</span>src<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/**/*</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">nodir</span><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 punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For more information please refer to <a href="https://www.Purgecss.com/" target="_blank" rel="nofollow noopener noreferrer">their documents</a>.</p> <h2 id="3-uncss" style="position:relative;"><a href="#3-uncss" aria-label="3 uncss permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. UnCSS</h2> <p><a href="https://github.com/uncss/uncss" target="_blank" rel="nofollow noopener noreferrer">UnCSS</a> is another tool to help you remove your unused CSS. But this tool is a bit different in sense that it will load your files in <a href="https://github.com/jsdom/jsdom" target="_blank" rel="nofollow noopener noreferrer">jsdom</a>, then will parse all the stylesheets with PostCSS.</p> <p>Once finished, <code class="language-text">document.querySelector</code> will filter out selectors that are not found in the HTML files. And finally, the remaining rules are converted back to CSS.</p> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> The best thing about this library which I am in love with, is their <a href="https://uncss-online.com/" target="_blank" rel="nofollow noopener noreferrer">unofficial server</a> where you can paste your HTML and CSS it will show you the shortened CSS online.</div></div> <h3 id="install" style="position:relative;"><a href="#install" aria-label="install permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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</h3> <p>Again you can use <code class="language-text">npm</code> to install it or use <code class="language-text">npx</code>:</p> <div class="gatsby-highlight" data-language="text"><pre style="counter-reset: linenumber NaN" class="language-text line-numbers"><code class="language-text">npm i -g uncss</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can use UnCSS with node:</p> <div class="gatsby-code-button-container" data-toaster-id="41924317758650710000" data-toaster-class="gatsby-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 uncss = require('uncss') var files = [ 'my', 'array', 'of', 'HTML', 'files', 'or', 'http://urls.com', ], options = { ignore: ['#added_at_runtime', /test\-[0-9]+/], media: [ '(min-width: 700px) handheld and (orientation: landscape)', ], csspath: '../public/css/', raw: 'h1 { color: green }', stylesheets: [ 'lib/bootstrap/dist/css/bootstrap.css', 'src/public/css/main.css', ], ignoreSheets: [/fonts.googleapis/], timeout: 1000, htmlroot: 'public', report: false, banner: false, uncssrc: '.uncssrc', userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)', inject: function(window) { window.document .querySelector('html') .classList.add('no-csscalc', 'csscalc') }, } uncss(files, options, function(error, output) { console.log(output) }) /* Look Ma, no options! */ uncss(files, function(error, output) { console.log(output) }) /* Specifying raw HTML */ var rawHtml = '...' uncss(rawHtml, options, function(error, output) { console.log(output) })`, `41924317758650710000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> uncss <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'uncss'</span><span class="token punctuation">)</span> <span class="token keyword">var</span> files <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">'my'</span><span class="token punctuation">,</span> <span class="token string">'array'</span><span class="token punctuation">,</span> <span class="token string">'of'</span><span class="token punctuation">,</span> <span class="token string">'HTML'</span><span class="token punctuation">,</span> <span class="token string">'files'</span><span class="token punctuation">,</span> <span class="token string">'or'</span><span class="token punctuation">,</span> <span class="token string">'http://urls.com'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">ignore</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'#added_at_runtime'</span><span class="token punctuation">,</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">test\-[0-9]+</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">media</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'(min-width: 700px) handheld and (orientation: landscape)'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">csspath</span><span class="token operator">:</span> <span class="token string">'../public/css/'</span><span class="token punctuation">,</span> <span class="token literal-property property">raw</span><span class="token operator">:</span> <span class="token string">'h1 { color: green }'</span><span class="token punctuation">,</span> <span class="token literal-property property">stylesheets</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'lib/bootstrap/dist/css/bootstrap.css'</span><span class="token punctuation">,</span> <span class="token string">'src/public/css/main.css'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">ignoreSheets</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">fonts.googleapis</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">timeout</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token literal-property property">htmlroot</span><span class="token operator">:</span> <span class="token string">'public'</span><span class="token punctuation">,</span> <span class="token literal-property property">report</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">banner</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">uncssrc</span><span class="token operator">:</span> <span class="token string">'.uncssrc'</span><span class="token punctuation">,</span> <span class="token literal-property property">userAgent</span><span class="token operator">:</span> <span class="token string">'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)'</span><span class="token punctuation">,</span> <span class="token function-variable function">inject</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">window</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> window<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">'html'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'no-csscalc'</span><span class="token punctuation">,</span> <span class="token string">'csscalc'</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">uncss</span><span class="token punctuation">(</span>files<span class="token punctuation">,</span> options<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> output</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>output<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">/* Look Ma, no options! */</span> <span class="token function">uncss</span><span class="token punctuation">(</span>files<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> output</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>output<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">/* Specifying raw HTML */</span> <span class="token keyword">var</span> rawHtml <span class="token operator">=</span> <span class="token string">'...'</span> <span class="token function">uncss</span><span class="token punctuation">(</span>rawHtml<span class="token punctuation">,</span> options<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> output</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>output<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Or use their build flows which supports Gulp, Grunt and Broccoli (unfortunately no Webpack 😔). For more information about how to setup those tools refer to <a href="https://github.com/uncss/uncss" target="_blank" rel="nofollow noopener noreferrer">their documentation</a>.</p> <h2 id="comparison" style="position:relative;"><a href="#comparison" aria-label="comparison permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Comparison</h2> <p>Now let’s compare these tools and see their pros and cons.</p> <h3 id="purifycss" style="position:relative;"><a href="#purifycss" aria-label="purifycss permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>PurifyCSS</h3> <p>Some people believe the biggest problem with PurifyCSS is lack of modularity. Some think it’s also its biggest benefit 🤷🏽‍♂️. It can work with any file type not just HTML. It can also find selectors which are added using JavaScript.</p> <p>Unfortunately since every word is considered a selector, this can end up in a lot of false positives and make the resulting CSS a bit larger than it should be.</p> <h3 id="purgecss" style="position:relative;"><a href="#purgecss" aria-label="purgecss permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Purgecss</h3> <p>Purgecss fixes the above issue by providing the possibility to create an extractor. This is simply a function which takes content of a file and extracts the list of CSS selectors used in it.</p> <p>The extractor can be used as a parser that returns an AST (abstract syntax tree) and looks through it to find any CSS selectors. This is the way <code class="language-text">purge-from-html</code> works. You can specify which selectors you want to use for each file type, allowing you to get the most accurate results. Additionally, you can use the default or legacy extractor, which will mimic PurifyCSS’s behaviour.</p> <p>That said, Purgecss has some drawbacks too. FIrst and foremost you will need to write a custom extractor for frameworks like <code class="language-text">Tailwind</code>. Another problem is when you use a syntax highlighter like <a href="https://prismjs.com/" target="_blank" rel="nofollow noopener noreferrer">primjs</a>, in which case you will have to whitelist your token classes using a property called <code class="language-text">whitelistPatternsChildren</code>.</p> <p>Another point to consider is that Purgecss doesn’t have an extractor for JavaScript files. But because of its modularity, developers can create custom extractors for frameworks like <em>Angular</em>, <em>React</em> or <em>Vue</em>.</p> <h3 id="uncss" style="position:relative;"><a href="#uncss" aria-label="uncss permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>UnCSS</h3> <p>Because of its HTML emulation and JavaScript execution, UnCSS is effective at removing unused selectors from web applications. However, its emulation can have a cost in terms of performance and practicality.</p> <p>At this point in time, UnCSS is probably the most accurate tool to remove unused CSS if you do not use server-side rendering.</p> <h2 id="other-tools" style="position:relative;"><a href="#other-tools" aria-label="other 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>Other tools</h2> <p>Here is of other tools you can consider:</p> <ul> <li><a href="https://www.jitbit.com/unusedcss/" target="_blank" rel="nofollow noopener noreferrer">GitBit</a>: an online tool which crawls your root page and stylesheets linked in it.</li> <li><a href="https://unused-css.com/" target="_blank" rel="nofollow noopener noreferrer">UnusedCSS</a>: another online tool which easily find and removes unused CSS rules</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>Although these tools are really helpful in terms of finding unused CSS, each has its own drawbacks and you will need to be careful to not end up with a broken UI.</p> <p>Hope you’ve gained just a tiny bit insight on how to find your unused CSS and deploy them to space 😁👇.</p> <blockquote class="twitter-tweet"><p lang="en" dir="ltr">Deploy... to Space?!? 🚀🔥🤯 <a href="https://t.co/zb8jNPs5zs">https://t.co/zb8jNPs5zs</a></p>&mdash; StackBlitz (@stackblitz) <a href="https://twitter.com/stackblitz/status/1123816907881242624?ref_src=twsrc%5Etfw">May 2, 2019</a></blockquote><![CDATA[Removing duplicates from arrays in JavaScript]]>https://yashints.dev/blog/2019/04/24/dedupe-array-jshttps://yashints.dev/blog/2019/04/24/dedupe-array-jsWed, 24 Apr 2019 00:00:00 GMT<p>There are multiple ways to remove duplicates from an array with JavaScript. But, it’s very important to know the details of how efficient they, especially if you’re dealing with large arrays.</p> <!--more--> <h2 id="simplest-approach" style="position:relative;"><a href="#simplest-approach" aria-label="simplest approach permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Simplest approach</h2> <p>The easiest way is to use ES6’s (ECMAScript 2015) <code class="language-text">Set</code> object. This let’s you store unique values of any type. It will automatically remove duplicates for us, isn’t that sweet?</p> <div class="gatsby-code-button-container" data-toaster-id="58353092555605656000" data-toaster-class="gatsby-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 fruit = [ 'apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries', 'avo', 'avo', ]; let uniqueFruit = [...new Set(fruit)]; console.log(uniqueFruit); // ['apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries']`, `58353092555605656000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> fruit <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">'apple'</span><span class="token punctuation">,</span> <span class="token string">'orange'</span><span class="token punctuation">,</span> <span class="token string">'avo'</span><span class="token punctuation">,</span> <span class="token string">'pear'</span><span class="token punctuation">,</span> <span class="token string">'cherries'</span><span class="token punctuation">,</span> <span class="token string">'strawberries'</span><span class="token punctuation">,</span> <span class="token string">'avo'</span><span class="token punctuation">,</span> <span class="token string">'avo'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">let</span> uniqueFruit <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span>fruit<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>uniqueFruit<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ['apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries']</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Here we had to use the <code class="language-text">spread</code> operator to get an array from <code class="language-text">Set</code> again.</p> <h2 id="smart-but-naïve-approach" style="position:relative;"><a href="#smart-but-na%C3%AFve-approach" aria-label="smart but naïve approach permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Smart but naïve approach</h2> <p>We can use the built in filter method of ES5 to achieve the same:</p> <div class="gatsby-code-button-container" data-toaster-id="48252675968474400000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const fruits = [ 'apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries', 'avo', 'avo', ]; const uniqueFruit = fruits.filter( (item, i, arr) => { return arr.indexOf(item) == i; } ); console.log(uniqueFruit); // ['apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries']`, `48252675968474400000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> fruits <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">'apple'</span><span class="token punctuation">,</span> <span class="token string">'orange'</span><span class="token punctuation">,</span> <span class="token string">'avo'</span><span class="token punctuation">,</span> <span class="token string">'pear'</span><span class="token punctuation">,</span> <span class="token string">'cherries'</span><span class="token punctuation">,</span> <span class="token string">'strawberries'</span><span class="token punctuation">,</span> <span class="token string">'avo'</span><span class="token punctuation">,</span> <span class="token string">'avo'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> uniqueFruit <span class="token operator">=</span> fruits<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token parameter">item<span class="token punctuation">,</span> i<span class="token punctuation">,</span> arr</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> arr<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token operator">==</span> i<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>uniqueFruit<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ['apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries']</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>What we’re doing here is not that complex. We’re going through each element and check if the first position of this item in the array is equal to current position. Since these two positions are different for duplicate items, they will get filtered and we end up with a unique array 🤩.</p> <div class="custom-block warning"><div class="custom-block-body"> <strong>Warning:</strong> This approach is not that efficient for large arrays (quadratic time).</div></div> <h2 id="hash-table-to-rescue" style="position:relative;"><a href="#hash-table-to-rescue" aria-label="hash table to rescue permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Hash table to rescue</h2> <p>This approach is to place each item in a <code class="language-text">hashtable</code> and then check for it’s presence. This gives a linear time, but has at least two pitfalls:</p> <ul> <li>Since hash keys can only be string, this code doesn’t distinguish number and numeric strings. This means <code class="language-text">['1', 1]</code> will return <code class="language-text">[1]</code>.</li> <li>Because of ☝🏼, all objects will be equal 🤦‍♂️.</li> </ul> <div class="gatsby-code-button-container" data-toaster-id="23456249521525050000" data-toaster-class="gatsby-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 unique(fruits) { var seen = {}; return fruits.filter(item => { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); }`, `23456249521525050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">unique</span><span class="token punctuation">(</span><span class="token parameter">fruits</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> seen <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">return</span> fruits<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">item</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> seen<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token boolean">false</span> <span class="token operator">:</span> <span class="token punctuation">(</span>seen<span class="token punctuation">[</span>item<span class="token punctuation">]</span> <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 punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="the-hybrid-and-best-approach" style="position:relative;"><a href="#the-hybrid-and-best-approach" aria-label="the hybrid and best approach permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 hybrid and best approach</h2> <p>A better approach combines both approaches. It uses hash lookups for primitive types and linear search for objects:</p> <div class="gatsby-code-button-container" data-toaster-id="18583469469815173000" data-toaster-class="gatsby-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 unique(fruits) { var prims = { boolean: {}, number: {}, string: {}, }, objs = []; return fruits.filter(item => { var type = typeof item; if (type in prims) return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true); else return objs.indexOf(item) >= 0 ? false : objs.push(item); }); }`, `18583469469815173000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">unique</span><span class="token punctuation">(</span><span class="token parameter">fruits</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> prims <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">boolean</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">number</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">string</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> objs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">return</span> fruits<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">item</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">var</span> type <span class="token operator">=</span> <span class="token keyword">typeof</span> item<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>type <span class="token keyword">in</span> prims<span class="token punctuation">)</span> <span class="token keyword">return</span> prims<span class="token punctuation">[</span>type<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token boolean">false</span> <span class="token operator">:</span> <span class="token punctuation">(</span>prims<span class="token punctuation">[</span>type<span class="token punctuation">]</span><span class="token punctuation">[</span>item<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">return</span> objs<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token operator">>=</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token boolean">false</span> <span class="token operator">:</span> objs<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>item<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="sort--unique" style="position:relative;"><a href="#sort--unique" aria-label="sort unique permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Sort &#x26; unique</h2> <p>Another option is to sort the array and then remove the items equal to the one right after:</p> <div class="gatsby-code-button-container" data-toaster-id="64285918653507570000" data-toaster-class="gatsby-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 unique(fruits) { return fruits .sort() .filter((item, pos, ary) => { return !pos || item != ary[pos - 1]; }); }`, `64285918653507570000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">unique</span><span class="token punctuation">(</span><span class="token parameter">fruits</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> fruits <span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item<span class="token punctuation">,</span> pos<span class="token punctuation">,</span> ary</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">!</span>pos <span class="token operator">||</span> item <span class="token operator">!=</span> ary<span class="token punctuation">[</span>pos <span class="token operator">-</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 punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This item is similar to hash table approach, it does not work with objects. And more importantly we have to change the original array which is a side effect and not a good way to go about this.</p> <h2 id="using-reduce" style="position:relative;"><a href="#using-reduce" aria-label="using reduce permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 reduce</h2> <div class="gatsby-code-button-container" data-toaster-id="74461200349849200000" data-toaster-class="gatsby-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 uniqueFruits = fruits.reduce((a, b) => { if (a.indexOf(b) < 0) a.push(b); return a; }, []); console.log(uniqueFruits); // ['apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries']`, `74461200349849200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> uniqueFruits <span class="token operator">=</span> fruits<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</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>a<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span> <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> a<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> a<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> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>uniqueFruits<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ['apple', 'orange', 'avo', 'pear', 'cherries', 'strawberries']</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This approach uses an accumulator to see whether the item is previously inserted into it or not. Very similar to filter approach we introduced earlier, a bit faster though.</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>These are just a couple of ways of doing the same operation. But as you can see, very different in nature and support in browsers. Pick carefully and happy coding.</p><![CDATA[Web performance statistics infographic]]>https://yashints.dev/blog/2019/04/14/webperf-statistics-inforgraphichttps://yashints.dev/blog/2019/04/14/webperf-statistics-inforgraphicSun, 14 Apr 2019 10:38:01 GMT<p>A while back, Nick Galov from <a href="https://hostingtribunal.com" target="_blank" rel="nofollow noopener noreferrer">Hostingtribunal.com</a> contacted me to let me know they had created an inforgraphic photo for web performance statistics.</p> <!--more--> <p>This infographic contains some very useful statistics regarding page load time and some advice on where to focus for improvements.</p> <p>This was after I’d given my talk on web performance at <a href="https://ndcsydney.com/talk/need-for-speed-8-performance-tuning-of-your-web-application/" target="_blank" rel="nofollow noopener noreferrer">NDC Sydney</a>, so the timing was really good.</p> <h1 id="what-happened" style="position:relative;"><a href="#what-happened" aria-label="what happened permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 happened</h1> <p>I got so busy during the last couple of months that I rarely blogged and more was focused on my talk for <a href="https://ndcporto.com/talk/need-for-speed-8-performance-tuning-of-your-web-application/" target="_blank" rel="nofollow noopener noreferrer">NDC Porto</a>.</p> <h1 id="what-next" style="position:relative;"><a href="#what-next" aria-label="what 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>What next</h1> <p>Here you go, this is the infographic promised to be published on my blog. Hope this helps people find their motive to move towards a faster web.</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/ef4ac175a9a0d7e91e2bb79356ddb6a6/4b190/Website-Speed-IG.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 1916.296296296296%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAF/ABQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAQBAgMFBv/EABgBAAMBAQAAAAAAAAAAAAAAAAABAgME/9oADAMBAAIQAxAAAAG2VJ6OVgVHLmc5p6AOVyZLggZrDNYMi5cq111VrlhpuWtebpVHRNEy2qXjjk0nVfTSKC4P1NrWzpceATvawpLknm2Oa7qlCoy9/RWk8eeqB74TMjBYT5c8xXSe6edA6mzjsvyI2WtzsZSucdsHQmMtbklTnE1itiC55llp2wYECpd0rpFIkm2MxYmqgVN4I597lQWUrVjVwUJaufUNp5J0wP/EACIQAAICAgIDAAMBAAAAAAAAAAECAAMREgQTFDEyBRAhM//aAAgBAQABBQJtAoK5wk7BOxZ2iBC011aMczOAPnZoWabNABF9TE1ms1rIIWHAgExMQNGsBBOS1FNZ6UYeHTC4NuMQerQqW98HpeRS0bk1GWc7U101mmpa5d1h0UEaJD71SpdqZbxK7Wa1FcnDiWpXt2qSNgGTdupM5CyvlMiDmWS92tcqQvGuZBcdrUGVwkPsddK9tct41dzH6RiwHq1mUC1Mzuqshs44h5tSwV19OY2M0cew19FubqzU/GI6P5PyH+5wYuBMiOu0Fa4X0YPhPkwfK/Jg+U+TF+U+e22Cx4bnBSlCoprj1oGStSorEsGrI6BVZJb/AFwqmarlhgj9GE7TOJ2Cf2atNRGVxALCNLIeS08pp5bQeiP14dwHh2meBdP/xAAfEQACAQMFAQAAAAAAAAAAAAAAEQECECEDEhMgMUH/2gAIAQMBAT8BFJj5dG3HSM9HFnbIroQ7sUW4zYR4SR4SMmohFXoyTmqOesmjT+GzSv8A/8QAHxEAAgIBBQEBAAAAAAAAAAAAAAEQESECAxITMRRB/9oACAECAQE/AYzDccozFlxUpFmCjEWcipouOw5D9EP0Q0LTgdmnyEdGk+fbFq3v05b5ZZ//xAAuEAACAAQEBQMCBwAAAAAAAAAAAQIRITEQEjKRAyJRcYEgM0ITgiM0QVJhcpL/2gAIAQEABj8CsmL8NFJGh7Gh7GmLYoSwl0KCm5+i5+heeFcKxksyKPGqwopE2aU+8ZTgw+Iyz3MjKYfUyxOIrw3go4nKPpU1vwjkWZGZ8WT6TJ8SJ9pnKnuVZqwhh5fuLwGaq7GVtT7kpTnhnjNRafkvC4ehpJNpeRQyhopFIYdmZolKhC6VMqcKImczZdrzgoc0ukz3EZopzP4Ip0rheFF69sE3xIcv7WicOWZKr7Gb63NKxd7lDNClU+O5KKXWhw72Li/qezGvtPZif2n5eP8AyVqacHi8XQdMGPD4l4TllI0IfIr9SkKJuCZoe50FOJmt7l5lfUqPwWZYpjVk52NRpRpRpXostyy3Pjuf/8QAJBABAAICAgIDAAIDAAAAAAAAAQARITFBYVFxEIGRwfGh0eH/2gAIAQEAAT8hyq84iyQvmyIaQV5i/qMbJC3h7mQmvMJTERsW+iX2Co+E/JwKfqeg+ogyj7iy5cWXG7b9sTWoK8CUgFiecRWBhrEwsxUtc4OGBHGZi1QypLujqVX8kRkV7hmrh4puUPMP7/K5lyhAlTM34h3A/OJawAHhf9TRNZlkWCDAH7T+IYhVZXGZQ452EQWVKUrcwByubxm11xRc4D91N2b9Rtkge7Cks/ogVOCtQlY3tDFQPTESmScCOOWDob9MdD7WKlWThs93AQmbzGlgGmDVRuXKBagbGilBLUKkaGru0tioo28Qrqxogt5Eb833BQhCvggjbpWGoHNdIACxQzL1ttnVZirjwAt2IZIsGIzlTPr9pU0wdwmFUzZm/EL7ePJV3APMxuaSLp/5lVgpsgzcvDXMyrHEpiTT+YaNX9Tle98GjpaauLV5HUvus3yZumiX5E35Jqm3fvzLwaJXlAcnuaItp7WEp0h9Eqi/KDEV7ajCyUoWlCDlWN3M2qL8Jja0gkFriIbKl5h5ODd3ETL8mo4+oFBk9Sta/wAwC658jDTuDg+5uBsW+2NvGUKHVS7xOiBHJ4inCeUt4SjfymuiVPXx1DGtF4SH/9oADAMBAAIAAwAAABDn/LMzDsw0HA4ELDz7LIKgGT5XGAFAEfwDB8wDJM3TDDGEGs//xAAgEQADAAIBBQEBAAAAAAAAAAAAAREhMRBBUWFxsYGh/9oACAEDAQE/EFUpOF4RCQSTIPJn2OrAkoOdBFRER3DKh5HSj7iIbfGCu/w6j2Nuj+FEJ70WkW2lwoQyVQ0uT6mz4dmU0ssyvLNUefw2i0VNmUXn0Txf4iLIU80hGf/EAB8RAAMBAQACAgMAAAAAAAAAAAABESExgbFRcUGRof/aAAgBAgEBPxBpW0wWnRNzRiXBMq6hOjdCs0bor5HzUUyNYJTpDiKEl0r8Nk6SFwVa17INqzolMF9vCSr8+BOqshOMR6fRwj0HCE6sIJiFa1Z5OA096cISe+2X2P8AbMUL+DviU8EEH//EACYQAQACAgIBBAIDAQEAAAAAAAEAESExQWFRcYGhsZHhwdHwEPH/2gAIAQEAAT8QWNQwQe4AeXT9cxEKvXmKIg7M5i4g1fDKkSjV4P3A2AtVdl+0FmTMpKKpZeT/AHiJoXY1gYLoKVTfv3CNiG7NpQtPu8qgJlTw6RovcBtAAsopWB89k5LXxqCSDdZwXLiwWpRogpgJTYxgaS0Cbgqctfv1goAgW6KeSYYLD2el4iMQ1QC8uo2lE5HEUt12MuGvuJ2rCJlsd31GIJ3tAtRLHr7O4XuJj6LCiVhsHFtLi73qKcnai6xx7xKQChQ1BSgmhFQp0PELAE2seL7bIhQEEumNp0G5BjjDiVkHeQ/KlB2VazkVRGF8BVYPizffrNKEJSvCPioKsIui75E6qFUKSlj8woVDmm8PmCjABQdGCp3NNvpncQjaZD+uOCw0sO6ruUxysEOdTsQCm/iswi0MFcBaPg1gmfM2sFPuUQKkdhBTvuJkweRDfudSnFZQtO7TV1L4UGEJMMKCLpd5p7jKnCrH/mDBYVBQvmb2apNYH6SLdKSQ1nYVHIrq3rfev3DJLvAVQXddfE2iAyhz+IKEQFBckTeaxbQvPvE9nZW5TGDeshfXcs21yKcYz/71EVtZjYfXH5hAIBlSrjxAKLLDlceZzGQ7nPEVDYjpJR2VjJyKMICq7Lm+/wDalbNqqzoWpmFFw1yvkmQKDhAFe8SV3xuL8RLEKsiGq11FUerJKR+WolpGFgCtfUYRKvIZFvjcVxpUXUdBgHj1guucGifSAXM+LHxFKxeawjS2N0NemI4iZApn4l5Xr5dfErn26boxxf8AEIVrTealMTZ3KHRvXOuY3eOcmpzEfSHnF+DjvGepimhweZ4FdR2CrvJWsQChRNiUxNkMNswV/MegddC+lxwoNWf2i1CN28tYYeIApRQfcHaFUb4i0wGhLOeYvkSh1fmJduQpd75Nw2voiaPiKCEaRD0ZjQxWPvxGjEFNC766gyLBpapX9xCngWinpM7ZSssp84+pYu6OeD4/coSzjlzKyHCDR5edkLsF5y0x2DpxiLwyr5u+kZWUuucjn5iHB9G5l2CpZbr0ICiIFufiybAI9/qLKYq+cfMCKtPDbA/2TKzVTRH/AAZjCz/pKT/j9o2aHf6z/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Web performance infographic" title="" src="/static/ef4ac175a9a0d7e91e2bb79356ddb6a6/4b190/Website-Speed-IG.jpg" srcset="/static/ef4ac175a9a0d7e91e2bb79356ddb6a6/6f81f/Website-Speed-IG.jpg 270w, /static/ef4ac175a9a0d7e91e2bb79356ddb6a6/09d21/Website-Speed-IG.jpg 540w, /static/ef4ac175a9a0d7e91e2bb79356ddb6a6/4b190/Website-Speed-IG.jpg 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" decoding="async" /> </a> </span></p><![CDATA[Fixing: unable to deploy to npm: 'you must be logged in']]>https://yashints.dev/blog/2019/02/15/npm-publish-issuehttps://yashints.dev/blog/2019/02/15/npm-publish-issueFri, 15 Feb 2019 16:00:00 GMT<p>Recently I created a small library with <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular</a> which I wanted to publish to <code class="language-text">npm</code> (the node package manager). However, when I had everything in place from a build perspective using <a href="https://travis-ci.com/" target="_blank" rel="nofollow noopener noreferrer">Travis CI</a> in my GitHub repo, it was failing to publish the package with a <code class="language-text">401</code> login error.</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 guess I used a lot of terms and concepts you might not be familiar with. So let’s take a step back and see what are those.</p> <p>I have a GitHub repository where the code is kept. You can setup a build for your repository using <a href="https://travis-ci.com/" target="_blank" rel="nofollow noopener noreferrer">Travis CI</a> if you enable Travic CI on your repo and create a file named <code class="language-text">.travis.yml</code> in root directory, with each push to your branch the code is built and even published.</p> <p>I am not going to explain how to setup a build pipeline using Travic CI. You can find instructions on <a href="https://docs.travis-ci.com" target="_blank" rel="nofollow noopener noreferrer">their documentation here</a>. The docs are very comprehensive and detailed with examples on some of the most common project types.</p> <p>The build is very simple and doesn’t require any special steps. However, when you want to publish it (to <code class="language-text">npm</code> in my case), I had to generate a authentication token and encrypt it using Travic CI CLI so I can put it in my build file.</p> <p><strong>Note</strong>: Do not put the token as is in your build file, since anyone can use it when you commit your code and push it up stream.</p> <p>I followed <a href="https://docs.travis-ci.com/user/deployment/npm/" target="_blank" rel="nofollow noopener noreferrer">the instructions here</a> to setup deploy steps for my project.</p> <p>However, when I pushed my code, although the build was successful, I was getting an <code class="language-text">401</code> error during deployment:</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/4fc9b8a67b6d51ff584cc7417f7c37a5/7f09e/npm-401.jpg" style="display: block" target="_blank" rel="noopener" > <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/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABy5AD/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFxABAAMAAAAAAAAAAAAAAAAAAQAQQf/aAAgBAQABPyHCNf/aAAwDAQACAAMAAAAQ+C//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAYEAEBAQEBAAAAAAAAAAAAAAABABEhYf/aAAgBAQABPxAVDXhIFMt8v//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="error 401 deploying to npm" title="" src="/static/4fc9b8a67b6d51ff584cc7417f7c37a5/47311/npm-401.jpg" srcset="/static/4fc9b8a67b6d51ff584cc7417f7c37a5/6f81f/npm-401.jpg 270w, /static/4fc9b8a67b6d51ff584cc7417f7c37a5/09d21/npm-401.jpg 540w, /static/4fc9b8a67b6d51ff584cc7417f7c37a5/47311/npm-401.jpg 1080w, /static/4fc9b8a67b6d51ff584cc7417f7c37a5/7f09e/npm-401.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" decoding="async" /> </a> </span></p> <h2 id="why-it-happens" style="position:relative;"><a href="#why-it-happens" aria-label="why it happens permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 it happens</h2> <p>So it seems a while back Travis has moved away from <code class="language-text">.org</code> domain and uses <code class="language-text">.com</code>. However, the CLI is still defaulting to <code class="language-text">.org</code> as so when you encrypt your API key, it will be for wrong domain.</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>Fortunately you can easily fix this using <code class="language-text">--com</code> flag when you’re encrypting your key. So from the root of your project just use these commands to re-encrypt your key with right domain:</p> <div class="gatsby-code-button-container" data-toaster-id="77099399988955860000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`travis login --com travis encrypt --com <token> --add 'deploy.api_key'`, `77099399988955860000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">travis login <span class="token parameter variable">--com</span> travis encrypt <span class="token parameter variable">--com</span> <span class="token operator">&lt;</span>token<span class="token operator">></span> <span class="token parameter variable">--add</span> <span class="token string">'deploy.api_key'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p><strong>Tip</strong>: If you’re a windows user like me, you can use <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10" target="_blank" rel="nofollow noopener noreferrer"><em>Windows 10 WSL</em></a> (windows subsystem for Linux) and it works like a charm.</p> <p>Once you’ve applied the commands, simply commit and push your code up.</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/fa999739109d7fb667eefdac2c63ddf1/934bb/npmdeployok.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 31.851851851851855%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABzIAD/8QAFRABAQAAAAAAAAAAAAAAAAAAEEH/2gAIAQEAAQUCh//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABcQAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQEAAT8huUMp/9oADAMBAAIAAwAAABD4L//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAQEBAQEBAAAAAAAAAAAAAAERAJFBYf/aAAgBAQABPxAuGT3JGIcz8HN//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="successful deployment to npm" title="" src="/static/fa999739109d7fb667eefdac2c63ddf1/47311/npmdeployok.jpg" srcset="/static/fa999739109d7fb667eefdac2c63ddf1/6f81f/npmdeployok.jpg 270w, /static/fa999739109d7fb667eefdac2c63ddf1/09d21/npmdeployok.jpg 540w, /static/fa999739109d7fb667eefdac2c63ddf1/47311/npmdeployok.jpg 1080w, /static/fa999739109d7fb667eefdac2c63ddf1/934bb/npmdeployok.jpg 1089w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Hope this helps you save some time and have a great weekend.</p><![CDATA[Setting Google Analytics for Angular applications]]>https://yashints.dev/blog/2019/02/12/angular-ga-tagmanagerhttps://yashints.dev/blog/2019/02/12/angular-ga-tagmanagerTue, 12 Feb 2019 00:00:00 GMT<p>Many a times we want to add some sort of analytics to our applications and for me the most obvious choice would be Google Analytics.</p> <!--more--> <p>Google is in the process of phasing out the legacy <code class="language-text">ga.js</code> and <code class="language-text">analytics.js</code> products that ships with Google Analytics, with its new, more flexible <strong>Global Site Tag</strong> <code class="language-text">gtag.js</code> that ships with Google Tag Manager.</p> <p>So let’s see what it takes to set it up and I assure you it will be really quick.</p> <h2 id="get-a-tracking-id-from-google-analytics" style="position:relative;"><a href="#get-a-tracking-id-from-google-analytics" aria-label="get a tracking id from google analytics permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Get a tracking id from Google Analytics</h2> <p>If you already have a property in <a href="https://analytics.google.com" target="_blank" rel="nofollow noopener noreferrer">Google Analytics</a>, simply get it from admin dashboard in property list. If not follow <a href="https://support.google.com/analytics/answer/1042508?hl=en" target="_blank" rel="nofollow noopener noreferrer">these steps</a> to create one.</p> <p>Tracking id is in this form usually:</p> <blockquote> <p>UA-XXXXXXXXX-X</p> </blockquote> <p>In the same place you can click on tracking code page and you will see a code snippet which you can copy and put in inside your <code class="language-text">index.html</code> file:</p> <div class="gatsby-code-button-container" data-toaster-id="29547634846931505000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!-- Global site tag (gtag.js) - Google Analytics --> <script async src=&quot;https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X&quot;></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-XXXXXXXXX-X'); </script>`, `29547634846931505000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> Global site <span class="token function">tag</span> <span class="token punctuation">(</span>gtag<span class="token punctuation">.</span>js<span class="token punctuation">)</span> <span class="token operator">-</span> Google Analytics <span class="token operator">--</span><span class="token operator">></span> <span class="token operator">&lt;</span>script <span class="token keyword">async</span> src<span class="token operator">=</span><span class="token string">"https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator">&lt;</span>script<span class="token operator">></span> window<span class="token punctuation">.</span>dataLayer <span class="token operator">=</span> window<span class="token punctuation">.</span>dataLayer <span class="token operator">||</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">gtag</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>dataLayer<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>arguments<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token function">gtag</span><span class="token punctuation">(</span><span class="token string">'js'</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">gtag</span><span class="token punctuation">(</span><span class="token string">'config'</span><span class="token punctuation">,</span> <span class="token string">'UA-XXXXXXXXX-X'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We don’t need the last line since will be configuring it from our app. So remove it:</p> <div class="gatsby-code-button-container" data-toaster-id="93339083912521170000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!-- Global site tag (gtag.js) - Google Analytics --> <script async src=&quot;https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X&quot;></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); </script> `, `93339083912521170000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> Global site <span class="token function">tag</span> <span class="token punctuation">(</span>gtag<span class="token punctuation">.</span>js<span class="token punctuation">)</span> <span class="token operator">-</span> Google Analytics <span class="token operator">--</span><span class="token operator">></span> <span class="token operator">&lt;</span>script <span class="token keyword">async</span> src<span class="token operator">=</span><span class="token string">"https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator">&lt;</span>script<span class="token operator">></span> window<span class="token punctuation">.</span>dataLayer <span class="token operator">=</span> window<span class="token punctuation">.</span>dataLayer <span class="token operator">||</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">gtag</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>dataLayer<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>arguments<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token function">gtag</span><span class="token punctuation">(</span><span class="token string">'js'</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span> </code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="configuring-our-project" style="position:relative;"><a href="#configuring-our-project" aria-label="configuring our 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>Configuring our project</h2> <p>If you have an existing application simply ignore the installation process. I will be creating a new app:</p> <div class="gatsby-code-button-container" data-toaster-id="32936572331522230000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng new analytics`, `32936572331522230000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng new analytics</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>From here select yes for routing:</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/8abdbf21bbd1f08f36ecf3dc480161c1/cda38/routing.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 19.62962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAEABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAEDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAc2kIB//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAZEAEAAgMAAAAAAAAAAAAAAAABABARMUH/2gAIAQEAAT8hzuKva//aAAwDAQACAAMAAAAQc8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAACAwEAAAAAAAAAAAAAAAABEQAhQRD/2gAIAQEAAT8QZWO7Clkef//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Enable routing" title="" src="/static/8abdbf21bbd1f08f36ecf3dc480161c1/47311/routing.jpg" srcset="/static/8abdbf21bbd1f08f36ecf3dc480161c1/6f81f/routing.jpg 270w, /static/8abdbf21bbd1f08f36ecf3dc480161c1/09d21/routing.jpg 540w, /static/8abdbf21bbd1f08f36ecf3dc480161c1/47311/routing.jpg 1080w, /static/8abdbf21bbd1f08f36ecf3dc480161c1/cda38/routing.jpg 1410w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>When it comes to capturing changes in a SPA app it is important to listen to changes in routes and events. We would ideally listen to those and send them to analytics, but we want to do it only once for the entire application.</p> <p>The best place for that is in root component. So open your <code class="language-text">AppComponent</code> and add the code below to it:</p> <div class="gatsby-code-button-container" data-toaster-id="6470235167208415000" data-toaster-class="gatsby-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 { filter } from 'rxjs/operators'; declare var gtag; export class AppComponent { constructor(router: Router) { const navEndEvents = router.events.pipe( filter( event => event instanceof NavigationEnd ) ); navEndEvents.subscribe( (event: NavigationEnd) => { gtag('config', 'UA-XXXXXXXXX-X', { page_path: event.urlAfterRedirects, }); } ); } }`, `6470235167208415000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> filter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs/operators'</span><span class="token punctuation">;</span> <span class="token keyword">declare</span> <span class="token keyword">var</span> gtag<span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppComponent</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span>router<span class="token operator">:</span> Router<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> navEndEvents <span class="token operator">=</span> router<span class="token punctuation">.</span>events<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span> <span class="token function">filter</span><span class="token punctuation">(</span> event <span class="token operator">=></span> event <span class="token keyword">instanceof</span> <span class="token class-name">NavigationEnd</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> navEndEvents<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span> <span class="token punctuation">(</span>event<span class="token operator">:</span> NavigationEnd<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">gtag</span><span class="token punctuation">(</span><span class="token string">'config'</span><span class="token punctuation">,</span> <span class="token string">'UA-XXXXXXXXX-X'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> page_path<span class="token operator">:</span> event<span class="token punctuation">.</span>urlAfterRedirects<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We are not doing anything special here, first, we get a reference to router in the constructor. Then we filter its events to only get navigation end events.</p> <p>Afterwards we subscribe to those and use the one liner from Google Analytics code snippet and add one parameter to it which is its <code class="language-text">URL</code>.</p> <p>Now let’s test it by defining some routes:</p> <div class="gatsby-code-button-container" data-toaster-id="12677829186886025000" data-toaster-class="gatsby-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 routes: Routes = [ { path: '', component: HomeComponent }, { path: 'about', component: AboutComponent }, ]; @NgModole({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], }) export class AppRoutingModile {}`, `12677829186886025000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">const</span> routes<span class="token operator">:</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> HomeComponent <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">'about'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> AboutComponent <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModole</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span>RouterModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span>routes<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> exports<span class="token operator">:</span> <span class="token punctuation">[</span>RouterModule<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">class</span> <span class="token class-name">AppRoutingModile</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And that’s it. If you start the app using <code class="language-text">ng serve</code> from command line you should start receiving events in your analytics dashboard.</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/a07ddb0d4b20630731c4fe0d273f01a4/90191/route-change.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 37.407407407407405%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAHABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAEDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd+sJB//xAAWEAADAAAAAAAAAAAAAAAAAAAAECH/2gAIAQEAAQUCKv/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABkQAAMAAwAAAAAAAAAAAAAAAAABEUFhkf/aAAgBAQABPyEmSXSaP//aAAwDAQACAAMAAAAQA8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAwEBAAAAAAAAAAAAAAABABExkbH/2gAIAQEAAT8QorCDeNQYY7P/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Route change logs to GA" title="" src="/static/a07ddb0d4b20630731c4fe0d273f01a4/47311/route-change.jpg" srcset="/static/a07ddb0d4b20630731c4fe0d273f01a4/6f81f/route-change.jpg 270w, /static/a07ddb0d4b20630731c4fe0d273f01a4/09d21/route-change.jpg 540w, /static/a07ddb0d4b20630731c4fe0d273f01a4/47311/route-change.jpg 1080w, /static/a07ddb0d4b20630731c4fe0d273f01a4/0047d/route-change.jpg 1620w, /static/a07ddb0d4b20630731c4fe0d273f01a4/274e1/route-change.jpg 2160w, /static/a07ddb0d4b20630731c4fe0d273f01a4/90191/route-change.jpg 2255w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p><![CDATA[The essential difference between pure and impure pipes in Angular and why that matters]]>https://yashints.dev/blog/2019/01/31/angular-pure-pipeshttps://yashints.dev/blog/2019/01/31/angular-pure-pipesThu, 31 Jan 2019 00:00:00 GMT<p>When writing a custom pipe in Angular you can specify whether you define a pure or an impure pipe:</p> <!--more--> <div class="gatsby-code-button-container" data-toaster-id="83791526508436750000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@Pipe({ name: 'myCustomPipe', pure: false/true <----- here (default is \`true\`) }) export class MyCustomPipe {}`, `83791526508436750000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">@<span class="token function">Pipe</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'myCustomPipe'</span><span class="token punctuation">,</span> <span class="token literal-property property">pure</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token operator">/</span><span class="token boolean">true</span> <span class="token operator">&lt;</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span> <span class="token function">here</span> <span class="token punctuation">(</span><span class="token keyword">default</span> is <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">true</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">export</span> <span class="token keyword">class</span> <span class="token class-name">MyCustomPipe</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Angular has a pretty good documentation on pipes that you can find here. But as it often happens with documentation the clearly reasoning for division is missing. In this article I’d like to fill that hole and demonstrate the difference from the prospective of functional programming which shows where the idea of pure and impure pipes come from. Besides learning the difference you will know how it affects the performance and this knowledge will help you write efficient and performant pipes.</p> <blockquote> <p>I work as a developer advocate at <a href="https://angular-grid.ag-grid.com/?utm_source=mehraban&#x26;utm_medium=blog&#x26;utm_campaign=angularpurepipes" target="_blank" rel="nofollow noopener noreferrer">ag-Grid</a>. If you’re curios to learn about data grids or looking for the ultimate Angular data grid solution, get in touch or give it a try with the guide “<a href="https://medium.com/ag-grid/get-started-with-angular-grid-in-5-minutes-83bbb14fac93" target="_blank" rel="nofollow noopener noreferrer">Get started with Angular grid in 5 minutes</a>”. I’m happy to answer any questions you may have.</p> </blockquote> <h2 id="a-pure-function" style="position:relative;"><a href="#a-pure-function" aria-label="a pure function permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>A pure function</h2> <p>There’s so much information on the web about functional programming that probably every developer knows what a pure function is. For myself I define a pure function as a function that doesn’t have an internal state. It means that all operations it performs are not affected by that state and given the same input parameters and produces the same deterministic output.</p> <p>Here are the two versions of a function that adds numbers. The first one is pure and the second one is impure:</p> <div class="gatsby-code-button-container" data-toaster-id="82440957751532180000" data-toaster-class="gatsby-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 addPure = (v1, v2) => { return v1 + v2; }; const addImpure = (() => { let state = 0; return v => { return (state += v); }; })();`, `82440957751532180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">addPure</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">v1<span class="token punctuation">,</span> v2</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> v1 <span class="token operator">+</span> v2<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> addImpure <span class="token operator">=</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> state <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token parameter">v</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span>state <span class="token operator">+=</span> v<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If I call both functions with the same input, say number <code class="language-text">1</code>, the first one will produce the same output <code class="language-text">2</code> on every call:</p> <div class="gatsby-code-button-container" data-toaster-id="69683965663906685000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`addPure(1, 1); // 2 addPure(1, 1); // 2 addPure(1, 1); // 2`, `69683965663906685000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">addPure</span><span class="token punctuation">(</span><span class="token number">1</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 comment">// 2</span> <span class="token function">addPure</span><span class="token punctuation">(</span><span class="token number">1</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 comment">// 2</span> <span class="token function">addPure</span><span class="token punctuation">(</span><span class="token number">1</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 comment">// 2</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>while the second one produces different output:</p> <div class="gatsby-code-button-container" data-toaster-id="31515576773136966000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`addImpure(1); // 1 addImpure(1); // 2 addImpure(1); // 3`, `31515576773136966000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">addImpure</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 comment">// 1</span> <span class="token function">addImpure</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 comment">// 2</span> <span class="token function">addImpure</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 comment">// 3</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>So the key takeaway here is that even if the input doesn’t change the impure function can produce different output. <strong>It means that we cannot use the input value to determine if the output will change.</strong></p> <p>Let’s see another interesting consequence of the fact that a function has a state. Suppose you have a <code class="language-text">calculator</code> object that takes as a parameter the function to add numbers and uses it to make calculations:</p> <div class="gatsby-code-button-container" data-toaster-id="1912056197668965400" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class Calculator { constructor(addFn) { this.addFn = addFn; } add(v1, v2) { return this.addFn(v1, v2); } }`, `1912056197668965400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Calculator</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">addFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>addFn <span class="token operator">=</span> addFn<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token parameter">v1<span class="token punctuation">,</span> v2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addFn</span><span class="token punctuation">(</span>v1<span class="token punctuation">,</span> v2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If the function is pure and doesn’t have a state it can be safely shared with many instances of the <code class="language-text">Calculator</code> classes:</p> <div class="gatsby-code-button-container" data-toaster-id="46632231919617890000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class Calculator { constructor(addFn) { this.addFn = addFn; } add(v1, v2) { return this.addFn(v1, v2); } } const c1 = new Calculator(add); const c2 = new Calculator(add); c1.add(1, 1); // 2 c2.add(1, 1); // 2`, `46632231919617890000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Calculator</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">addFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>addFn <span class="token operator">=</span> addFn<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token parameter">v1<span class="token punctuation">,</span> v2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addFn</span><span class="token punctuation">(</span>v1<span class="token punctuation">,</span> v2<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> c1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Calculator</span><span class="token punctuation">(</span>add<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> c2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Calculator</span><span class="token punctuation">(</span>add<span class="token punctuation">)</span><span class="token punctuation">;</span> c1<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">1</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 comment">// 2</span> c2<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">1</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 comment">// 2</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>However, <strong>the function that is not pure can’t be shared</strong>. This is because the operations performed by one instance of <code class="language-text">Calculator</code> will affect the function state and consequently the result of operations performed by the other instance of <code class="language-text">Calculator</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="64818833322057376000" data-toaster-class="gatsby-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 add = (() => { let state = 0; return v => { return (state += v); }; })(); class Calculator { constructor(addFn) { this.addFn = addFn; } add(v1, v2) { return this.addFn(v1), this.addFn(v2); } } const c1 = new Calculator(add); const c2 = new Calculator(add); c1.add(1, 1); // 2 c2.add(1, 1); // 4 // <------ here we have \`4\` instead of \`2\``, `64818833322057376000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">const</span> add <span class="token operator">=</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> state <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token parameter">v</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span>state <span class="token operator">+=</span> v<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">class</span> <span class="token class-name">Calculator</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">addFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>addFn <span class="token operator">=</span> addFn<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token parameter">v1<span class="token punctuation">,</span> v2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addFn</span><span class="token punctuation">(</span>v1<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addFn</span><span class="token punctuation">(</span>v2<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> c1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Calculator</span><span class="token punctuation">(</span>add<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> c2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Calculator</span><span class="token punctuation">(</span>add<span class="token punctuation">)</span><span class="token punctuation">;</span> c1<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">1</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 comment">// 2</span> c2<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">1</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 comment">// 4 // &lt;------ here we have `4` instead of `2`</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can see that the first call to <code class="language-text">add</code> method on the second instance produces the output <code class="language-text">4</code> instead of expected <code class="language-text">2</code>.</p> <p>So let’s recap what we’ve learnt so far about functions:</p> <h3 id="pure" style="position:relative;"><a href="#pure" aria-label="pure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Pure:</h3> <ul> <li>input parameters value determine the output so if input parameters don’t change the output doesn’t change</li> <li>can be shared across many usages without affecting the output result</li> </ul> <h3 id="impure" style="position:relative;"><a href="#impure" aria-label="impure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Impure:</h3> <ul> <li>cannot use the input value to determine if the output will change</li> <li>cannot be shared because the internal state can be affected from outside</li> </ul> <h2 id="applying-that-knowledge-to-angular-pipes" style="position:relative;"><a href="#applying-that-knowledge-to-angular-pipes" aria-label="applying that knowledge to angular pipes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Applying that knowledge to Angular pipes</h2> <p>Suppose we defined one custom pipe and make it pure:</p> <div class="gatsby-code-button-container" data-toaster-id="73945646721790820000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@Pipe({ name: 'myCustomPipe', pure: true, }) export class MyCustomPipe {}`, `73945646721790820000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">@<span class="token function">Pipe</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'myCustomPipe'</span><span class="token punctuation">,</span> <span class="token literal-property property">pure</span><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 keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">MyCustomPipe</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And use it like this in a component template:</p> <div class="gatsby-code-button-container" data-toaster-id="65912254905358060000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{% raw %} <span>{{ v1 | customPipe }}</span> <span>{{ v2 | customPipe }}</span> {% endraw %}`, `65912254905358060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html">{% raw %} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>{{ v1 | customPipe }}<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>span</span><span class="token punctuation">></span></span>{{ v2 | customPipe }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> {% endraw %}</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Since the pipe is pure it means that there’s no internal state and the pipe can be shared. How can Angular leverage that? Even though there are two usages in the template Angular <strong>can create only one pipe instance which can be shared between the usages</strong>. For those who know from my previous articles <a href="https://blog.angularindepth.com/the-mechanics-of-property-bindings-update-in-angular-39c0812bc4ce" target="_blank" rel="nofollow noopener noreferrer">what a component factory</a> is here is the relevant compiled code which defines only one pipe definition:</p> <div class="gatsby-code-button-container" data-toaster-id="3147686924706727400" data-toaster-class="gatsby-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 View_AppComponent_0(_l) { return viewDef_1(0, [ pipeDef_2(0, ExponentialStrengthPipe_3, []), // node index 0 ...`, `3147686924706727400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">View_AppComponent_0</span><span class="token punctuation">(</span><span class="token parameter">_l</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">viewDef_1</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token function">pipeDef_2</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> ExponentialStrengthPipe_3<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 comment">// node index 0</span> <span class="token operator">...</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>which is shared in <a href="https://blog.angularindepth.com/the-mechanics-of-dom-updates-in-angular-3b2970d5c03d#163d" target="_blank" rel="nofollow noopener noreferrer">updateRenderer function</a>:</p> <div class="gatsby-code-button-container" data-toaster-id="29035424203613626000" data-toaster-class="gatsby-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(_ck,_v) { unwrapValue_7(_v,4,0,_ck(_v,5,0,nodeValue_8(_v, 0),...); ^^^ unwrapValue_7(_v,8,0,_ck(_v,9,0,nodeValue_8(_v, 0),...);`, `29035424203613626000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">_ck<span class="token punctuation">,</span>_v</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">unwrapValue_7</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">_ck</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">nodeValue_8</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span> <span class="token number">0</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 operator">^</span><span class="token operator">^</span><span class="token operator">^</span> <span class="token function">unwrapValue_7</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">_ck</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">9</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">nodeValue_8</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span> <span class="token number">0</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <div class="gatsby-highlight" data-language="text"><pre style="counter-reset: linenumber NaN" class="language-text line-numbers"><code class="language-text"> ^^^</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Here is the <code class="language-text">unwrapValue</code> function is used to retrieve the current pipe value by calling <code class="language-text">transform</code> on it. The pipe instance is referenced by the node index in the <code class="language-text">nodeValue</code> function call — which is <code class="language-text">0</code> in this case.</p> <p>However, if we define the pipe as impure assuming there’s some internal state:</p> <div class="gatsby-code-button-container" data-toaster-id="65343486010869680000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@Pipe({ name: 'myCustomPipe', pure: false, }) export class MyCustomPipe {}`, `65343486010869680000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">@<span class="token function">Pipe</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'myCustomPipe'</span><span class="token punctuation">,</span> <span class="token literal-property property">pure</span><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 keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">MyCustomPipe</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We don’t want the pipe in the second usage to be affected by the call to it in the first usage so angular <strong>creates two instances</strong> of the pipe each with its own state:</p> <div class="gatsby-code-button-container" data-toaster-id="72170631113645860000" data-toaster-class="gatsby-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 View_AppComponent_0(_l) { return viewDef(0, [ ... pipeDef_2(0, ExponentialStrengthPipe, []) // node index 4 ... pipeDef_2(0, ExponentialStrengthPipe, []) // node index 8`, `72170631113645860000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">View_AppComponent_0</span><span class="token punctuation">(</span><span class="token parameter">_l</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">viewDef</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token operator">...</span> <span class="token function">pipeDef_2</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> ExponentialStrengthPipe<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// node index 4</span> <span class="token operator">...</span> <span class="token function">pipeDef_2</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> ExponentialStrengthPipe<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// node index 8</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>and it is <strong>not shared</strong> in <a href="https://blog.angularindepth.com/the-mechanics-of-dom-updates-in-angular-3b2970d5c03d#163d" target="_blank" rel="nofollow noopener noreferrer">updateRenderer function</a>:</p> <div class="gatsby-code-button-container" data-toaster-id="63431665203213990000" data-toaster-class="gatsby-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(_ck,_v) { unwrapValue_7(_v,4,0,_ck(_v,5,0,nodeValue_8(_v, 4),...); ^^^ unwrapValue_7(_v,8,0,_ck(_v,9,0,nodeValue_8(_v, 8),...); ^^^`, `63431665203213990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">_ck<span class="token punctuation">,</span>_v</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">unwrapValue_7</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">_ck</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">nodeValue_8</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span> <span class="token number">4</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 operator">^</span><span class="token operator">^</span><span class="token operator">^</span> <span class="token function">unwrapValue_7</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">_ck</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span><span class="token number">9</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token function">nodeValue_8</span><span class="token punctuation">(</span>_v<span class="token punctuation">,</span> <span class="token number">8</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 operator">^</span><span class="token operator">^</span><span class="token operator">^</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can see here that instead of node index <code class="language-text">0</code> now for each usage Angular uses different node index — <code class="language-text">4</code> and <code class="language-text">8</code> respectively.</p> <p>The second point from the summary in the first chapter was that with pure functions we can use the input value to determine if the output will change while with impure functions we can’t have such guarantee.</p> <p>In Angular we pass input parameters to a pipe like this:</p> <div class="gatsby-code-button-container" data-toaster-id="64274343762728714000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{% raw %} <span>{{ v1 | customPipe:param1:param2 }}</span> {% endraw %}`, `64274343762728714000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html">{% raw %} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>{{ v1 | customPipe:param1:param2 }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> {% endraw %}</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>So if a pipe is pure we know that it’s output (through transform method) is strictly determined by the input parameters. If the input parameters don’t change the output won’t change. This reasoning allows Angular to optimize the pipe and call <code class="language-text">transform</code> method <strong>only when input parameters change</strong>.</p> <p>But if a pipe is impure and has internal state the same parameters do not guarantee that same output as demonstrated with the call to impure <code class="language-text">addFn</code> function in the first chapter. It means that Angular is forced to trigger <code class="language-text">transform</code> function on a pipe instance on every <a href="https://blog.angularindepth.com/angulars-digest-is-reborn-in-the-newer-version-of-angular-718a961ebd3e" target="_blank" rel="nofollow noopener noreferrer">digest</a>.</p> <p>A good example of impure pipe is the <a href="https://angular.io/api/common/AsyncPipe" target="_blank" rel="nofollow noopener noreferrer">AsyncPipe</a> from <code class="language-text">@angular/common</code> package. This pipe has internal state that holds an underlying subscription created by subscribing to the observable passed to the pipe as a parameter. Because of that Angular has to create a new instance for each pipe usage to prevent different observables affecting each other. And also has to call <code class="language-text">transform</code> method on each digest because even thought the observable parameter may not change the new value may arrive through this observable that needs to be processed by change detection.</p> <p>The other two impure pipes are <a href="https://angular.io/api/common/JsonPipe" target="_blank" rel="nofollow noopener noreferrer">JsonPipe</a> and <a href="https://angular.io/api/common/SlicePipe" target="_blank" rel="nofollow noopener noreferrer">SlicePipe</a>. Angular puts an additional restriction on a pipe to be considered pure — the input to the pipe cannot be mutable. If the input is mutable, a pipe need to be re-evaluated on every <a href="https://blog.angularindepth.com/angulars-digest-is-reborn-in-the-newer-version-of-angular-718a961ebd3e" target="_blank" rel="nofollow noopener noreferrer">digest</a> because an input object can be mutated without changing the object reference (the pipe parameter stays the same). And that’s exactly why both <code class="language-text">JsonPipe</code> and <code class="language-text">SlicePipe</code> pipes are not considered pure despite not having an internal state.</p> <p>The rest of Angular default pipes are pure.</p> <h2 id="conclusion" style="position:relative;"><a href="#conclusion" aria-label="conclusion permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conclusion</h2> <p>So as we’ve seen impure pipes can have significant performance hit if not used wisely and carefully. The performance hit comes from the fact that Angular creates multiple instances of an impure pipe and also calls it’s <code class="language-text">transform</code> method on every digest cycle.</p> <p>I hope by reading the article you now know the difference between the two types, how Angular handles both of them and what mental model should you use when designing and implementing your custom pipes.</p> <p>Also, check out another good article that demonstrates other advantages of pure pipes in Angular is <a href="https://blog.angularindepth.com/tiny-angular-pipe-to-make-any-function-memoizable-f6c8fa917f2f" target="_blank" rel="nofollow noopener noreferrer">The benefits of using pure pipes in Angular templates</a>.</p><![CDATA[Amazon Virtual Concierge]]>https://yashints.dev/blog/2019/01/14/amazon-virtual-hosthttps://yashints.dev/blog/2019/01/14/amazon-virtual-hostMon, 14 Jan 2019 00:00:00 GMT<p>Recently we (at <a href="https://readify.net/" target="_blank" rel="nofollow noopener noreferrer">Readify</a>) had a chance to have a go at two very interesting problems and we decided to use a few interesting technologies to solve them.</p> <!--more--> <p>After a long discussion and using a categorisation approach we decided to focus on these:</p> <h2 id="problem-1" style="position:relative;"><a href="#problem-1" aria-label="problem 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Problem #1</h2> <p>Many companies have an open office with hot desk policy. That is a challenging problem at times when the number of seats are less than their staff count. This can happen if they have working from home policies or are a consultancy like us.</p> <p>So the problem of knowing if there is an available desk is very important for people, to know whether they can come to office or should work from home in case it’s very busy. Basically utilisation of people’s time is the most important aspect of every business.</p> <h2 id="problem-2" style="position:relative;"><a href="#problem-2" aria-label="problem 2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Problem #2</h2> <p>Some companies do not have a reception. This is not a bad thing and sometimes makes the atmosphere more friendly.</p> <p>Usually the process looks a bit like this. When someone wants to come to the office for a meeting or an interview, they might have to go through concierge to get a pass. When that happened they can go to their desired floor (sometimes elevator is controlled by passes) and use that pass to open the door and enter the office. However, once they are in, someone needs to get notified and attend to them.</p> <p>We thought let’s try to see if we can fix this and make sure visitors feels 1. welcomed, and 2. amazed by the usage of technology.</p> <h2 id="initial-research" style="position:relative;"><a href="#initial-research" aria-label="initial research permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Initial research</h2> <p>To try to solve desk occupancy problem, we spiked two different technologies, <a href="https://en.wikipedia.org/wiki/Bluetooth_low_energy_beacon" target="_blank" rel="nofollow noopener noreferrer">Bluetooth beacons</a> and WiFi probe requests. We realised we could identify who is sitting where using a mobile app and a beacon. We could also identify the area they are sitting at using their WiFi signal. But we decided to not go further on this since it arose some privacy concerns we needed to tackle before progressing. It also needed a bit more thinking in terms of how exactly we wanted to tackle the challenge and whether we could solve it without knowing the exact location of a specific person. 🤔</p> <p>For our second problem we had a brain storming session where we went through many ideas and finally decided to use a mixture of service to solve this problem:</p> <ul> <li>Facial recognition (for detecting a returning visitor or a staff)</li> <li>A sort of Dialog component (like a Bot) to communicate</li> <li>Speech component so we can talk to people</li> <li>And an integration component where we fetch the required information about our people</li> </ul> <p>At first we focused on Azure service because they had everything we needed. <a href="https://azure.microsoft.com/en-au/services/cognitive-services/face/" target="_blank" rel="nofollow noopener noreferrer">Face API</a>, <a href="https://dev.botframework.com/" target="_blank" rel="nofollow noopener noreferrer">Microsoft Bot framework</a> and <a href="https://azure.microsoft.com/en-au/services/cognitive-services/speech-services/" target="_blank" rel="nofollow noopener noreferrer">Cognitive Speech services</a> where already available. We decided to give them a shot using a PoC (proof of concept) and see what we can do in one week.</p> <p>We had success using all of those services and were going to write an application utilising all of the above, when we found out about the <a href="https://docs.sumerian.amazonaws.com/articles/concierge-experience/" target="_blank" rel="nofollow noopener noreferrer">Amazon Virtual Concierge</a> from some of our people who attended the Amazon ReInvent in US.</p> <p>They had a virtual host and were using literally every service we had used from Azure, but obviously everything AWS. Rekognition, Lex, Poly and more services to support different scenarios. Funny enough it also had a solution for our first problem, but we didn’t pursue it further => 🔐.</p> <h2 id="creating-a-proof-of-concept-aka-poc" style="position:relative;"><a href="#creating-a-proof-of-concept-aka-poc" aria-label="creating a proof of concept aka poc permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 proof of concept (aka PoC)</h2> <p>We decided to play around with their <a href="https://docs.sumerian.amazonaws.com/articles/virtual-concierge/" target="_blank" rel="nofollow noopener noreferrer">virtual concierge starter pack</a> and try to customise it. This starter package uses:</p> <ol> <li><strong>Amazon Sumerian:</strong> lets you create and run virtual reality (VR), augmented reality (AR), and 3D applications quickly and easily without requiring any specialized programming or 3D graphics expertise. It has an online editor and you can write your scenarios in JavaScript 😎. Two component are being used from Sumerian: <ul> <li>Host component</li> <li>Speech component</li> <li>Point of interest (utilises computer vision so the host can maintain eye contact wherever the visitor moves)</li> </ul> </li> <li><strong>JavaScript computer vision library JSFeet</strong>: for face detection</li> <li><strong>Amazon DynamoDB</strong>: to keep a database of people, which is queried later when the face is detected</li> <li><strong>Amazon S3</strong>: to store any required asset</li> <li><strong>Amazon Lex</strong>: to filter a user’s speech into different request types</li> <li><strong>Amazon Poly</strong>: speech to text</li> </ol> <h2 id="structure-of-the-application-and-workflows" style="position:relative;"><a href="#structure-of-the-application-and-workflows" aria-label="structure of the application and workflows permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Structure of the application and workflows</h2> <p>The PoC consists of a couple of scenes and some flows to connect those:</p> <ul> <li><em>Welcome scene</em>: What is shown at start-up. This scene has the introduction spoken by the virtual host and also is the trigger point of all other scenes</li> <li><em>Visitor scene</em>: Where some options are shown to visitors and they can choose from them</li> <li><em>Staff verification scene</em>: Where we get the staff name and ask visitor whether we’ve got it right</li> <li><em>Notification scene</em>: Where we get the visitor name and notify the person they are here to visit</li> <li><em>Staff scene</em>: Where we detect staff and welcome them back (also messages like happy birthday, happy anniversary, etc would be delivered here)</li> <li><em>Info scene</em>: Where anybody can get information about what options are available and how to move around</li> <li><em>Idle scene</em>: When the visitor or staff scenes are closed, this screen provides suggestions to users on how to interact with the scene</li> </ul> <h3 id="flows" style="position:relative;"><a href="#flows" aria-label="flows permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Flows</h3> <p>We have implemented two flows so far, Visitor and Staff (with plans to expand on these later). When a staff start the conversation in the welcome scene we use face detection and the <a href="https://aws.amazon.com/rekognition/" target="_blank" rel="nofollow noopener noreferrer">AWS Rekognition API</a> to discover who’s the person and welcome them back. For now we decided to leave it at this with plans to go a bit further and do more like showing them a plan of empty desks and so on.</p> <p>For visitors however, a more detailed scenario is implemented. First they can get engaged from welcome screen by just saying Hi Fiona (the name of the virtual host which can be customised), or just press the start button.</p> <p>From there, further instructions are provided which will be read to them and they can press the mic button to talk and express their intentions. For example they can say:</p> <blockquote> <p>I am here to see Yaser</p> </blockquote> <p>Or:</p> <blockquote> <p>Visiting Alex</p> </blockquote> <p>Once we detect their intent, we can then transfer them to verification scene where we show them people with the name mentioned. As of now the default name detection is somewhat terrible so we are using Lex’s specific value slot type. For reference, two slot types are provided, one which learns as it goes and one that you can specify the values and their synonyms. We also show a picture of the person to help them better identify and confirm the person.</p> <p>Once that’s done and they have confirmed the person’s identity, we redirect them to notification scene, where they enter their name and we notify the person they have confirmed before.</p> <h2 id="behind-the-scenes" style="position:relative;"><a href="#behind-the-scenes" aria-label="behind the scenes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Behind the scenes</h2> <p>The web application has a main script which contains a web worker. The web worker has all the background activities required for application to operate. Services like face detection, face recognition, voice recording, and communication between main thread and web worker are all handled here.</p> <p>Just to give you an example, when you press the mic button and speak, the audio is captured in an event handler which encodes it and sends it to Poly to convert to text.</p> <p>Or when someone stands in front of the camera, a method in the worker gets called, tries to detect a face and if the face is detected, will send the picture to Amazon Rekognition service to see if the person is known.</p> <p>Multiple services are used behind the scene. At the core of this experience is the ability to converse with the Sumerian Host which is enabled by the Sumerian Dialogue (chatbot) and Speech (text-to-speech) components, as well as the animation system that syncs the gestures and lip sync with the speech. You can use the Host component’s Point of Interest system in conjunction with OpenCV’s face detection to follow the location of the user’s face, relative to the webcam screen space.</p> <p><img src="/9fab85b47cc845c7e5f838fdb8b37357/vh.jfif" alt="Amazon Virtual Host"></p> <h2 id="key-findings" style="position:relative;"><a href="#key-findings" aria-label="key findings permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Key findings</h2> <p>We reached to a point where a demo was available and the team was happy with the outcome. But although we finished the first phase on time, we found few issues with the whole experience.</p> <ul> <li>The Amazon Sumerian is not a place where people can collaborate. Only one person can work on a particular scene at a time.</li> <li>You cannot keep the source code in source control. At most you can export the whole scene as a zip file and share it.</li> <li>Adding a simple scene takes a bit of time. But its very straightforward</li> <li>The produced bundle is not optimised properly although they are using <strong>Webpack</strong></li> <li>AWS JavaScript SDK is great and well documented</li> </ul> <h2 id="conclusion" style="position:relative;"><a href="#conclusion" aria-label="conclusion permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conclusion</h2> <p>We had a great opportunity to play around with the virtual host and create experiences which would be unforgettable. The true use of technology for something good. It’s also a good opportunity to get your started with a few AWS services and integrate them to solve a problem rather than just learning individually.</p><![CDATA[Chrome DevTools]]>https://yashints.dev/blog/2019/01/13/chromedevtoolshttps://yashints.dev/blog/2019/01/13/chromedevtoolsSun, 13 Jan 2019 00:00:00 GMT<p><a href="https://www.google.com/chrome/" target="_blank" rel="nofollow noopener noreferrer">Google Chrome</a> is currently one of the most popular web browsers used by developers today. The <a href="https://developers.google.com/web/tools/chrome-devtools/" target="_blank" rel="nofollow noopener noreferrer">Chrome DevTools</a> can greatly improve your workflow by helping you develop, test and debug your websites right within your browser.</p> <!--more--> <p>However, there are tons of tips and tricks that we don’t know about it which can help us even further. Just because we don’t see them in menus doesn’t mean we shouldn’t use them to boost our productivity.</p> <p>So I got inspired by <a href="https://vscodecandothat.com/" target="_blank" rel="nofollow noopener noreferrer">VS Code can do</a> that series by by <a href="https://twitter.com/burkeholland" target="_blank" rel="nofollow noopener noreferrer">Burke Holland</a> and <a href="https://twitter.com/sarah_edo" target="_blank" rel="nofollow noopener noreferrer">Sarah Drasner</a> and decided to write about these here. Hope it helps you as it’s helping me and many others day by day 👌.</p> <p>Are you ready? Here we go:</p> <h2 id="screen-shots" style="position:relative;"><a href="#screen-shots" aria-label="screen shots permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Screen shots</h2> <p>You can capture a full page screen shot or what is in the screen without any extension. Simply press <kbd>CTRL</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> for windows and <kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> for Mac users, to open up the command pallet and type <code class="language-text">screenshot</code> to see the menu of three options:</p> <ul> <li>Capture full size screenshot</li> <li>Capture screenshot</li> <li>Capture node screenshot</li> </ul> <p>Selecting any of those options will save an image of the website to your computer.</p> <p><img src="/83685f7f94635f0e36c677f193173b2c/screenshot.gif" alt="Chrome DevTools Screenshot"></p> <h2 id="drag-and-drop-in-elements-panel" style="position:relative;"><a href="#drag-and-drop-in-elements-panel" aria-label="drag and drop in elements panel permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Drag and Drop in elements panel</h2> <p>I didn’t know this until last week and it’s awesome. You can drag and drop elements wherever you want inside elements panel and it would reflect the changes in the page. It’s very good if you want to quickly see how things look like with small changes.</p> <p><img src="/c61f82738100762c26988180a470d0df/drgdrop.gif" alt="Chrome DevTools Drag Drop"></p> <h2 id="pretty-print---minified-source-code" style="position:relative;"><a href="#pretty-print---minified-source-code" aria-label="pretty print minified source 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>Pretty Print { } minified source code</h2> <p>Sometimes you like to see the source code formatted like the original code. This makes more sense in terms of CSS rules or code which is not uglified. This built in feature has saved me some time when debugging CSS rules. Simply press <code class="language-text">{}</code> at the bottom of the page.</p> <p><img src="/e1e8971e0fa2cda7aade4b55f422bdc7/prettyprint.gif" alt="Chrome DevTools pretty print"></p> <h2 id="reference-the-selected-element-in-console" style="position:relative;"><a href="#reference-the-selected-element-in-console" aria-label="reference the selected element in console permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Reference the selected element in console</h2> <p>Sometimes you might want to manipulate an element using JavaScript rather than changing the HTML inside element panel.</p> <p><img src="/6624a2999ae2fb89e4364180026bc6ba/refelement.gif" alt="Chrome DevTools reference element"></p> <h2 id="watch-expressions" style="position:relative;"><a href="#watch-expressions" aria-label="watch 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>Watch expressions</h2> <p>Many times you would like to watch a particular expression to see how it changes under certain circumstances. This is really easy, simply add the expression to watch section:</p> <p><img src="/fedcd564935649736f6dc3717e05f200/watch.gif" alt="Chrome DevTools watch expression"></p> <p>And as you saw you can see the last expression using <code class="language-text">$_</code>.</p> <h2 id="snippets" style="position:relative;"><a href="#snippets" aria-label="snippets permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Snippets</h2> <p>We all have some repetitive piece of code we use time to time. From a template for an click handler to a document ready function, it can be anything really. That’s where the code snippets section comes in handy. You can store a snippet and use it real easy. Just open the snippet section and click <code class="language-text">new</code>. Write your snippet down and whenever you want to use it, press <kbd>Ctrl</kbd>+<kbd>Enter</kbd> for windows and <kbd>Cmd</kbd>+<kbd>Enter</kbd> for Mac users, or right click and press <code class="language-text">run</code>.`</p> <p><img src="/a9bf6a57821bcf10332255b1fe9c83af/snippet.gif" alt="Chrome DevTools code snippets"></p> <h2 id="overriding-location" style="position:relative;"><a href="#overriding-location" aria-label="overriding location permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Overriding location</h2> <p>If you are writing a web application with information depending where the user is, you might want to check the app behaves as expected with user’s location. That’s where location override in Chrome DevTools is very useful. Simply press <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> for windows and <kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> for Mac users, to open the command pallet, type <code class="language-text">sensors</code>, and then select a different location from override location drop down. You can even set it to a custom latitude and longitude if you have them.</p> <p><img src="/e7f61430139b1cdf2c3a394dc628f34d/locationoverride.gif" alt="Chrome DevTools location override"></p> <h2 id="editing-any-text-on-screen" style="position:relative;"><a href="#editing-any-text-on-screen" aria-label="editing any text on screen permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Editing any text on screen</h2> <p>Sometimes you have a limited width and want to see how a long text looks like on the page. Or you simply are checking whether ellipsis appear if the text is long enough. Chrome DevTools has a feature called design mode which you can set it on in the console and then change any text you want and watch the changes on the fly. Super cool right? 😎</p> <p><img src="/5852f839d3a2bfc75c5562f0edab35d7/designmode.gif" alt="Chrome DevTools design mode"></p> <p>That’s it for this post. Keep an eye out for the second post 👀.</p> <p>Also if you likes this post please spread the word and share it 👍.</p><![CDATA[Angular Virtual Scrolling]]>https://yashints.dev/blog/2018/12/06/angular-virtual-scrollhttps://yashints.dev/blog/2018/12/06/angular-virtual-scrollThu, 06 Dec 2018 00:00:00 GMT<p>If you have followed my series on performance improvement, you would’ve stumbled upon my <a href="/blog/2018/11/10/web-perf-4">image optimisation post</a> where I went through a series of steps to lazy load images on your page.</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>When you have many items in your page, regardless of their nature (text, images, video, etc), it tends to slow down your page tremendously. There are ways to get around this but you should put too much effort into this.</p> <p>When it comes to Angular, it gets even worst since this can cause really slow scrolling, plus you have to do dirty check on each of these nodes.</p> <p>But fear not, I have good news for you, with Angular V7 out, there is a new feature called <a href="https://material.angular.io/cdk/scrolling/overview" target="_blank" rel="nofollow noopener noreferrer">Virtual Scroll</a> which allows you to displays large lists of elements in a performing way by only rendering the items that fit on-screen. This may seem trivial but I am here to prove you wrong.</p> <h2 id="dom-nodes" style="position:relative;"><a href="#dom-nodes" aria-label="dom nodes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>DOM nodes</h2> <p>To prove its benefits, I created an application which has a list of thousands items containing a title and an image.</p> <p>Then I used the virtual scroll feature to see how many DOM nodes are created at each time when I scroll and here is the result:</p> <p><img src="/fe188107116f9c3dbed63b6ae889f50c/vscrolldom.gif" alt="Virtual Scrolling only loads 5 nodes"></p> <p>As you can see from the picture, it only loads 5 items at a time no matter where I am in the list. This is specifically good if you want to implement infinite scrolling behaviour on mobile 🔥.</p> <h2 id="network-calls" style="position:relative;"><a href="#network-calls" aria-label="network calls permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Network calls</h2> <p>To even make it better, I used the site <a href="https://picsum.photos/" target="_blank" rel="nofollow noopener noreferrer">Lorem Picsum</a> to give each item a different image (to prevent the browser from caching the image) and since only five <code class="language-text">DOM</code> nodes are created at a time, the network calls are also done accordingly.</p> <p><img src="/4519067116a12fa65c1e38c4cd7463a3/vscrollnetcall.gif" alt="Virtual scroll network calls when scrolling"></p> <p>Remember we had to use the <code class="language-text">Intersection API</code> to achieve this. It’s very convenient isn’t it? 👌</p> <h2 id="how-to-do-it" style="position:relative;"><a href="#how-to-do-it" aria-label="how to 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 to do it</h2> <p>Ok, let’s get to how to implement this. First let’s create a new project using <a href="https://cli.angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular CLI</a>:</p> <div class="gatsby-code-button-container" data-toaster-id="31956918373070754000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng new virtual-scroll`, `31956918373070754000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng new virtual-scroll</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>With the newer versions of CLI it prompts you to specify whether you will need routing module and what is the default style file format (CSS/SCSS, etc.).</p> <p>Now you will need to add the CDK package:</p> <div class="gatsby-code-button-container" data-toaster-id="4102843705982017500" data-toaster-class="gatsby-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 i -s @angular/cdk`, `4102843705982017500`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i <span class="token parameter variable">-s</span> @angular/cdk</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> You will have to navigate to the virtual-scroll folder first.</div></div> <p>Once done open the created folder with your editor of choice #VSCode 😁, and open your <code class="language-text">app.module.ts</code> file.</p> <p>Import the <code class="language-text">ScrollingModule</code> and <code class="language-text">ScrollDispatcher</code> from CDK and add them to your module:</p> <div class="gatsby-code-button-container" data-toaster-id="17191379857326084000" data-toaster-class="gatsby-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 { ScrollingModule, ScrollDispatcher, } from '@angular/cdk/scrolling'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, ScrollingModule, MatListModule, MatToolbarModule, MatCardModule, ], providers: [ScrollDispatcher], bootstrap: [AppComponent], }) export class AppModule {}`, `17191379857326084000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> ScrollingModule<span class="token punctuation">,</span> ScrollDispatcher<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/cdk/scrolling'</span><span class="token punctuation">;</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> declarations<span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<span class="token punctuation">]</span><span class="token punctuation">,</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span> BrowserModule<span class="token punctuation">,</span> ScrollingModule<span class="token punctuation">,</span> MatListModule<span class="token punctuation">,</span> MatToolbarModule<span class="token punctuation">,</span> MatCardModule<span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> providers<span class="token operator">:</span> <span class="token punctuation">[</span>ScrollDispatcher<span class="token punctuation">]</span><span class="token punctuation">,</span> bootstrap<span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<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">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> I am using Material Design and that’s why I have more imports.</div></div> <p>Now open your <code class="language-text">app.component.ts</code> file (feel free to create a new component if you like, I am just hacking something together 🤷‍) and create an array of 1000 items containing a title and an image:</p> <div class="gatsby-code-button-container" data-toaster-id="47684363860778880000" data-toaster-class="gatsby-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 { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; interface IImage { title: string; src: string; } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], }) export class AppComponent { images: IImage[] = Array.from( new Array(1000), (x, i) => ({ title: \`Image #\${i}\`, src: \`https://picsum.photos/200/?\${i}\`, }) ); observableImages = new BehaviorSubject< IImage[] >(this.images); }`, `47684363860778880000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> BehaviorSubject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs'</span><span class="token punctuation">;</span> <span class="token keyword">interface</span> <span class="token class-name">IImage</span> <span class="token punctuation">{</span> title<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> src<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Component</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> selector<span class="token operator">:</span> <span class="token string">'app-root'</span><span class="token punctuation">,</span> templateUrl<span class="token operator">:</span> <span class="token string">'./app.component.html'</span><span class="token punctuation">,</span> styleUrls<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'./app.component.scss'</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">export</span> <span class="token keyword">class</span> <span class="token class-name">AppComponent</span> <span class="token punctuation">{</span> images<span class="token operator">:</span> IImage<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token builtin">Array</span><span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token builtin">Array</span></span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span> title<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Image #</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> src<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://picsum.photos/200/?</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<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 punctuation">)</span><span class="token punctuation">;</span> observableImages <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BehaviorSubject<span class="token operator">&lt;</span> IImage<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">></span></span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>images<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I am using a subject behavior from RxJs just to simulate having an observable and loading data async from server.</p> <p>Now in the <code class="language-text">app.component.html</code> add we need to add the <code class="language-text">cdk-virtual-scroll-viewport</code> and give it an <code class="language-text">itemSize</code> which has a pixel unit.</p> <p>This is basically where everything is glued together.</p> <p>When all items are the same fixed size (in this case all cards have the same height), you can use the <code class="language-text">FixedSizeVirtualScrollStrategy</code>. This can be easily added to your viewport using the <code class="language-text">itemSize</code> directive. The advantage of this constraint is that it allows for better performance, since items do not need to be measured as they are rendered.</p> <div class="gatsby-code-button-container" data-toaster-id="63047861655609450000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<cdk-virtual-scroll-viewport class=&quot;list-container lg&quot; [itemSize]=&quot;200&quot; > <div *cdkVirtualFor=&quot;let image of observableImages | async;&quot; > <mat-card class=&quot;example-card&quot;> <mat-card-header> <div mat-card-avatar class=&quot;example-header-image&quot; ></div> <mat-card-title >{{image.title}}</mat-card-title > <mat-card-subtitle>WoW</mat-card-subtitle> </mat-card-header> <img mat-card-image [src]=&quot;image.src&quot; alt=&quot;Random photo&quot; /> <mat-card-content> <p> This is a random image selected from LoremPicsum. </p> </mat-card-content> <mat-card-actions> <button mat-button>LIKE</button> <button mat-button>SHARE</button> </mat-card-actions> </mat-card> </div> </cdk-virtual-scroll-viewport>`, `63047861655609450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>cdk-virtual-scroll-viewport</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>list-container lg<span class="token punctuation">"</span></span> <span class="token attr-name">[itemSize]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<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">*cdkVirtualFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>let image of observableImages | async;<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>mat-card</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>example-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>mat-card-header</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">mat-card-avatar</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>example-header-image<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>mat-card-title</span> <span class="token punctuation">></span></span>{{image.title}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>mat-card-title</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>mat-card-subtitle</span><span class="token punctuation">></span></span>WoW<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>mat-card-subtitle</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>mat-card-header</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">mat-card-image</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>image.src<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>Random photo<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>mat-card-content</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> This is a random image selected from LoremPicsum. <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>mat-card-content</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>mat-card-actions</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">mat-button</span><span class="token punctuation">></span></span>LIKE<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>button</span> <span class="token attr-name">mat-button</span><span class="token punctuation">></span></span>SHARE<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>mat-card-actions</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>mat-card</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>cdk-virtual-scroll-viewport</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>All I have here is a container with <code class="language-text">200px</code> as <code class="language-text">itemSize</code>. Inside I am creating a <code class="language-text">div</code> in a loop over my list asynchronously and giving it a title, and an image.</p> <p>The <code class="language-text">HTML</code> for card is from <a href="https://material.angular.io/components/card/examples" target="_blank" rel="nofollow noopener noreferrer">Angular Material examples</a>.</p> <p>And that’s it. Now run <code class="language-text">ng serve</code> in VSCode terminal and open up a browser and navigate to <code class="language-text">localhost:4200</code>.</p> <h2 id="done" style="position:relative;"><a href="#done" aria-label="done permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Done</h2> <p>And that’s it. Look at how easy it is to implement a lazy loading strategy for items in a list in Angular with their new <code class="language-text">Virtual Scroll</code> feature with so little code required.</p> <p>You can read more about this feature on <a href="https://material.angular.io/cdk/scrolling/overview" target="_blank" rel="nofollow noopener noreferrer">Angular Material website</a> and the code for this example is available on <a href="">my GitHub repository</a>.</p> <p>If you liked the post please spread the word so other people can benefit from using this new feature 🙏.</p><![CDATA[Getting started on TensorFlow.js]]>https://yashints.dev/blog/2018/11/27/get-started-with-tensorflowjshttps://yashints.dev/blog/2018/11/27/get-started-with-tensorflowjsTue, 27 Nov 2018 00:00:00 GMT<p>If you are like me, who have been wondering what is machine learning (aka ML) and scaped from all those mathematical jargon, it’s an exciting time since the <code class="language-text">TensorFlow.js</code> is here to the rescue.</p> <!--more--> <p>You can find the <a href="https://github.com/yashints/mobilenet" target="_blank" rel="nofollow noopener noreferrer">code for this post here</a>.</p> <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>I’ve been a front end developer for may years, but also curious about machine learning and AI. However, never had a chance to go deeper into it because I have always been busy and most of the machine learning frameworks have been written in languages that I had no exposure to.</p> <p>Things has changed, and people are now using machine learning in mobile devices or in the browser. <code class="language-text">TensorFlow.js</code> is one of the libraries which allows us to create, train and deploy ML models in the browser or in <code class="language-text">Node.js</code>. To be honest, I am really excited about this since it allows me to play with models and neural networks without need to go very low level or learn a new language 🤯.</p> <p>Don’t get me wrong, I am not afraid of learning a new language and in fact it is one of my hobbies. But since I have been busy with lot’s of different tasks, simply haven’t had time to dive into that area.</p> <p>The good thing about this library is that you don’t need to have prior knowledge on ML, you just deal with some high level APIs that have simplified a lot of concepts for you, so you can focus on deploying the models and solving problems rather than reinventing the wheel 🔥.</p> <p>But there are more options which open up a whole lot of opportunities for us. Basically you can:</p> <ul> <li>Import a pre-trained model and use it (predict or deploy it)</li> <li>Import a pre-trained models (Keras or Python) and train it with your dataset</li> <li>Create, train, predict, and deploy privacy friendly models (data never leaves the app)</li> <li>And probably much more that I am not aware of 🤷‍.</li> </ul> <h2 id="core-concepts" style="position:relative;"><a href="#core-concepts" aria-label="core 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>Core concepts</h2> <p>Before we go further into how to use it, we need to get familiar with some basic concepts so to be on the same page.</p> <p><strong>Tensor</strong></p> <p>The central unit of data in TensorFlow.js is the tensor: a set of numerical values shaped into an array of one or more dimensions. A <code class="language-text">Tensor</code> instance has a shape attribute that defines the array <code class="language-text">shape</code> (i.e., how many values are in each dimension of the array).</p> <p><strong>Variables</strong></p> <p>Variables are initialized with a tensor of values. Unlike Tensors, however, their values are mutable.</p> <p><strong>Operations (Ops)</strong></p> <p>While tensors allow you to store data, operations (ops) allow you to manipulate that data. TensorFlow.js provides a wide variety of ops suitable for linear algebra and machine learning that can be performed on tensors. Because tensors are immutable, these ops do not change their values; instead, ops return new tensors.</p> <p><strong>Models and Layers</strong></p> <p>Conceptually, a model is a function that given some input will produce some desired output. In <code class="language-text">TensorFlow.js</code> there are two ways to create models. You can use ops directly to represent the work the model does.</p> <p>Or you can use the high-level API <code class="language-text">tf.model</code> to construct a model out of layers, which are a popular abstraction in deep learning.</p> <div class="custom-block warning"><div class="custom-block-body"><strong>Warning:</strong> Because TensorFlow.js uses the GPU to accelerate math operations, it’s necessary to manage GPU memory when working with tensors and variables. TensorFlow.js provide two functions to help with this: <code class="language-text">dispose</code> and <code class="language-text">tf.tidy</code>. We will dive into these later.</div></div> <h2 id="how-to-use-a-pre-trained-model" style="position:relative;"><a href="#how-to-use-a-pre-trained-model" aria-label="how to use a pre trained model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 to use a pre-trained model</h2> <p>You can use pre-trained models from the highly-popular <a href="https://keras.io/" target="_blank" rel="nofollow noopener noreferrer">Keras</a> Python library to make predictions. This means you don’t need to be a data scientist to be able to use the models or even to build powerful ML-powered apps.</p> <p>Fortunately there are many models available and ready to use which are being exposed via <code class="language-text">TensorFlow.js</code>. For this you will need to use <code class="language-text">TensorFlow.js converter</code> which is an open source library to load a pre-trained model into a format which is understandable by <code class="language-text">TenserFlow.js</code>.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> For this you will need to know a tiny bit of <a href="https://www.python.org/" target="_blank" rel="nofollow noopener noreferrer">Python</a> and have it installed locally.</div></div> <p>You will need to perform two operations to have a ready to use model. First save the model locally, and then run the convertor to convert it. But I found an easier way which doesn’t require running a conversion. The conversion logic is already implemented in the <code class="language-text">tensorflowjs</code> Python package 😁, so I am just going to use that.</p> <h3 id="save-the-model" style="position:relative;"><a href="#save-the-model" aria-label="save the model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Save the model</h3> <p>Let’s go through an example, say we want to import the MobileNet network (which is used to detect objects in images) and save it locally. First follow the <a href="https://www.tensorflow.org/install/pip" target="_blank" rel="nofollow noopener noreferrer">instructions here to install the pre-requisites</a>.</p> <p>Then we can write the below code to save the model locally:</p> <div class="gatsby-code-button-container" data-toaster-id="45943987243039940000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`from keras.applications import mobilenet import tensorflowjs as tfjs mobilenet = mobilenet.MobileNet() save_path = &quot;output\\mobilenet&quot; tfjs.converters.save_keras_model(mobilenet, save_path)`, `45943987243039940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="py"><pre style="counter-reset: linenumber NaN" class="language-py line-numbers"><code class="language-py"><span class="token keyword">from</span> keras<span class="token punctuation">.</span>applications <span class="token keyword">import</span> mobilenet <span class="token keyword">import</span> tensorflowjs <span class="token keyword">as</span> tfjs mobilenet <span class="token operator">=</span> mobilenet<span class="token punctuation">.</span>MobileNet<span class="token punctuation">(</span><span class="token punctuation">)</span> save_path <span class="token operator">=</span> <span class="token string">"output\\mobilenet"</span> tfjs<span class="token punctuation">.</span>converters<span class="token punctuation">.</span>save_keras_model<span class="token punctuation">(</span>mobilenet<span class="token punctuation">,</span> save_path<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>َAfter running this, you should have a <code class="language-text">mobilenet</code> folder in the <code class="language-text">output</code> folder which contains the following files:</p> <p><img src="/6c51a28e6620e02bffe60079f03545cd/savedtensormodel.jpg" alt="Saved keras model in TensorFlow.js format"></p> <p>And guess what, you’re ready to use this and write your first <code class="language-text">TensorFlow.js</code> application.</p> <p>If you’re keen to convert the model using the CLI commands, have a look at <a href="https://js.tensorflow.org/tutorials/import-keras.html" target="_blank" rel="nofollow noopener noreferrer">this tutorial</a>.</p> <h2 id="use-the-model-in-your-application" style="position:relative;"><a href="#use-the-model-in-your-application" aria-label="use the model in your 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>Use the model in your application</h2> <p>I am using <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular</a> in my example, but feel free to use any framework you prefer or even vanilla JS 🙃.</p> <h3 id="create-the-app" style="position:relative;"><a href="#create-the-app" aria-label="create 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>Create the app</h3> <p>I’ve got the Angular CLI installed already, so I am just going to open up a command prompt and create a new application:</p> <div class="gatsby-code-button-container" data-toaster-id="59427001198047355000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng new mobilenet cd mobilenet`, `59427001198047355000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng new mobilenet <span class="token builtin class-name">cd</span> mobilenet</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="install-the-tensorflowjs" style="position:relative;"><a href="#install-the-tensorflowjs" aria-label="install the tensorflowjs permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the TensorFlow.js</h3> <p>This will take a few moments (creating the app and installing all the npm packages). When finished add the <code class="language-text">TensorFlow.js</code> package as well:</p> <div class="gatsby-code-button-container" data-toaster-id="22560046077575848000" data-toaster-class="gatsby-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 @tensorflow/tfjs --save`, `22560046077575848000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @tensorflow/tfjs <span class="token parameter variable">--save</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once this is finished, copy the content of your saved model into your asset folder and open the folder with your editor of choice (<a href="https://code.visualstudio.com/" target="_blank" rel="nofollow noopener noreferrer">VS Code</a> 😁).</p> <p>You will also need to have the image classes for prediction purposes. So create a file somewhere in the project and add the content of <a href="https://github.com/tensorflow/tfjs-examples/blob/master/mobilenet/imagenet_classes.js" target="_blank" rel="nofollow noopener noreferrer">this file</a> into it. I’ve put it in my assets folder.</p> <h3 id="import-the-model-and-use-it" style="position:relative;"><a href="#import-the-model-and-use-it" aria-label="import the model and use 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>Import the model and use it</h3> <p>Open your <code class="language-text">app.component.ts</code> file and add the import statement:</p> <div class="gatsby-code-button-container" data-toaster-id="58681752898538780000" data-toaster-class="gatsby-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 * as tf from '@tensorflow/tfjs' import { IMAGENET_CLASSES } from '../assets/imagenet-classes'`, `58681752898538780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> tf <span class="token keyword">from</span> <span class="token string">'@tensorflow/tfjs'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">IMAGENET_CLASSES</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../assets/imagenet-classes'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>We will need some variables to hold our data and some references to out HTML elements we have to use:</p> <div class="gatsby-code-button-container" data-toaster-id="40465793406225380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`model: tf.Model; classes: any[]; imageData: ImageData; @ViewChild('chosenImage') img: ElementRef; @ViewChild('fileUpload') fileUpload: ElementRef;`, `40465793406225380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts">model<span class="token operator">:</span> tf<span class="token punctuation">.</span>Model<span class="token punctuation">;</span> classes<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> imageData<span class="token operator">:</span> ImageData<span class="token punctuation">;</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">ViewChild</span></span><span class="token punctuation">(</span><span class="token string">'chosenImage'</span><span class="token punctuation">)</span> img<span class="token operator">:</span> ElementRef<span class="token punctuation">;</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">ViewChild</span></span><span class="token punctuation">(</span><span class="token string">'fileUpload'</span><span class="token punctuation">)</span> fileUpload<span class="token operator">:</span> ElementRef<span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The model will have our model, classes is used for our prediction result, and <code class="language-text">imageData</code> is used to convert our file upload file to it and show it in an image on the page.</p> <p>And two global variables, the image size is the size which model is trained on, and the number of predictions we want to pick from prediction result (since it is an array):</p> <div class="gatsby-code-button-container" data-toaster-id="68842688276120390000" data-toaster-class="gatsby-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 IMAGE_SIZE = 224 const TOPK_PREDICTIONS = 5`, `68842688276120390000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">const</span> <span class="token constant">IMAGE_SIZE</span> <span class="token operator">=</span> <span class="token number">224</span> <span class="token keyword">const</span> <span class="token constant">TOPK_PREDICTIONS</span> <span class="token operator">=</span> <span class="token number">5</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Time to add a method to load the model and call it in the <code class="language-text">ngOnInit</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="11540529603427863000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ngOnInit() { this.loadModel(); } async loadModel() { this.model = await tf.loadModel('/assets/model.json'); }`, `11540529603427863000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token function">ngOnInit</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><span class="token function">loadModel</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">async</span> <span class="token function">loadModel</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>model <span class="token operator">=</span> <span class="token keyword">await</span> tf<span class="token punctuation">.</span><span class="token function">loadModel</span><span class="token punctuation">(</span><span class="token string">'/assets/model.json'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We will need a file upload and an image in our HTML, so let’s add them:</p> <div class="gatsby-code-button-container" data-toaster-id="41428396465443210000" data-toaster-class="gatsby-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;container&quot;> <h2> Using MobileNet neural network in Angular </h2> <div class=&quot;upload&quot; [hidden]=&quot;!model&quot;> Upload an image: <input #fileUpload type=&quot;file&quot; id=&quot;files&quot; name=&quot;files[]&quot; (change)=&quot;fileChangeEvent(\$event)&quot; /> </div> <div> <img #chosenImage width=&quot;224&quot; height=&quot;224&quot; class=&quot;sample-image&quot; /> <div class=&quot;predictions&quot;> <div *ngFor=&quot;let class of classes&quot; class=&quot;row&quot; > <div class=&quot;col-sm-6&quot;> {{class.className}} </div> <div class=&quot;col-sm-6&quot;> {{class.probability.toFixed(3)}} </div> </div> </div> </div> </div>`, `41428396465443210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>container<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 punctuation">></span></span> Using MobileNet neural network in Angular <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>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>upload<span class="token punctuation">"</span></span> <span class="token attr-name">[hidden]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!model<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Upload an image: <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">#fileUpload</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>file<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>files<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>files[]<span class="token punctuation">"</span></span> <span class="token attr-name">(change)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fileChangeEvent($event)<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> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">#chosenImage</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>224<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>224<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>sample-image<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>predictions<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">*ngFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>let class of classes<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>row<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>col-sm-6<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{class.className}} <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>col-sm-6<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {{class.probability.toFixed(3)}} <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>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And a bit of CSS to make it pretty:</p> <div class="gatsby-code-button-container" data-toaster-id="36349083973658170000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.container { padding: 200px; .sample-image { margin: 20px; } .predictions { margin-top: 20px; width: 100%; } }`, `36349083973658170000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="scss"><pre style="counter-reset: linenumber NaN" class="language-scss line-numbers"><code class="language-scss"><span class="token selector">.container </span><span class="token punctuation">{</span> <span class="token property">padding</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span> <span class="token selector">.sample-image </span><span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> 20px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.predictions </span><span class="token punctuation">{</span> <span class="token property">margin-top</span><span class="token punctuation">:</span> 20px<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The predictions section in the HTML will have the prediction results in it, we assume it is stored in a variable called <code class="language-text">classes</code>.</p> <p>Now let’s go back to our TypeScript file and add the prediction code. Let’s create a handler for our file input first, that will trigger our prediction logic:</p> <div class="gatsby-code-button-container" data-toaster-id="66808219068533555000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`fileChangeEvent(event: any) { const file = event.target.files[0]; if (!file || !file.type.match('image.*')) { return; } this.classes = []; const reader = new FileReader(); reader.onload = e => { this.img.nativeElement.src = e.target['result']; this.predict(this.img.nativeElement); }; reader.readAsDataURL(file); }`, `66808219068533555000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token function">fileChangeEvent</span><span class="token punctuation">(</span>event<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> file <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>files<span class="token punctuation">[</span><span class="token number">0</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>file <span class="token operator">||</span> <span class="token operator">!</span>file<span class="token punctuation">.</span>type<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token string">'image.*'</span><span class="token punctuation">)</span><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">this</span><span class="token punctuation">.</span>classes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> reader<span class="token punctuation">.</span><span class="token function-variable function">onload</span> <span class="token operator">=</span> e <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>img<span class="token punctuation">.</span>nativeElement<span class="token punctuation">.</span>src <span class="token operator">=</span> e<span class="token punctuation">.</span>target<span class="token punctuation">[</span><span class="token string">'result'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">predict</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>img<span class="token punctuation">.</span>nativeElement<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> reader<span class="token punctuation">.</span><span class="token function">readAsDataURL</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>All we are doing in this method is to read the selected file, put as the source of the image on the page so it’s visible which image is selected and call the predict method. We have call that in the <code class="language-text">onload</code> event handler asynchronously because file has to be read first.</p> <p>Let’s now write the prediction code:</p> <div class="gatsby-code-button-container" data-toaster-id="1567708795802236200" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async predict(imageData: ImageData): Promise<any> { this.fileUpload.nativeElement.value = ''; const startTime = performance.now(); const logits = tf.tidy(() => { // tf.fromPixels() returns a Tensor from an image element. const img = tf.fromPixels(imageData).toFloat(); const offset = tf.scalar(127.5); // Normalize the image from [0, 255] to [-1, 1]. const normalized = img.sub(offset).div(offset); // Reshape to a single-element batch so we can pass it to predict. const batched = normalized.reshape([1, IMAGE_SIZE, IMAGE_SIZE, 3]); // Make a prediction through mobilenet. return this.model.predict(batched); }); // Convert logits to probabilities and class names. this.classes = await this.getTopKClasses(logits, TOPK_PREDICTIONS); const totalTime = performance.now() - startTime; console.log(\`Done in \${Math.floor(totalTime)}ms\`); }`, `1567708795802236200`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">async</span> <span class="token function">predict</span><span class="token punctuation">(</span>imageData<span class="token operator">:</span> ImageData<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fileUpload<span class="token punctuation">.</span>nativeElement<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token keyword">const</span> startTime <span class="token operator">=</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> logits <span class="token operator">=</span> tf<span class="token punctuation">.</span><span class="token function">tidy</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 comment">// tf.fromPixels() returns a Tensor from an image element.</span> <span class="token keyword">const</span> img <span class="token operator">=</span> tf<span class="token punctuation">.</span><span class="token function">fromPixels</span><span class="token punctuation">(</span>imageData<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFloat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> offset <span class="token operator">=</span> tf<span class="token punctuation">.</span><span class="token function">scalar</span><span class="token punctuation">(</span><span class="token number">127.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Normalize the image from [0, 255] to [-1, 1].</span> <span class="token keyword">const</span> normalized <span class="token operator">=</span> img<span class="token punctuation">.</span><span class="token function">sub</span><span class="token punctuation">(</span>offset<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">div</span><span class="token punctuation">(</span>offset<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Reshape to a single-element batch so we can pass it to predict.</span> <span class="token keyword">const</span> batched <span class="token operator">=</span> normalized<span class="token punctuation">.</span><span class="token function">reshape</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 constant">IMAGE_SIZE</span><span class="token punctuation">,</span> <span class="token constant">IMAGE_SIZE</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">// Make a prediction through mobilenet.</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>model<span class="token punctuation">.</span><span class="token function">predict</span><span class="token punctuation">(</span>batched<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 comment">// Convert logits to probabilities and class names.</span> <span class="token keyword">this</span><span class="token punctuation">.</span>classes <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getTopKClasses</span><span class="token punctuation">(</span>logits<span class="token punctuation">,</span> <span class="token constant">TOPK_PREDICTIONS</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> totalTime <span class="token operator">=</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">;</span> <span class="token builtin">console</span><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">Done in </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>totalTime<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">ms</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you don’t understand the code here at the first glance, it’s perfectly OK. Since we have imported the model we have to know a bit about its internals.</p> <p>First of all I am using the <code class="language-text">tidy</code> function as I mentioned earlier to make sure we don’t have any memory leak.</p> <p>Then I will convert the image to a float data type which is expected in this model.</p> <p>Once that is done we need to normalise the data from [0, 255] range to [-1, 1]. The <code class="language-text">scalar</code> operation creates a tensor with provided value.</p> <p>And at last we need to reshape our input to a [1, IMAGE_SIZE, IMAGE_SIZE, 3] tensor and call predict.</p> <p>Once we got the result we have to extract the top <code class="language-text">x</code> classes from the result, so let’s implement that:</p> <div class="gatsby-code-button-container" data-toaster-id="6888016995515134000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`async getTopKClasses(logits, topK): Promise<any[]> { const values = await logits.data(); const valuesAndIndices = []; for (let i = 0; i < values.length; i++) { valuesAndIndices.push({ value: values[i], index: i }); } valuesAndIndices.sort((a, b) => { return b.value - a.value; }); const topkValues = new Float32Array(topK); const topkIndices = new Int32Array(topK); for (let i = 0; i < topK; i++) { topkValues[i] = valuesAndIndices[i].value; topkIndices[i] = valuesAndIndices[i].index; } const topClassesAndProbs = []; for (let i = 0; i < topkIndices.length; i++) { topClassesAndProbs.push({ className: IMAGENET_CLASSES[topkIndices[i]], probability: topkValues[i] }); } return topClassesAndProbs; }`, `6888016995515134000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="ts"><pre style="counter-reset: linenumber NaN" class="language-ts line-numbers"><code class="language-ts"><span class="token keyword">async</span> <span class="token function">getTopKClasses</span><span class="token punctuation">(</span>logits<span class="token punctuation">,</span> topK<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token builtin">any</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">const</span> values <span class="token operator">=</span> <span class="token keyword">await</span> logits<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> valuesAndIndices <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> values<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> valuesAndIndices<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> value<span class="token operator">:</span> values<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> index<span class="token operator">:</span> i <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> valuesAndIndices<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> b<span class="token punctuation">.</span>value <span class="token operator">-</span> a<span class="token punctuation">.</span>value<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> topkValues <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Float32Array</span><span class="token punctuation">(</span>topK<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> topkIndices <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Int32Array</span><span class="token punctuation">(</span>topK<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> topK<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> topkValues<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> valuesAndIndices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span> topkIndices<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> valuesAndIndices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>index<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> topClassesAndProbs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> topkIndices<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> topClassesAndProbs<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> className<span class="token operator">:</span> <span class="token constant">IMAGENET_CLASSES</span><span class="token punctuation">[</span>topkIndices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span> probability<span class="token operator">:</span> topkValues<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> topClassesAndProbs<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Alright, remember we called this method with the result of predict in shape of a <code class="language-text">logit</code>. Logits are normally either a <code class="language-text">Tensor</code> or an array or a typed array.</p> <p>So basically we get the result by awaiting the <code class="language-text">data</code> method. Then we create a new array using the value and index of the output of that.</p> <p>And based on that we calculate the resulting classes based on the formed array. Again you don’t need to understand what the code does, at a high level it is just mapping the result to one of the classes we got from the GitHub repository earlier.</p> <h2 id="running-the-app" style="position:relative;"><a href="#running-the-app" aria-label="running 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>Running the app</h2> <p>You can now run the app and go to <code class="language-text">localhost:4200</code> and upload an image and see what predictions you get 😎.</p> <p><video controls playsinline webkit-playsinline style="max-width: 900px" src="/f74ed381f4512a2f1ac7a1979d68396d/Mobilenet.webm" preload="auto"> Your browser does not support the video tag. </video></p> <p>And that’s how easy it is to get started. Hope you’ve enjoyed this post and be sure there will be more.</p> <p>You can find the <a href="https://github.com/yashints/mobilenet" target="_blank" rel="nofollow noopener noreferrer">code for this post here</a>.</p><![CDATA[Web font optimisation]]>https://yashints.dev/blog/2018/11/23/web-perf-5https://yashints.dev/blog/2018/11/23/web-perf-5Fri, 23 Nov 2018 00:00:00 GMT<p>Web fonts enable us to have good design, branding, readability and accessibility. Moreover, they would bring selectable, searchable, zoomable and high DPI text. However, with every advantage comes a trade off.</p> <!--more--> <p>All other parts:</p> <p><a href="/blog/2018/09/29/web-perf-1">Part 1 on HTML and CSS</a></p> <p><a href="/blog/2018/10/06/web-perf-2">Part 2 use Preload/Prefetch to boost load time</a></p> <p><a href="/blog/2018/10/12/web-perf-3">Part 3 JavaScript tips and tricks</a></p> <p><a href="/blog/2018/11/12/web-perf-4">Part 4 Image optimisation</a></p> <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>People use web fonts heavily these days without realising how much impact it would have on the overall page speed.</p> <p>This doesn’t mean you shouldn’t use them, just the fact that you should know how to use an optimised font and to how to load to reduce the impact on page load.</p> <p>Optimising web fonts depends on where you host the font, your web application’s design and back end server, your technical abilities and how far your company is willing to invest in this. But don’t let this hold you from following the techniques I will go through, even a little improvement on overall page load counts towards a better user experience.</p> <h2 id="finding-out-how-many-fonts-you-are-using" style="position:relative;"><a href="#finding-out-how-many-fonts-you-are-using" aria-label="finding out how many fonts you are using permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 out how many fonts you are using</h2> <p>Before you start the task, you should find out what fonts are used throughout your website. You can easily find this out using Audit tabs in Chrome DevTools’ network tab and looking at the HTTP requests.</p> <p>Once in the tab click on the filter icon and look for file extensions like <code class="language-text">woff</code>, <code class="language-text">woff2</code>, <code class="language-text">tff</code>, <code class="language-text">otf</code> and so on:</p> <p><img src="/8576b18315655ed5f59939bc2581ce78/webfontusage.jpg" alt="Finding what web fonts you are using"></p> <h2 id="deciding-how-many-is-too-many" style="position:relative;"><a href="#deciding-how-many-is-too-many" aria-label="deciding how many is too many permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Deciding how many is too many</h2> <p>Research shows on average 67% of web pages use custom fonts, with websites averaging between four web font HTTP requests.</p> <p>Once you figured out how many fonts you are using, you should think about how many fonts you should use. Normally these decisions are driven by UX or design team, but you can definitely have a word with them.</p> <p>If you are thinking how many is too many, the rule of thumb is that <a href="https://engageinteractive.co.uk/blog/how-many-fonts-is-too-many-fonts" target="_blank" rel="nofollow noopener noreferrer">three is crowd and two is the best to stick to</a>.</p> <p>If you use less fonts throughout your website, not only the number of network requests are reduced, but also the design is more streamlined and consistent.</p> <h2 id="choose-the-subset-you-need" style="position:relative;"><a href="#choose-the-subset-you-need" aria-label="choose the subset you need permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Choose the subset you need</h2> <p>Unless you have an international website supporting multiple languages, it doesn’t make sense to use all character sets. Choose only what you need and for the languages you use.</p> <p>Ilya Grigorik a Developer Advocate and Web Perf Guru at Google, <a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization" target="_blank" rel="nofollow noopener noreferrer">explains how you can subset or split web fonts into multiple unicode ranges to deliver only what you need</a>.</p> <p>You can use the <a href="http://www.w3.org/TR/css3-fonts/#descdef-unicode-range" target="_blank" rel="nofollow noopener noreferrer">Unicode-range descriptor</a> to specify a list of range values, which can be set out in three different forms:</p> <ul> <li><strong>Single codepoint</strong>: indicates a single character.</li> <li><strong>Interval range</strong>: indicates start and of the codepoints of a range of characters.</li> <li><strong>Wildcard range</strong>: <code class="language-text">?</code> character indicates any hexadecimal digit.</li> </ul> <p>To demonstrate the possibilities, this is how you can split the <a href="https://fontawesome.com/" target="_blank" rel="nofollow noopener noreferrer">Font Awesome</a> into Latin and Japanese subsets. Once done, the browser would download each subset as needed.</p> <div class="custom-block info"><div class="custom-block-body"> Note: Unicode-range subsetting is particularly important for Asian languages, where the number of glyphs is much larger than in Western languages and a typical “full” font is often measured in megabytes instead of tens of kilobytes.</div></div> <div class="gatsby-code-button-container" data-toaster-id="45007897480582980000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@font-face { font-family: 'Awesome Font'; font-style: normal; font-weight: 400; src: local('Awesome Font'), url('/fonts/awesome-l.woff2') format('woff2'), url('/fonts/awesome-l.woff') format('woff'), url('/fonts/awesome-l.ttf') format('truetype'), url('/fonts/awesome-l.eot') format('embedded-opentype'); unicode-range: U+000-5FF; /* Latin glyphs */ } @font-face { font-family: 'Awesome Font'; font-style: normal; font-weight: 400; src: local('Awesome Font'), url('/fonts/awesome-jp.woff2') format('woff2'), url('/fonts/awesome-jp.woff') format('woff'), url('/fonts/awesome-jp.ttf') format('truetype'), url('/fonts/awesome-jp.eot') format('embedded-opentype'); unicode-range: U+3000-9FFF, U+ff??; /* Japanese glyphs */ }`, `45007897480582980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token atrule"><span class="token rule">@font-face</span></span> <span class="token punctuation">{</span> <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Awesome Font'</span><span class="token punctuation">;</span> <span class="token property">font-style</span><span class="token punctuation">:</span> normal<span class="token punctuation">;</span> <span class="token property">font-weight</span><span class="token punctuation">:</span> 400<span class="token punctuation">;</span> <span class="token property">src</span><span class="token punctuation">:</span> <span class="token function">local</span><span class="token punctuation">(</span><span class="token string">'Awesome Font'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.woff2'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff2'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.woff'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.ttf'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'truetype'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.eot'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'embedded-opentype'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">unicode-range</span><span class="token punctuation">:</span> U+000-5FF<span class="token punctuation">;</span> <span class="token comment">/* Latin glyphs */</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@font-face</span></span> <span class="token punctuation">{</span> <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Awesome Font'</span><span class="token punctuation">;</span> <span class="token property">font-style</span><span class="token punctuation">:</span> normal<span class="token punctuation">;</span> <span class="token property">font-weight</span><span class="token punctuation">:</span> 400<span class="token punctuation">;</span> <span class="token property">src</span><span class="token punctuation">:</span> <span class="token function">local</span><span class="token punctuation">(</span><span class="token string">'Awesome Font'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-jp.woff2'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff2'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-jp.woff'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-jp.ttf'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'truetype'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-jp.eot'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'embedded-opentype'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">unicode-range</span><span class="token punctuation">:</span> U+3000-9FFF<span class="token punctuation">,</span> U+ff??<span class="token punctuation">;</span> <span class="token comment">/* Japanese glyphs */</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> The <code class="language-text">local()</code> directive allows you to reference, load, and use locally installed fonts. The <code class="language-text">url()</code> directive allows you to load external fonts, and are allowed to contain an optional <code class="language-text">format()</code> hint indicating the format of the font referenced by the provided URL.</div></div> <p>There is a catch however which is not all browsers currently <a href="http://caniuse.com/#feat=font-unicode-range" target="_blank" rel="nofollow noopener noreferrer">support unicode-range</a>. Fortunately most of the major browsers support it, you will need to have a fallback option.</p> <p>Now if you’re asking how I can determine which subsets I need, the answer is:</p> <ul> <li>If the browser supports unicode-range, then it will automatically select the right subset. You will just need to provide the subset files and specify the appropriate range in the <code class="language-text">@font-face</code> rules.</li> <li>If the browser does not support this feature, then you will need to hide all unnecessary subsets, which is, you have to specify the required subsets manually.</li> </ul> <p>You can generate the subsets using an open source tool called <a href="https://github.com/behdad/fonttools/" target="_blank" rel="nofollow noopener noreferrer">pyftsubset tool</a>. In addition to that some font services allow manual subsetting via custom query parameters.</p> <p>There are some other opportunities you can leverage apart from subsetting. Let’s say you just need a Google font to show your page title. You can specify which characters to download from that font only using a <code class="language-text">&amp;text=</code> syntax:</p> <div class="gatsby-code-button-container" data-toaster-id="52855957935698330000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<link href=&quot;//fonts.googleapis.com/css?family=Roboto&text=log&quot; rel=&quot;stylesheet&quot; />`, `52855957935698330000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</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>//fonts.googleapis.com/css?family=Roboto&amp;text=log<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block warning"><div class="custom-block-body"><strong>Warning:</strong> You need to be careful since this is not a word selector but a character selector. This means characters <code class="language-text">l</code>, <code class="language-text">o</code>, and <code class="language-text">g</code> will be shown on Roboto.</div></div> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; " > <a class="gatsby-resp-image-link" href="/static/727a971696e3f21f5fc9977746d48ca0/41099/font-certain-characters.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 60%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQAF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB2hBqP//EABcQAAMBAAAAAAAAAAAAAAAAABAREiD/2gAIAQEAAQUCxKH/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAZEAACAwEAAAAAAAAAAAAAAAAAARARQXH/2gAIAQEAAT8hFeqKEmm+x//aAAwDAQACAAMAAAAQw8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAACAwEBAAAAAAAAAAAAAAABEQAhMRBR/9oACAEBAAE/EIRNAukWxwgdEIO/6amT/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="This image shows that only the letter g is rendered with Roboto font" title="" src="/static/727a971696e3f21f5fc9977746d48ca0/41099/font-certain-characters.jpg" srcset="/static/727a971696e3f21f5fc9977746d48ca0/6f81f/font-certain-characters.jpg 270w, /static/727a971696e3f21f5fc9977746d48ca0/41099/font-certain-characters.jpg 500w" sizes="(max-width: 500px) 100vw, 500px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="deliver-optimised-font-formats" style="position:relative;"><a href="#deliver-optimised-font-formats" aria-label="deliver optimised font formats permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Deliver optimised font formats</h2> <p>There are four major formats used on the web:</p> <ul> <li><strong>Embedded Open Type (EOT)</strong>: Microsoft designed this format, which is now only used by IE browsers.</li> <li><strong>True Type Font (TTF)</strong>: A format that’s been around since the late 1980s that has partial IE support.</li> <li><strong>Web Open Font Format (WOFF)</strong>: A format developed in 2009, which is essentially OpenType or TrueType with compression and additional metadata. It enjoys widespread support but is not available in some older browser.</li> <li><strong>Web Open Font Format (WOFF2)</strong>: An improvement on WOFF that provides, on average, a 30% reduction in file size. Support is still a work in progress for many browsers.</li> </ul> <p>There isn’t one format that works in all of the browsers, hence the need to deliver multiple formats to provide a consistent experience. From Google developer’s website:</p> <ul> <li>Serve WOFF 2.0 variant to browsers that support it.</li> <li>Serve WOFF variant to the majority of browsers.</li> <li>Serve TTF variant to old Android (below 4.4) browsers.</li> <li>Serve EOT variant to old IE (below IE9) browsers.</li> </ul> <p>If majority of your users use modern web browsers you can get away with specifying just two formats:</p> <div class="gatsby-code-button-container" data-toaster-id="43655688860875740000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@font-face { font-family: 'Roboto'; src: local('Roboto'), local('Roboto'), url(fonts/Roboto.woff2) format('woff2'), url(fonts/Roboto.woff) format('woff'); }`, `43655688860875740000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token atrule"><span class="token rule">@font-face</span></span> <span class="token punctuation">{</span> <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Roboto'</span><span class="token punctuation">;</span> <span class="token property">src</span><span class="token punctuation">:</span> <span class="token function">local</span><span class="token punctuation">(</span><span class="token string">'Roboto'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">local</span><span class="token punctuation">(</span><span class="token string">'Roboto'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span>fonts/Roboto.woff2<span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff2'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span>fonts/Roboto.woff<span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="always-check-for-the-font-locally" style="position:relative;"><a href="#always-check-for-the-font-locally" aria-label="always check for the font 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>Always check for the font locally</h2> <p>Some users might already have the fonts installed on their system, so why they should be forced to download the fonts again. You can prevent this by making sure you give precedence to <code class="language-text">local()</code> in the <code class="language-text">src</code> attribute of font face rule.</p> <p>In the above sample note how the <code class="language-text">src: local</code> is used before the <code class="language-text">url</code>.</p> <h2 id="optimnising-the-loading-and-rendering" style="position:relative;"><a href="#optimnising-the-loading-and-rendering" aria-label="optimnising the loading and rendering permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Optimnising the loading and rendering</h2> <p>By default the fonts are lazy loaded, which means the network request is delayed until the render tree is fully constructed, which in turn results in delayed text rendering.</p> <p>There are three hooks you would need to implement a custom font loading strategy:</p> <ul> <li><code class="language-text">&lt;link rel=preload></code></li> <li>CSS <code class="language-text">font-display</code> property</li> <li>Font Loading API</li> </ul> <h3 id="preload-your-web-font" style="position:relative;"><a href="#preload-your-web-font" aria-label="preload your web font permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Preload your web font</h3> <p>If there is a high chance that the font is used in the page, then you can load the font eagerly using the platform feature: <code class="language-text">&lt;link rel=preload></code>.</p> <p>This will tell the browser that the font should be fetched early, but it won’t specify how to use it. You will need to specify the appropriate CSS <code class="language-text">@font-face</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="66404047675932400000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<link rel=&quot;preload&quot; href=&quot;/fonts/Roboto.woff2&quot; as=&quot;font&quot; />`, `66404047675932400000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></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>/fonts/Roboto.woff2<span class="token punctuation">"</span></span> <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>font<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="gatsby-code-button-container" data-toaster-id="16054617573775931000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@font-face { font-family: 'Awesome Font'; font-style: normal; font-weight: 400; /* will be preloaded */ src: local('Awesome Font'), url('/fonts/awesome-l.woff2') format('woff2'), url('/fonts/awesome-l.woff') format('woff'), url('/fonts/awesome-l.ttf') format('truetype'), url('/fonts/awesome-l.eot') format('embedded-opentype'); unicode-range: U+000-5FF; /* Latin glyphs */ }`, `16054617573775931000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token atrule"><span class="token rule">@font-face</span></span> <span class="token punctuation">{</span> <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Awesome Font'</span><span class="token punctuation">;</span> <span class="token property">font-style</span><span class="token punctuation">:</span> normal<span class="token punctuation">;</span> <span class="token property">font-weight</span><span class="token punctuation">:</span> 400<span class="token punctuation">;</span> <span class="token comment">/* will be preloaded */</span> <span class="token property">src</span><span class="token punctuation">:</span> <span class="token function">local</span><span class="token punctuation">(</span><span class="token string">'Awesome Font'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.woff2'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff2'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.woff'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'woff'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.ttf'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'truetype'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'/fonts/awesome-l.eot'</span><span class="token punctuation">)</span></span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'embedded-opentype'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">unicode-range</span><span class="token punctuation">:</span> U+000-5FF<span class="token punctuation">;</span> <span class="token comment">/* Latin glyphs */</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block warning"><div class="custom-block-body"><strong>Warning:</strong> Not all browsers support this feature, but those who support it also support WOFF2, so you should use that format.</div></div> <p>For more info on the other solutions refer to <a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization" target="_blank" rel="nofollow noopener noreferrer">this great post</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>In short these are the points you have to consider when optimising web fonts:</p> <ul> <li>Audit and monitor your font use.</li> <li>Subset your font resources.</li> <li>Deliver optimized font formats to each browser.</li> <li>Give precedence to <code class="language-text">local()</code> in your <code class="language-text">src</code> list.</li> <li>Customize font loading and rendering using <code class="language-text">&lt;link rel="preload"></code>, <code class="language-text">font-display</code>, or the Font Loading API.</li> <li>Specify revalidation and optimal caching policies</li> </ul> <p>Hope this helps you move one more step in the right direction to improve your web application’s performance.</p><![CDATA[How to fix debugging Flutter in VS Code]]>https://yashints.dev/blog/2018/11/16/how-to-fix-vscode-flutter-debughttps://yashints.dev/blog/2018/11/16/how-to-fix-vscode-flutter-debugFri, 16 Nov 2018 00:00:00 GMT<h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p><a href="https://flutter.io" target="_blank" rel="nofollow noopener noreferrer">Flutter</a> is a framework created by <a href="https://google.com" target="_blank" rel="nofollow noopener noreferrer">Google</a> which allows you to build beautiful native apps on iOS and Android from a single codebase.</p> <!--more--> <p>I recently finished my project at my latest client and had it mind to play with, so I set everything up based on their <a href="https://flutter.io/docs" target="_blank" rel="nofollow noopener noreferrer">documentation</a> which to my opinion is the most straight forward doc I’ve ever seen.</p> <p>You will need to install a few things:</p> <ul> <li>Flutter</li> <li>Android Studio</li> <li>An editor of choice (which mine is <a href="https://code.visualstudio.com/" target="_blank" rel="nofollow noopener noreferrer">Visual Studio Code</a>)</li> </ul> <p>Once the setup is done, you will have a hello world app you could make. Flutter uses dart which I find it interesting. It’s similar to <code class="language-text">Java Script</code>, but it supports types like <code class="language-text">Type Script</code> (however it is not a super set of JS like <code class="language-text">Type Script</code>).</p> <p>You will also need to install one of the android images since you will need it for running your app if you don’t want to test it on an actual device.</p> <p>When you’re ready just hit debug in VS code and the app runs on the simulator. It’s really fascinating since it uses Material Design theme and it almost looks the same in iOS and Android.</p> <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>Now all these was to let you know that currently if you run the app once, exit from it and change something or run it again without change, you will get an error:</p> <div class="custom-block danger"><div class="custom-block-body"> Program linking failed. “terminating with uncaught exception of type std::bad_alloc: std::bad_alloc” failed</div></div> <p>At first I thought I messed something up. So I started stripping my code to see which change has broken the app.</p> <h2 id="resolution" style="position:relative;"><a href="#resolution" aria-label="resolution permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Resolution</h2> <p>Nothing helped, so I started Googling to see if someone else has faced the same issue and <a href="https://github.com/flutter/flutter/issues/22568" target="_blank" rel="nofollow noopener noreferrer">there it was</a>.</p> <p>Based on this thread all I need to do was to add a lunch settings to VS Code and specify the <code class="language-text">--enable-software-rendering</code> flag:</p> <div class="gatsby-code-button-container" data-toaster-id="7438404018240829000" data-toaster-class="gatsby-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;version&quot;: &quot;0.2.0&quot;, &quot;configurations&quot;: [ { &quot;name&quot;: &quot;Flutter&quot;, &quot;request&quot;: &quot;launch&quot;, &quot;type&quot;: &quot;dart&quot;, &quot;args&quot;: [&quot;--enable-software-rendering&quot;] } ] }`, `7438404018240829000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"0.2.0"</span><span class="token punctuation">,</span> <span class="token property">"configurations"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Flutter"</span><span class="token punctuation">,</span> <span class="token property">"request"</span><span class="token operator">:</span> <span class="token string">"launch"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dart"</span><span class="token punctuation">,</span> <span class="token property">"args"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"--enable-software-rendering"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And that’s it. This will resolve the issue. If you don’t want to use this approach you can also uninstall the app from the simulator and run it again, however, this works sometimes and not always.</p> <p>They might fix this issue later but for now that’s the way.</p> <p>Hope this helps you explore more into Flutter and create some awesome apps.</p><![CDATA[Image optimisation]]>https://yashints.dev/blog/2018/11/12/web-perf-4https://yashints.dev/blog/2018/11/12/web-perf-4Mon, 12 Nov 2018 00:00:00 GMT<p>Recently I had a chance to present a talk at <a href="https://ndcsydney.com/talk/need-for-speed-8-performance-tuning-of-your-web-application/" target="_blank" rel="nofollow noopener noreferrer">NDC Sydney</a> about web performance and it received a great feedback.</p> <!--more--> <p>That inspired me to write up a series of posts on each topic I covered in that talk, and who knows, maybe each of these posts would be a talk some day by their own 😃.</p> <p>All other parts:</p> <p><a href="/blog/2018/09/29/web-perf-1">Part 1 on HTML and CSS</a></p> <p><a href="/blog/2018/10/06/web-perf-2">Part 2 use Preload/Prefetch to boost load time</a></p> <p><a href="/blog/2018/10/12/web-perf-3">Part 3 JavaScript tips and tricks</a></p> <p><a href="/blog/2018/11/23/web-perf-5">Part 5 Web font optimisation</a></p> <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>Believe me you don’t want Google to hate your website. Knowing the most heavy weight items on every website are images, it is very important to focus on their optimisation.</p> <p>Fortunately, reducing their size is very easy and has massive impact on the overall size of the page. For most of the users on a mobile device, the image quality wouldn’t be so important. Even on a desktop with high resolution there are sacrifices you can make. That’s because human eyes won’t detect certain pixels not being present.</p> <p>As long as you don’t go too far optimising an image to make it ugly, it is a good to continue reducing its size 🤷‍.</p> <blockquote> <p>Images take more than %50 of a web page’s overall weight 😱. That’s why we should optimise them!</p> </blockquote> <table> <thead> <tr> <th 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/94dd15338b0d454aa565d4505c40c020/72e01/avragebytespp.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 65.92592592592594%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHtzZKpf//EABgQAAIDAAAAAAAAAAAAAAAAAAERAAIQ/9oACAEBAAEFAiZW2JwBZ//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAQADAQEAAAAAAAAAAAAAAAEAEUEQkf/aAAgBAQABPyFRgt37BvGO0FXz/9oADAMBAAIAAwAAABAPz//EABcRAAMBAAAAAAAAAAAAAAAAAAEQESH/2gAIAQMBAT8QNuL/xAAWEQADAAAAAAAAAAAAAAAAAAAQESH/2gAIAQIBAT8QiH//xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhQRBR/9oACAEBAAE/EFFP3BGIUI5rblKyiAlWcDI6Cq9fP//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Average bytes per page" title="" src="/static/94dd15338b0d454aa565d4505c40c020/72e01/avragebytespp.jpg" srcset="/static/94dd15338b0d454aa565d4505c40c020/6f81f/avragebytespp.jpg 270w, /static/94dd15338b0d454aa565d4505c40c020/09d21/avragebytespp.jpg 540w, /static/94dd15338b0d454aa565d4505c40c020/72e01/avragebytespp.jpg 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" decoding="async" /> </a> </span></th> </tr> </thead> <tbody> <tr> <td align="center"><em>Average bytes per page 2018</em></td> </tr> </tbody> </table> <h2 id="what-does-image-optimisation-mean" style="position:relative;"><a href="#what-does-image-optimisation-mean" aria-label="what does image optimisation mean permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 does image optimisation mean</h2> <p>Image optimisation is referred to <strong>reducing image sizes</strong> using different techniques. This will result in the page being loaded faster, hence having a better user experience.</p> <h2 id="why-bother" style="position:relative;"><a href="#why-bother" aria-label="why bother permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 bother</h2> <p>Here are some benefits you would gain by optimising your images:</p> <ul> <li>It will improve the page load time. For every second users have to wait for the page to load, Amazon will lose $1.6 billion in sales per year (you may now pick a calculator and see how much your company would be impacted 😁).</li> <li>It improves your SEO capabilities, your site will rank higher in search engines resulting in more traffic.</li> <li>Creating site backups will be faster (if you are using a CMS or if you backup the whole site)</li> <li>Smaller image sizes use less bandwidth, resulting in not draining user’s mobile data quota.</li> <li>Requires less storage space on the server (or CDN), makes it more cost effective.</li> </ul> <h2 id="lets-optimise-them" style="position:relative;"><a href="#lets-optimise-them" aria-label="lets optimise them permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Let’s optimise them</h2> <p>The primary goal of image optimisation is to find the balance between file size and image quality. But before we start on optimisation tips, we should understand different image formats and when to use each.</p> <h3 id="choose-the-right-format" style="position:relative;"><a href="#choose-the-right-format" aria-label="choose the right format permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Choose the right format</h3> <ul> <li><strong>PNG</strong> – produces higher quality images, but also has a larger file size. Was created as a lossless image format, although it can also be lossy.</li> <li><strong>JPEG</strong> – uses lossy and lossless optimization. You can adjust the quality level for a good balance of quality and file size.</li> <li><strong>GIF</strong> – only uses 256 colors. It’s the best choice for animated images. It only uses lossless compression.</li> </ul> <p>There are some newer image formats like <strong>WebP</strong> and <strong>Jpeg2000</strong>, but the browser support is not there yet. In summary you should use JPEG for images with lots of colour and PNG for simpler images.</p> <h3 id="size-vs-compression" style="position:relative;"><a href="#size-vs-compression" aria-label="size vs compression permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Size vs Compression</h3> <p>This is an example of an image before and after compression. Note how the quality is impacted (you can’t see it in the cat, but around it):</p> <p><strong>Before</strong> <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/f418272fbe68058ad6a67edb674ebd63/21b8f/cat-lg.jpg" 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/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEAv/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAGqapGhEv8A/8QAGRAAAwEBAQAAAAAAAAAAAAAAAAECAxEE/9oACAEBAAEFAr9EovfhDVzWWbp5QcR//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhAAAgIDAAAAAAAAAAAAAAAAAAECMRESMv/aAAgBAQAGPwKhGyMuJyij/8QAGxABAAICAwAAAAAAAAAAAAAAAQARIVExQYH/2gAIAQEAAT8h7TnZHsooeNwdgHZKUVlXLeQIqP/aAAwDAQACAAMAAAAQlO//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhMUFxgaH/2gAIAQEAAT8QFKMQCgvnHsr3IEY6RDHTKmWrPlV+RwojQ6SqABgn/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Cat" title="" src="/static/f418272fbe68058ad6a67edb674ebd63/47311/cat-lg.jpg" srcset="/static/f418272fbe68058ad6a67edb674ebd63/6f81f/cat-lg.jpg 270w, /static/f418272fbe68058ad6a67edb674ebd63/09d21/cat-lg.jpg 540w, /static/f418272fbe68058ad6a67edb674ebd63/47311/cat-lg.jpg 1080w, /static/f418272fbe68058ad6a67edb674ebd63/0047d/cat-lg.jpg 1620w, /static/f418272fbe68058ad6a67edb674ebd63/274e1/cat-lg.jpg 2160w, /static/f418272fbe68058ad6a67edb674ebd63/21b8f/cat-lg.jpg 4896w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>After</strong> <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/90e74e99d64dfa1db5e3ee84560be56e/e5166/cat-sm.jpg" 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/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQB/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAapqhrEv/8QAGRAAAwEBAQAAAAAAAAAAAAAAAAECAwQR/9oACAEBAAEFAr6JRe7RDVzWWbp5QeI//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGxAAAgEFAAAAAAAAAAAAAAAAAAECEBESMTL/2gAIAQEABj8C0JmSLuJyqf/EABsQAAIDAAMAAAAAAAAAAAAAAAABESFRMUGB/9oACAEBAAE/Ie03qKwpPjROoT1EKLZFt3glKIP/2gAMAwEAAgADAAAAEITv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAACH/2gAIAQIBAT8QR//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExQXGBsf/aAAgBAQABPxClo7AKC+ceyoBkIx0iGOiVMsWfKvyOFEaHSVQQME//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Cat" title="" src="/static/90e74e99d64dfa1db5e3ee84560be56e/47311/cat-sm.jpg" srcset="/static/90e74e99d64dfa1db5e3ee84560be56e/6f81f/cat-sm.jpg 270w, /static/90e74e99d64dfa1db5e3ee84560be56e/09d21/cat-sm.jpg 540w, /static/90e74e99d64dfa1db5e3ee84560be56e/47311/cat-sm.jpg 1080w, /static/90e74e99d64dfa1db5e3ee84560be56e/e5166/cat-sm.jpg 1200w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>For the same reason that you can’t figure out the difference in the cat itself between the first and second image, it is safe to compress image to that degree. Just to let you know the first image is 4mb and the second is only 27kb. 🤷‍</p> <h3 id="lossy-vs-lossless-optimisation" style="position:relative;"><a href="#lossy-vs-lossless-optimisation" aria-label="lossy vs lossless optimisation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Lossy vs Lossless Optimisation</h3> <p>Now that you know how important it is to compress images and reduce the quality, it is also important to know we have two types of compression:</p> <ul> <li> <p><strong>Lossy</strong> - this is kind of a filter to eliminate some data from the image, in the above example you could see some loss in the area around the cat. Using this technique, the file size will be reduced to a large degree. Tools such as Adobe Photoshop, Affinity Photo or some free online tools such as <a href="https://imagecompressor.com/" target="_blank" rel="nofollow noopener noreferrer">Image Compressor</a> will do the trick for you.</p> </li> <li> <p><strong>Lossless</strong> - this is a filter that does not eliminate any data, but uses compression only to reduce the size, but it means it requires images to be uncompressed to operate. You can do this easily using tools like <a href="http://netm.ag/optimize-263" target="_blank" rel="nofollow noopener noreferrer">FileOptimizer</a> and <a href="http://imageoptim.com/" target="_blank" rel="nofollow noopener noreferrer">ImageOptim</a>.</p> </li> </ul> <p>You will need to experience it yourself and find the sweet spot for your images. It is a task which requires some work beforehand but saves you a lot of time later. Another thing to consider is to use these tools like ImageOptim in your build process, this way you don’t even need to worry about doing it upfront. And your original images remain untouched.</p> <h2 id="using-the-right-dimension" style="position:relative;"><a href="#using-the-right-dimension" aria-label="using the right dimension permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Using the right dimension</h2> <p>As important as compression is, by itself it can go only so far keeping the same dimension. After you apply the compression you cannot reduce the size with the same width and height anymore.</p> <p>Apart from this, you will need to know that showing a picture with 2000px width on a mobile device is not such a good idea. Especially on smaller devices the human ability to detect changes are far less than when they are looking at a bit monitor with a large aspect ratio.</p> <p>To achieve this you can use the <code class="language-text">srcset</code> and <code class="language-text">width descriptors</code> attribute in <code class="language-text">HTML</code>. With this, you can mention multiple screen sizes and specify which image to use for each size.</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/dbcaa7867cc1481e522b666ffbd0e07f/5a190/srcset-width-descriptors.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,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAABl0lEQVR42o1Sa2+iQBTl//+apn9g06TWWpWHUoQqMojIS3AQFRhmYA/VsM1+2OzNzWQe59w59yG1Xfef/tNwFG0r/fXcb2DD5d2+oXNZllXV8/0ojq+3G8A9mQtRXC70nGO9XK9VVZ2LAvsTpQDR/FxcbmVVJ1mW+f5OX+ry3DAMVVMlBCirKghDd7eDh1HkHw5739/YNtw/BEHoEqLYjnYOvC7LRBS2cdQ2Tc1YT8Y/W8cBFmtyPK43m53nYYV9TOcbW7Ptt5U5jj3S0hM7ZSw4iKZ5yH5k26fWxUlirFbEdU3LWupLRVUcsjCMF90YV/QkioJnKT8mgnMxkFEPZA5ymmVf6zVxCUKsTFNRVcdRPz9/fdmzEprTtIljUZZ3ljT0QHz/fExTcKDfsixtoU1nU4I45pu2eC1oUgf+wOzJZVl6+z3Nc8bYXfZS11G298lEVpTRaAT9DplNJs/j8ZNH1qKnPXopVXUNnUBAIdD2dgs+VOAe9YQQmlPWsJpVOHLOf07BH9kN5+gZWgPyMEbdP+an634Dt35n+UM7BVEAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Cat picture using srcset" title="" src="/static/dbcaa7867cc1481e522b666ffbd0e07f/5a190/srcset-width-descriptors.png" srcset="/static/dbcaa7867cc1481e522b666ffbd0e07f/01bf6/srcset-width-descriptors.png 270w, /static/dbcaa7867cc1481e522b666ffbd0e07f/07484/srcset-width-descriptors.png 540w, /static/dbcaa7867cc1481e522b666ffbd0e07f/5a190/srcset-width-descriptors.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" decoding="async" /> </a> </span></p> <p>When you use width descriptors, you’re providing the browser with a list of images and their true width so that it can select the best source based on the viewport size.</p> <h2 id="using-svgs" style="position:relative;"><a href="#using-svgs" aria-label="using svgs permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 SVGs</h2> <p>SVG is a scalable vector format which works great for logos, icons, text, and simple images. Here are a couple reasons why you would consider using them:</p> <ul> <li>SVGs are automatically scalable in both browsers and photo editing tools. This is a dream for a web and graphic designers!</li> <li>Google indexes SVGs, the same way it does PNGs and JPGs, so you don’t have to worry about SEO.</li> <li>SVGs are traditionally (not always) smaller in file size than PNGs or JPGs. This can result in faster load times.</li> </ul> <p>Here is an example to show you how much difference it can have (Images from <a href="https://genkihagata.com" target="_blank" rel="nofollow noopener noreferrer">https://genkihagata.com</a>):</p> <table> <thead> <tr> <th align="center"><strong>JPEG</strong></th> </tr> </thead> <tbody> <tr> <td align="center"><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/39d7d939e8db298746ac301d7cd1204d/eea4a/boatscape_b.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAME/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHRMubA/8QAFhABAQEAAAAAAAAAAAAAAAAAEQEA/9oACAEBAAEFAmYizf/EABYRAQEBAAAAAAAAAAAAAAAAAAARAf/aAAgBAwEBPwGrr//EABYRAAMAAAAAAAAAAAAAAAAAAAABEv/aAAgBAgEBPwGUSj//xAAXEAADAQAAAAAAAAAAAAAAAAAAATEQ/9oACAEBAAY/ApkR/8QAGhABAAIDAQAAAAAAAAAAAAAAAQARIUFRgf/aAAgBAQABPyFTWLWrHIEUF5P/2gAMAwEAAgADAAAAEPQP/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAh/9oACAEDAQE/EFpsv//EABcRAQEBAQAAAAAAAAAAAAAAAAEAIWH/2gAIAQIBAT8QAcuN/8QAGhABAAIDAQAAAAAAAAAAAAAAAQARQXGRsf/aAAgBAQABPxCsV62eSzOiuwUOMBn/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="JPG" title="" src="/static/39d7d939e8db298746ac301d7cd1204d/47311/boatscape_b.jpg" srcset="/static/39d7d939e8db298746ac301d7cd1204d/6f81f/boatscape_b.jpg 270w, /static/39d7d939e8db298746ac301d7cd1204d/09d21/boatscape_b.jpg 540w, /static/39d7d939e8db298746ac301d7cd1204d/47311/boatscape_b.jpg 1080w, /static/39d7d939e8db298746ac301d7cd1204d/eea4a/boatscape_b.jpg 1280w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></td> </tr> <tr> <td align="center">Size: 81.4KB</td> </tr> </tbody> </table> <br/> <table> <thead> <tr> <th align="center"><strong>PNG</strong></th> </tr> </thead> <tbody> <tr> <td align="center"><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/6cafe49417919c68012b51e78b9ac1d0/21b4d/boatscape_b.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAABo0lEQVR42n3L22vTYBgG8PyDu/bC3enFcKtaJE0P6bYcvjRdsiz5cq5J2m8zS7vm4JrYuY0dCjsgSEHBMVBhHYwpKHihVyKYiReiIPx4L97nebBUKRz1yC2P8JeLkC3J1COeJTm6tgjoGsdX58lipXoPr80US3cLD2/dmZ2anpkrFtpmuetVsfcHzOSYn5w0z3eZWMfXJHzDqGSrC8oSydLzCwxdpSiiTs7hlduzpQdl4nATfBiL39+u/HgnYZMRmIwWL4/A1Yulj2Px82vpyxvp67l8/VLYjzlRblRY7n6dqQHqechcnDa/nQmfXolnx+bh7hqWpNF2ZI4CerRaPkD4HiLGG8QzVH+KqEHAmZZQF2QciIIqJZHVQXA9sJM07kTbTn8HM7pDPdjS/dR0OoaqqCq0ZR5CpanaTaOtoNDqDnQ/Uf0B9IfwSaYFw3xi97JWL8OAGwI3Al4M2psAZRxKzZb12NbEdr+B0oaX5BHnJdzNjX7J+yHrRjnsZvlbCJxcf8WwoAZlTeNb68CN/yj8DfvnFfKGy+tOrqE7oNX9z/gnMBIhqzkG0R0AAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="JPG" title="" src="/static/6cafe49417919c68012b51e78b9ac1d0/302a4/boatscape_b.png" srcset="/static/6cafe49417919c68012b51e78b9ac1d0/01bf6/boatscape_b.png 270w, /static/6cafe49417919c68012b51e78b9ac1d0/07484/boatscape_b.png 540w, /static/6cafe49417919c68012b51e78b9ac1d0/302a4/boatscape_b.png 1080w, /static/6cafe49417919c68012b51e78b9ac1d0/21b4d/boatscape_b.png 1280w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></td> </tr> <tr> <td align="center">Size: 85.1KB</td> </tr> </tbody> </table> <br/> <table> <thead> <tr> <th align="center"><strong>SVG</strong></th> </tr> </thead> <tbody> <tr> <td align="center"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 534.7" enable-background="new 0 0 1280 534.7"><g><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="131" y1="692.654" x2="1149" y2="-161.548"><stop offset="0" stop-color="#D2864A"></stop><stop offset=".576" stop-color="#7A898D"></stop><stop offset="1" stop-color="#3C4A57"></stop></linearGradient><path fill="url(#a)" d="M0-5.4h1280v542H0z"></path></g><g><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="294.611" y1="236.036" x2="184.739" y2="-65.835"><stop offset="0" stop-color="#D2864A"></stop><stop offset=".197" stop-color="#CE844A"></stop><stop offset=".383" stop-color="#C3804B"></stop><stop offset=".564" stop-color="#B0784D"></stop><stop offset=".743" stop-color="#956D4F"></stop><stop offset=".918" stop-color="#736052"></stop><stop offset="1" stop-color="#605854"></stop></linearGradient><path opacity=".22" fill="url(#b)" d="M385.1 203.1h-105L94.2-32.9h105l164.6 209.1z"></path><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="358.667" y1="200.556" x2="399.383" y2="-30.355"><stop offset="0" stop-color="#D2864A"></stop><stop offset=".197" stop-color="#CE844A"></stop><stop offset=".383" stop-color="#C3804B"></stop><stop offset=".564" stop-color="#B0784D"></stop><stop offset=".743" stop-color="#956D4F"></stop><stop offset=".918" stop-color="#736052"></stop><stop offset="1" stop-color="#605854"></stop></linearGradient><path opacity=".22" fill="url(#c)" d="M466.1 203.1h-93l-9.3-26.9L292-32.9h93l50.7 147.5 18.7 54.6 5 14.5z"></path><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="443.874" y1="216.529" x2="539.545" y2="-46.325"><stop offset="0" stop-color="#D2864A"></stop><stop offset=".288" stop-color="#D0854A"></stop><stop offset=".444" stop-color="#C8824B"></stop><stop offset=".569" stop-color="#BA7C4C"></stop><stop offset=".676" stop-color="#A7754E"></stop><stop offset=".773" stop-color="#8E6B50"></stop><stop offset=".862" stop-color="#6F5E53"></stop><stop offset=".944" stop-color="#4B5056"></stop><stop offset=".973" stop-color="#3C4A57"></stop></linearGradient><path opacity=".22" fill="url(#d)" d="M576.4-32.9L528 116.7 512.7 164 500 203.1h-93l28.7-88.5 47.7-147.5z"></path><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="608.784" y1="238.684" x2="662.946" y2="-68.483"><stop offset="0" stop-color="#D2864A"></stop><stop offset=".2" stop-color="#CF854A"></stop><stop offset=".358" stop-color="#C5814B"></stop><stop offset=".502" stop-color="#B47A4D"></stop><stop offset=".637" stop-color="#9D714F"></stop><stop offset=".766" stop-color="#7E6451"></stop><stop offset=".89" stop-color="#595654"></stop><stop offset=".973" stop-color="#3C4A57"></stop></linearGradient><path opacity=".22" fill="url(#e)" d="M864.8-32.9l-194 138.2-137.2 97.8H407l47.4-34 73.6-52.4L737.4-32.9z"></path><linearGradient id="f" gradientUnits="userSpaceOnUse" x1="712.124" y1="345.401" x2="1012.582" y2="-175.007"><stop offset=".456" stop-color="#D2864A"></stop><stop offset=".479" stop-color="#C8824B"></stop><stop offset=".599" stop-color="#966E4F"></stop><stop offset=".712" stop-color="#6F5E53"></stop><stop offset=".815" stop-color="#535355"></stop><stop offset=".905" stop-color="#424C56"></stop><stop offset=".973" stop-color="#3C4A57"></stop></linearGradient><path opacity=".12" fill="url(#f)" d="M1258.7-32.9l-672.6 246h-94.4l-25.7-9.8 55.6-10 522-226.2z"></path><path fill="#EBD08D" d="M1301.9 59.6c0-14.5-11.7-26.2-26.2-26.2-7.3 0-14 3-18.7 7.9-6.6-5.7-15.2-9.2-24.6-9.2-10 0-19 3.9-25.8 10.2-6.5-2.5-13.5-3.8-20.9-3.8-17.4 0-33 7.5-43.8 19.5-2.6-1.2-5.5-2-8.6-2-11 0-19.9 8.9-19.9 19.9 0 1.6.2 3.1.6 4.6-3.3-1.1-6.7-1.7-10.4-1.7-11.5 0-21.6 6-27.4 15.1-1.2-6.6-7-11.5-13.9-11.5-7.8 0-14.1 6.3-14.1 14.1v.3c-1.8-.5-3.8-.7-5.8-.7-13.4 0-24.2 10.8-24.2 24.2 0 2.9.5 5.6 1.4 8.2-3 1.3-5.1 4.3-5.1 7.7 0 .3 0 .6.1.9-3-1.8-6.5-2.9-10.3-2.9-10.3 0-18.7 7.9-19.5 18-4.4-4.2-10.3-6.8-16.8-6.8-13.4 0-24.2 10.8-24.2 24.2v.2l-.9.3c-3.2-2.5-7.2-3.9-11.5-3.9-1 0-2 .1-3 .3-3.5-2.9-8-4.6-12.9-4.6-9.8 0-18 7-19.8 16.4-5.1 2.4-9.1 6.7-10.9 12.1-1.5-.5-3.1-.8-4.8-.8-8.4 0-15.3 6.8-15.3 15.2 0 8.4 6.8 15.2 15.3 15.2h407V83.3c8.8-4.2 14.9-13.2 14.9-23.7z"></path><path fill="#859DAD" d="M-9 303.5h1289v233.1H-9z"></path><circle fill="#F2AC66" cx="419.6" cy="203.1" r="46.4"></circle><path opacity=".8" fill="#EBD08D" d="M274.2 121.2c-5.9 0-11.6 1-16.8 2.9 5.3-4 8.7-10.4 8.7-17.5 0-12.1-9.8-22-22-22-6.5 0-12.4 2.9-16.4 7.4l-1.9-.2c1.2-3.3 1.9-6.9 1.9-10.6 0-16.9-13.7-30.5-30.5-30.5-9.8 0-18.5 4.6-24.1 11.8-5.3-12.5-17.6-21.3-32.1-21.3-10 0-19 4.2-25.3 10.9-3.3-12.6-14.8-21.9-28.5-21.9-16.3 0-29.5 13.2-29.5 29.5 0 1.6.1 3.2.4 4.8-8.3 1.3-15.8 5-21.7 10.3-2.9-.5-5.9-.8-9-.8-28.8 0-52.1 23.3-52.1 52 0 14.6 5.7 27.8 15.7 37.3v59.8h283.2c28.1 0 50.9-22.8 50.9-51 0-28.1-22.8-50.9-50.9-50.9z"></path><path fill="#A0ADB7" d="M25.3 217.4l29.9-6.1 18 16.5 17.8 4.3 9 8h13l5 7 44 15 13-8 15 3 7 10.2 15 4.8 5 7.7 25 5.3 12 11 17-7h8l17 7h26l19 5 36-8 12 1 18 13 64-10 19-3h16l20 4 9 2h20l10-7h18l9 1h15l10-1.8 8-12.2h24l25-7 15 1.9 11-7.9h31l26 .2 16-3.4 23 8.2 38 2 53-21 12-3 10-7h12l41 7 31 5 20-12 28 4 22-11h11l71-33 18-5 26-8 16-9 10-19 26 7 26.2 3 19.8 1v143H-9v-100l19-4z"></path><path fill="#EBD08D" d="M673.9 209.2c-1.4 0-2.7.3-3.8 1l-1-.4c0-.4.1-.8.1-1.2 0-7.4-6-13.5-13.5-13.5-2.7 0-5.2.8-7.3 2.1-2.2-8.6-10-15.1-19.3-15.1-5.1 0-9.7 1.9-13.2 5-3-10.6-12.7-18.4-24.2-18.4-.6 0-1.2 0-1.8.1-4.1-12.1-15.5-20.8-28.9-20.8-4.8 0-9.4 1.1-13.4 3.1-4.6-4.6-11-7.5-18-7.6-1-9.8-9.3-17.4-19.3-17.4-8.5 0-15.7 5.5-18.3 13.1-2.5-5.7-7-10.3-12.7-12.8 2.3-2.9 3.7-6.6 3.7-10.5 0-9.4-7.6-17-17-17s-17 7.6-17 17c-10 2.6-17.4 11.8-17.4 22.6 0 1.7.2 3.3.5 4.8-4.4-2.8-9.6-4.4-15.2-4.4-3.9 0-7.5.8-10.9 2.2-3.8-7.2-11.3-12.1-20-12.1-5.1 0-9.8 1.7-13.5 4.5-3.8-5.6-10.2-9.2-17.4-9.2-11.6 0-21 9.4-21 21 0 1.5.2 3 .5 4.5-.6-.1-1.2-.1-1.9-.1-7.9 0-14.3 6.1-14.8 13.9-3.1-1.2-6.5-1.9-10-1.9-10.8 0-20.1 6.4-24.4 15.5-3.2-1.8-6.9-2.9-10.9-2.9-12 0-21.8 9.8-21.8 21.8l-3.1.4c-1.9-1.5-4.2-2.4-6.8-2.4-3.6 0-6.9 1.8-8.8 4.6l-4.2.6c-2.2-3.1-5.9-5.2-10-5.2-5.3 0-9.9 3.4-11.6 8.2l-1.7.2c-1.9-2.7-5-4.5-8.5-4.5-3.7 0-7 2-8.8 4.9-1.6-4.3-5.7-7.4-10.5-7.4-6.2 0-11.2 5-11.2 11.2v.2c-1.6-2.9-4.7-4.9-8.3-4.9-4.8 0-8.8 3.6-9.4 8.2-1.6-1.8-4-2.9-6.6-2.9-4.9 0-8.8 4-8.8 8.9 0 4.5 2.8 8.3 7.8 8.8v.2h533.9c4.4 0 7.9-3.6 7.9-8-.3-4.4-3.8-8-8.2-8z"></path><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="535.212" y1="308.863" x2="547.588" y2="544.998"><stop offset="0" stop-color="#D2864A"></stop><stop offset=".973" stop-color="#7A898D"></stop></linearGradient><path opacity=".37" fill="url(#g)" d="M709.1 536.5l-324-1.8 12-218.6h75z"></path></g></svg></td> </tr> <tr> <td align="center">Size: 6.1KB</td> </tr> </tbody> </table> <h2 id="lazy-loading-images" style="position:relative;"><a href="#lazy-loading-images" aria-label="lazy loading images permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Lazy loading images</h2> <p>When we consider all we’ve gone through so far, you would realise at some point that it is not enough to make images smaller anymore. Especially if you have too many of them in the page. This is where we need to make sure our web page loads with them fast instead.</p> <p>This is where lazy loading comes to rescue. Let’s see a demonstration on how it works (video from <a href="https://css-tricks.com" target="_blank" rel="nofollow noopener noreferrer">CSS Tricks</a>):</p> <div class="gatsby-resp-iframe-wrapper" style="padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem" > <iframe id="ytplayer" type="text/html" src="https://www.youtube.com/embed/CPmNHj9a0JI?autoplay=0&amp;origin=https://yashints.dev" frameborder="0" style=" position: absolute; top: 0; left: 0; width: 100%; height: 100%; "></iframe> </div> <h3 id="what-is-it" style="position:relative;"><a href="#what-is-it" aria-label="what is 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>What is it?</h3> <p>Lazy loading images is simply the act of not loading images until a later point in time. It is a technique in web development which applies to many other form of resources, but here we are focusing on images.</p> <blockquote> <p><strong>Wikipedia:</strong> Lazy loading is a design pattern commonly used in computer programming to defer initialization of an object until the point at which it is needed. It can contribute to efficiency in the program’s operation if properly and appropriately used.</p> </blockquote> <h3 id="how-it-is-done" style="position:relative;"><a href="#how-it-is-done" aria-label="how it is done permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 is done</h3> <p>Imagine you have a very long page with a lot of images. Why would the image at the bottom of the page get loaded if the user cannot see it. As simple as that, you can load the image on an event like when that part of the page is visible (using scroll event handler) or any other event. But not just when the page loads.</p> <p>Apart from that, if the user never scrolls down, that image wouldn’t get loaded, resulting in saving some network traffic and data usage for the end user.</p> <p>You will start to see a lot of benefits considering how much impact this has on the overall page load time and speed.</p> <h3 id="lazy-loading-techniques" style="position:relative;"><a href="#lazy-loading-techniques" aria-label="lazy loading techniques permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Lazy loading techniques</h3> <p>There are two common ways of loading an image on a page, using an <code class="language-text">img</code> tag, and CSS <code class="language-text">background-image</code>. Let’s start with the image tag.</p> <h4 id="image-tag" style="position:relative;"><a href="#image-tag" aria-label="image tag permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 tag</h4> <p>Here is a simple image tag we normally use to load an image:</p> <div class="gatsby-code-button-container" data-toaster-id="85675374935208250000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img src=&quot;/path/to/some/cat/image.jpg&quot; />`, `85675374935208250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</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>/path/to/some/cat/image.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The markup for lazy loading images is pretty similar. The <code class="language-text">src</code> attribute is the trigger for the browser to send a network request and fetch the image. No matter if this is the first or the 50th image on your page.</p> <p>To defer the load, simply use <code class="language-text">data-src</code> attribute.</p> <div class="gatsby-code-button-container" data-toaster-id="78930066078370410000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<img data-src=&quot;/path/to/some/cat/image.jpg&quot; />`, `78930066078370410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">data-src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/path/to/some/cat/image.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Since the <code class="language-text">src</code> is empty the browser doesn’t load the image when the tag is rendered. Now it is just the matter of triggering the load which normally is done when the image is entered the viewport.</p> <p>We can use events like <code class="language-text">scroll</code>, <code class="language-text">resize</code>, and <code class="language-text">orientationChange</code> to figure out when to trigger the load. The scroll event is pretty clear, when the user scrolls if the image tag is on the page then we trigger the load and tell the browser to fetch the image. However, the resize and orientation change events are equally important. The resize is when the user changes the window size like when they make the window smaller. The orientation change happens when the user rotates their device.</p> <p>Once we hook into these events, we can enable lazy loading and the result is really good:</p> <div class="gatsby-code-button-container" data-toaster-id="33649316779303030000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`document.addEventListener( 'DOMContentLoaded', function() { var lazyloadImages = document.querySelectorAll( 'img.lazy' ) var lazyloadThrottleTimeout function lazyload() { if (lazyloadThrottleTimeout) { clearTimeout(lazyloadThrottleTimeout) } lazyloadThrottleTimeout = setTimeout( function() { var scrollTop = window.pageYOffset lazyloadImages.forEach(function(img) { if ( img.offsetTop < window.innerHeight + scrollTop ) { img.src = img.dataset.src img.classList.remove('lazy') } }) if (lazyloadImages.length == 0) { document.removeEventListener( 'scroll', lazyload ) window.removeEventListener( 'resize', lazyload ) window.removeEventListener( 'orientationChange', lazyload ) } }, 20 ) } document.addEventListener('scroll', lazyload) window.addEventListener('resize', lazyload) window.addEventListener( 'orientationChange', lazyload ) } )`, `33649316779303030000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> lazyloadImages <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span> <span class="token string">'img.lazy'</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> lazyloadThrottleTimeout <span class="token keyword">function</span> <span class="token function">lazyload</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>lazyloadThrottleTimeout<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>lazyloadThrottleTimeout<span class="token punctuation">)</span> <span class="token punctuation">}</span> lazyloadThrottleTimeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> scrollTop <span class="token operator">=</span> window<span class="token punctuation">.</span>pageYOffset lazyloadImages<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">img</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> img<span class="token punctuation">.</span>offsetTop <span class="token operator">&lt;</span> window<span class="token punctuation">.</span>innerHeight <span class="token operator">+</span> scrollTop <span class="token punctuation">)</span> <span class="token punctuation">{</span> img<span class="token punctuation">.</span>src <span class="token operator">=</span> img<span class="token punctuation">.</span>dataset<span class="token punctuation">.</span>src img<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">'lazy'</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>lazyloadImages<span class="token punctuation">.</span>length <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'scroll'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'resize'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'orientationChange'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">20</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> lazyload<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'resize'</span><span class="token punctuation">,</span> lazyload<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'orientationChange'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="using-intersection-api" style="position:relative;"><a href="#using-intersection-api" aria-label="using intersection 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>Using intersection API</h3> <p>Let’s see what this API offers:</p> <blockquote> <p>The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport.</p> </blockquote> <p>Opposite to the previous technique where you might see some performance impact on the page because of all of those event handlers, this approach is relatively new.</p> <p>This API removes the previous performance hit by doing the math and delivering a very efficient way to call a callback function when the resource is on screen:</p> <div class="gatsby-code-button-container" data-toaster-id="80145732361405560000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`document.addEventListener( 'DOMContentLoaded', function() { var lazyloadImages if ('IntersectionObserver' in window) { lazyloadImages = document.querySelectorAll( '.lazy' ) var imageObserver = new IntersectionObserver( function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { var image = entry.target image.src = image.dataset.src image.classList.remove('lazy') imageObserver.unobserve(image) } }) } ) lazyloadImages.forEach(function(image) { imageObserver.observe(image) }) } else { var lazyloadThrottleTimeout lazyloadImages = document.querySelectorAll( '.lazy' ) function lazyload() { if (lazyloadThrottleTimeout) { clearTimeout(lazyloadThrottleTimeout) } lazyloadThrottleTimeout = setTimeout( function() { var scrollTop = window.pageYOffset lazyloadImages.forEach(function(img) { if ( img.offsetTop < window.innerHeight + scrollTop ) { img.src = img.dataset.src img.classList.remove('lazy') } }) if (lazyloadImages.length == 0) { document.removeEventListener( 'scroll', lazyload ) window.removeEventListener( 'resize', lazyload ) window.removeEventListener( 'orientationChange', lazyload ) } }, 20 ) } document.addEventListener( 'scroll', lazyload ) window.addEventListener('resize', lazyload) window.addEventListener( 'orientationChange', lazyload ) } } )`, `80145732361405560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> lazyloadImages <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">'IntersectionObserver'</span> <span class="token keyword">in</span> window<span class="token punctuation">)</span> <span class="token punctuation">{</span> lazyloadImages <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span> <span class="token string">'.lazy'</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> imageObserver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">IntersectionObserver</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">entries<span class="token punctuation">,</span> observer</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> entries<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">entry</span><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> <span class="token keyword">var</span> image <span class="token operator">=</span> entry<span class="token punctuation">.</span>target image<span class="token punctuation">.</span>src <span class="token operator">=</span> image<span class="token punctuation">.</span>dataset<span class="token punctuation">.</span>src image<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">'lazy'</span><span class="token punctuation">)</span> imageObserver<span class="token punctuation">.</span><span class="token function">unobserve</span><span class="token punctuation">(</span>image<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> lazyloadImages<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">image</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> imageObserver<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>image<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">var</span> lazyloadThrottleTimeout lazyloadImages <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span> <span class="token string">'.lazy'</span> <span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">lazyload</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>lazyloadThrottleTimeout<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>lazyloadThrottleTimeout<span class="token punctuation">)</span> <span class="token punctuation">}</span> lazyloadThrottleTimeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> scrollTop <span class="token operator">=</span> window<span class="token punctuation">.</span>pageYOffset lazyloadImages<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">img</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> img<span class="token punctuation">.</span>offsetTop <span class="token operator">&lt;</span> window<span class="token punctuation">.</span>innerHeight <span class="token operator">+</span> scrollTop <span class="token punctuation">)</span> <span class="token punctuation">{</span> img<span class="token punctuation">.</span>src <span class="token operator">=</span> img<span class="token punctuation">.</span>dataset<span class="token punctuation">.</span>src img<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">'lazy'</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>lazyloadImages<span class="token punctuation">.</span>length <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'scroll'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'resize'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'orientationChange'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">20</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'scroll'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'resize'</span><span class="token punctuation">,</span> lazyload<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'orientationChange'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We attach the observer on all the images we want to be lazy loaded. When the API detects that the element has entered the viewport, using the <code class="language-text">isIntersecting</code> property, we pick the URL from the <code class="language-text">data-src</code> attribute and move it to the <code class="language-text">src</code> attribute for the browser to trigger the image load like before. Once this is done, we remove the lazy class from the image and also remove the observer from that image.</p> <h3 id="css-background-image" style="position:relative;"><a href="#css-background-image" aria-label="css background image permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CSS background image</h3> <p>CSS background images are not as straightforward as the image tag. To load them the browser needs to build both the DOM tree and CSSDOM tree (<a href="/2018/09/29/web-perf-1">see here</a>). If the CSS rule is applicable to the node the browser loads it, otherwise doesn’t. So all we need to do is to not give it a background property by default and add it when it’s visible:</p> <div class="gatsby-code-button-container" data-toaster-id="53332091288724630000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`document.addEventListener( 'DOMContentLoaded', function() { var lazyloadImages if ('IntersectionObserver' in window) { lazyloadImages = document.querySelectorAll( '.lazy' ) var imageObserver = new IntersectionObserver( function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { var image = entry.target image.classList.remove('lazy') imageObserver.unobserve(image) } }) } ) lazyloadImages.forEach(function(image) { imageObserver.observe(image) }) } else { var lazyloadThrottleTimeout lazyloadImages = document.querySelectorAll( '.lazy' ) function lazyload() { if (lazyloadThrottleTimeout) { clearTimeout(lazyloadThrottleTimeout) } lazyloadThrottleTimeout = setTimeout( function() { var scrollTop = window.pageYOffset lazyloadImages.forEach(function(img) { if ( img.offsetTop < window.innerHeight + scrollTop ) { img.src = img.dataset.src img.classList.remove('lazy') } }) if (lazyloadImages.length == 0) { document.removeEventListener( 'scroll', lazyload ) window.removeEventListener( 'resize', lazyload ) window.removeEventListener( 'orientationChange', lazyload ) } }, 20 ) } document.addEventListener( 'scroll', lazyload ) window.addEventListener('resize', lazyload) window.addEventListener( 'orientationChange', lazyload ) } } )`, `53332091288724630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> lazyloadImages <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">'IntersectionObserver'</span> <span class="token keyword">in</span> window<span class="token punctuation">)</span> <span class="token punctuation">{</span> lazyloadImages <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span> <span class="token string">'.lazy'</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> imageObserver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">IntersectionObserver</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">entries<span class="token punctuation">,</span> observer</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> entries<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">entry</span><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> <span class="token keyword">var</span> image <span class="token operator">=</span> entry<span class="token punctuation">.</span>target image<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">'lazy'</span><span class="token punctuation">)</span> imageObserver<span class="token punctuation">.</span><span class="token function">unobserve</span><span class="token punctuation">(</span>image<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> lazyloadImages<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">image</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> imageObserver<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>image<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">var</span> lazyloadThrottleTimeout lazyloadImages <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span> <span class="token string">'.lazy'</span> <span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">lazyload</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>lazyloadThrottleTimeout<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>lazyloadThrottleTimeout<span class="token punctuation">)</span> <span class="token punctuation">}</span> lazyloadThrottleTimeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> scrollTop <span class="token operator">=</span> window<span class="token punctuation">.</span>pageYOffset lazyloadImages<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">img</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> img<span class="token punctuation">.</span>offsetTop <span class="token operator">&lt;</span> window<span class="token punctuation">.</span>innerHeight <span class="token operator">+</span> scrollTop <span class="token punctuation">)</span> <span class="token punctuation">{</span> img<span class="token punctuation">.</span>src <span class="token operator">=</span> img<span class="token punctuation">.</span>dataset<span class="token punctuation">.</span>src img<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">'lazy'</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>lazyloadImages<span class="token punctuation">.</span>length <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'scroll'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'resize'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span> <span class="token string">'orientationChange'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">20</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'scroll'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'resize'</span><span class="token punctuation">,</span> lazyload<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'orientationChange'</span><span class="token punctuation">,</span> lazyload <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And:</p> <div class="gatsby-code-button-container" data-toaster-id="73335456759158670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`#bg-image.lazy { background-image: none; background-color: #f1f1fa; } #bg-image { background-image: url('path/to/some/cat/image.jpg'); max-width: 600px; height: 400px; }`, `73335456759158670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">#bg-image.lazy</span> <span class="token punctuation">{</span> <span class="token property">background-image</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #f1f1fa<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">#bg-image</span> <span class="token punctuation">{</span> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'path/to/some/cat/image.jpg'</span><span class="token punctuation">)</span></span><span class="token punctuation">;</span> <span class="token property">max-width</span><span class="token punctuation">:</span> 600px<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 400px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We’ve seen how to reduce the image size using different compression methods, how to load different sizes for different screen sizes and at last how to lazy load them. Using these techniques, you can improve the performance of the page so much it becomes a hobby for you after some time to play with.</p> <p>And as always please spread the word and behold for the next post on web fonts 😃👋.</p><![CDATA[Optimising JavaScript]]>https://yashints.dev/blog/2018/10/12/web-perf-3https://yashints.dev/blog/2018/10/12/web-perf-3Fri, 12 Oct 2018 00:00:00 GMT<p>Recently I had a chance to present a talk at <a href="https://ndcsydney.com/talk/need-for-speed-8-performance-tuning-of-your-web-application/" target="_blank" rel="nofollow noopener noreferrer">NDC Sydney</a> about web performance and it received a great feedback.</p> <!--more--> <p>That inspired me to write up a series of posts on each topic I covered in that talk, and who knows, maybe each of these posts would be a talk some day by their own 😃.</p> <p>All other parts:</p> <p><a href="/blog/2018/09/29/web-perf-1">Part 1 on HTML and CSS</a></p> <p><a href="/blog/2018/10/06/web-perf-2">Part 2 use Preload/Prefetch to boost load time</a></p> <p><a href="/blog/2018/11/12/web-perf-4">Part 4 Image optimisation</a></p> <p><a href="/blog/2018/11/23/web-perf-5">Part 5 Web font optimisation</a></p> <p>Time to see what we can do for our old friend JavaScript. So let’s begin.</p> <h1 id="switch-to-http2" style="position:relative;"><a href="#switch-to-http2" aria-label="switch to http2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Switch to HTTP/2</h1> <p>With more and more hosting providers supporting <a href="https://en.wikipedia.org/wiki/HTTP/2" target="_blank" rel="nofollow noopener noreferrer">HTTP/2</a>, it’s becoming a good time to switch to this protocol instead and benefit from its multiplexed nature. What it means in terms of performance is that we don’t need to bundle all of our JavaScript into large bundles to reduce the number of calls to server.</p> <p>With <strong>HTTP/2</strong> designed to handle large number of requests, you can now increase the number of files required to render the page. Not too much tho:</p> <blockquote> <p>Too much of a good thing is a bad thing.</p> </blockquote> <h1 id="async--defer" style="position:relative;"><a href="#async--defer" aria-label="async defer permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Async &#x26; Defer</h1> <p>As I mentioned before, JavaScript, like CSS is a <strong>render blocking</strong> element. This simply means the browser needs to wait for it to load and execute before it can parse the rest of the <code class="language-text">HTML</code> document.</p> <p>This hugely increases our <a href="https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint" target="_blank" rel="nofollow noopener noreferrer">First Meaningful Pain</a>. In order to fix this issue we can use two of the features which are not used by many people but are very effective.</p> <h3 id="normal-execution" style="position:relative;"><a href="#normal-execution" aria-label="normal execution permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Normal execution</h3> <p>When you use a <code class="language-text">&lt;script></code> to load a JavaScript file, it interrupts the parsing of the document. Browser fetches the resource, executes this and then continues on paring:</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/d562503683c7b6a3c0ee5ed90085f60c/78c62/normaljsexec.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 20.740740740740744%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAEABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/9oADAMBAAIQAxAAAAHVsQ7Gb//EABkQAAIDAQAAAAAAAAAAAAAAAAERAAISMf/aAAgBAQABBQLRaIlef//EABcRAAMBAAAAAAAAAAAAAAAAAAACMQH/2gAIAQMBAT8BTaLD/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAx/9oACAECAQE/AUnb/8QAGBAAAgMAAAAAAAAAAAAAAAAAAAEQMTL/2gAIAQEABj8Cs04//8QAGBAAAwEBAAAAAAAAAAAAAAAAAAERIXH/2gAIAQEAAT8hdashevR29On/2gAMAwEAAgADAAAAEPvf/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAEDAQE/EETTJRf/xAAWEQADAAAAAAAAAAAAAAAAAAAAASH/2gAIAQIBAT8QRBaP/8QAGRABAQADAQAAAAAAAAAAAAAAAREAIaEx/9oACAEBAAE/EJcALNGuZYGpShnMfrq+oZ//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Normal execution" title="" src="/static/d562503683c7b6a3c0ee5ed90085f60c/47311/normaljsexec.jpg" srcset="/static/d562503683c7b6a3c0ee5ed90085f60c/6f81f/normaljsexec.jpg 270w, /static/d562503683c7b6a3c0ee5ed90085f60c/09d21/normaljsexec.jpg 540w, /static/d562503683c7b6a3c0ee5ed90085f60c/47311/normaljsexec.jpg 1080w, /static/d562503683c7b6a3c0ee5ed90085f60c/78c62/normaljsexec.jpg 1589w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h3 id="the-code-classlanguage-textasynccode-attribute" style="position:relative;"><a href="#the-code-classlanguage-textasynccode-attribute" aria-label="the code classlanguage textasynccode attribute permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">Async</code> attribute</h3> <p>The <code class="language-text">Async</code> attribute is used to indicate that this resource can be executed asynchronously. The parsing doesn’t need to be halted, it can be done right after the resource is fetched from network and is ready.</p> <div class="gatsby-code-button-container" data-toaster-id="5274455938216605000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script async src=&quot;script.js&quot;>`, `5274455938216605000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">async</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>script.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This attribute can be used only on external JavaScript files. The file would be downloaded in parallel and once the download is finished, the parsing is paused for the script to be executed:</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/7d5975f30349a8282be6f1d8b956cde5/ac99c/asyncjs.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 22.59259259259259%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgAB/9oADAMBAAIQAxAAAAHZkRsZf//EABgQAAIDAAAAAAAAAAAAAAAAAAAiAhES/9oACAEBAAEFAnMztj//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8BjH//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPwGq/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAEyM5Gh/9oACAEBAAY/ApLCzhJYf//EABoQAAICAwAAAAAAAAAAAAAAAAABESFR0fD/2gAIAQEAAT8hXBsV1tGBBH//2gAMAwEAAgADAAAAEPPv/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAER4f/aAAgBAwEBPxBINLp//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8QYf/EABoQAQEBAAMBAAAAAAAAAAAAAAERACExYbH/2gAIAQEAAT8QozNTYS9QZPgl7b93/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Async execution" title="" src="/static/7d5975f30349a8282be6f1d8b956cde5/47311/asyncjs.jpg" srcset="/static/7d5975f30349a8282be6f1d8b956cde5/6f81f/asyncjs.jpg 270w, /static/7d5975f30349a8282be6f1d8b956cde5/09d21/asyncjs.jpg 540w, /static/7d5975f30349a8282be6f1d8b956cde5/47311/asyncjs.jpg 1080w, /static/7d5975f30349a8282be6f1d8b956cde5/ac99c/asyncjs.jpg 1536w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h3 id="the-code-classlanguage-textdefercode-attribute" style="position:relative;"><a href="#the-code-classlanguage-textdefercode-attribute" aria-label="the code classlanguage textdefercode attribute permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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">Defer</code> attribute</h3> <p>The <code class="language-text">Defer</code> attribute is used to tell the browser to execute this script after parsing the whole document.</p> <div class="gatsby-code-button-container" data-toaster-id="5962054863523169000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script defer src=&quot;script.js&quot;>`, `5962054863523169000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">defer</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>script.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Like <code class="language-text">Async</code> this file gets downloaded in parallel but the execution only happens when the whole <code class="language-text">HTML</code> document is parsed:</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/61e576b9875fc024a3679482e7e2398a/ac99c/deferjs.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 22.59259259259259%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAEDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAdmBC8F//8QAGBAAAgMAAAAAAAAAAAAAAAAAAQIAECL/2gAIAQEAAQUC1FDiv//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAcEAAABgMAAAAAAAAAAAAAAAAAAQIQESExgZH/2gAIAQEABj8CyXBa503/xAAZEAACAwEAAAAAAAAAAAAAAAABEQAQIUH/2gAIAQEAAT8hZ5UABnXP/9oADAMBAAIAAwAAABB4D//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QH//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/EFn/xAAbEAEAAgIDAAAAAAAAAAAAAAABABEhQWFxof/aAAgBAQABPxDKBXvX2KUBXdU6pgRSuTP/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Deferred execution" title="" src="/static/61e576b9875fc024a3679482e7e2398a/47311/deferjs.jpg" srcset="/static/61e576b9875fc024a3679482e7e2398a/6f81f/deferjs.jpg 270w, /static/61e576b9875fc024a3679482e7e2398a/09d21/deferjs.jpg 540w, /static/61e576b9875fc024a3679482e7e2398a/47311/deferjs.jpg 1080w, /static/61e576b9875fc024a3679482e7e2398a/ac99c/deferjs.jpg 1536w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>At the end remember to put all of your <code class="language-text">script</code> tags right at the end of the <code class="language-text">body</code> to prevent more delay in parsing your <code class="language-text">HTML</code>.</p> <p>As for the browser support, fortunately these attributes are fully supported by all of the major ones.</p> <h1 id="code-splitting" style="position:relative;"><a href="#code-splitting" aria-label="code splitting permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 splitting</h1> <p>Most of the modern sites will bundle all of their JavaScript into one, resulting in an increase in load time and suffering from load performance.</p> <p>Code splitting allows you to split your application code into separate chunks and lazy load them when needed. This also means minimum required code to client and improve the page load time.</p> <p>You can split your code in three areas:</p> <ul> <li>Vendor code</li> <li>Entry point</li> <li>Dynamic splitting</li> </ul> <h2 id="vendor-code" style="position:relative;"><a href="#vendor-code" aria-label="vendor 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>Vendor code</h2> <p>Vendor code like Angular, React, moment, etc. can be separated from your main code. <a href="https://webpack.js.org/" target="_blank" rel="nofollow noopener noreferrer">Webpack</a> has full support for this and other methods. This technique allows you to have better control over cache invalidation of your bundles whenever your app or vendor code changes independently of one another.</p> <p>This is something every app should do.</p> <h2 id="entry-point" style="position:relative;"><a href="#entry-point" aria-label="entry point permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Entry point</h2> <p>This technique separates your code by entry points in your app. These points are where bundlers like webpack start from, when they build a dependency tree of your app.</p> <p>This is bar far the easiest way to split code, but it is manual and has some pitfalls:</p> <ul> <li>If there are any duplicated modules between entry points, they will be bundled in both.</li> <li>It isn’t as flexible and cannot be used to dynamically split code with your app logic.</li> </ul> <p>This technique is not suitable for when you have client side routing or when you have a mix of server side rendering and a single page app.</p> <h2 id="dynamic-splitting" style="position:relative;"><a href="#dynamic-splitting" aria-label="dynamic splitting permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Dynamic splitting</h2> <p>Separate code when dynamic <code class="language-text">import</code> are used. This is the best option for single page applications. Having different modules for different routes in your SPA is an example of this.</p> <h2 id="do-i-even-need-code-splitting" style="position:relative;"><a href="#do-i-even-need-code-splitting" aria-label="do i even need code splitting permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Do I even need code splitting?</h2> <p>This is one of many times when you hear me say it depends (I am a consultant after all 😉). If your app has many routes with isolated functionality and heavily uses frameworks and libraries, this answer is most probably <strong>YES</strong>.</p> <p>However, it is up to you to decide whether you need it or not by your own understanding of your app structure and code.</p> <h1 id="import-wisely" style="position:relative;"><a href="#import-wisely" aria-label="import wisely permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 wisely</h1> <p>If you use <code class="language-text">npm</code> or other package management systems for your dependencies, then you will have a lot of extra and unneeded files in your buid folder.</p> <p>When using a framework or a library, make sure you investigate wether they have separate modules you can import and if yes, only import what you need.</p> <p>For instance, let’s assume you are using <a href="https://underscorejs.org/" target="_blank" rel="nofollow noopener noreferrer">underscore</a>, but only use <code class="language-text">groupBy</code>, <code class="language-text">shuffle</code>, and <code class="language-text">partition</code>. Most people import the whole library like this:</p> <div class="gatsby-code-button-container" data-toaster-id="40354089697499960000" data-toaster-class="gatsby-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 * as _ from 'underscore'`, `40354089697499960000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> _ <span class="token keyword">from</span> <span class="token string">'underscore'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Instead of this, you could just import what you need:</p> <div class="gatsby-code-button-container" data-toaster-id="71779213836307830000" data-toaster-class="gatsby-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 { groupBy, shuffle, partition, } from 'underscore'`, `71779213836307830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> groupBy<span class="token punctuation">,</span> shuffle<span class="token punctuation">,</span> partition<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'underscore'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This way you only bring what your need and the bundlers will take care of the rest for you. Your total package size and as a result your page load time will decrease.</p> <h1 id="throttling-and-debounce" style="position:relative;"><a href="#throttling-and-debounce" aria-label="throttling and debounce permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Throttling and debounce</h1> <p>Ok, enough about the size, let’s see where else we can improve our performance.</p> <p>Many times you have to add an event listener to do something, like listening to page scroll. Then we forget that the listener fires every time the event is triggered.</p> <div class="gatsby-code-button-container" data-toaster-id="9197828500468975000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`window.addEventListener('scroll', function() { console.log('page scrolled') })`, `9197828500468975000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js">window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'page scrolled'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>In the above example, the message is printed into console whenever you scroll. Imagine you have some heavy operation in that callback function, this would turn into a big performance bottleneck.</p> <p>If you can’t remove that event listener and use a different approach, then you can use either <code class="language-text">debounce</code> or <code class="language-text">throttle</code> to alleviate the situation.</p> <h2 id="debounce" style="position:relative;"><a href="#debounce" aria-label="debounce permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Debounce</h2> <p>This feature enforces a function call to not happen until some time has passed since it’s last call. For example, call the function if 100 millisecond has passed from it’s last call.</p> <p>Look at this implementation from underscore:</p> <div class="gatsby-code-button-container" data-toaster-id="13348049036230992000" data-toaster-class="gatsby-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 debounce = (func, delay) => { let inDebounce return function() { const context = this const args = arguments clearTimeout(inDebounce) inDebounce = setTimeout( () => func.apply(context, args), delay ) } }`, `13348049036230992000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">debounce</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> delay</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> inDebounce <span class="token keyword">return</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">const</span> context <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token keyword">const</span> args <span class="token operator">=</span> arguments <span class="token function">clearTimeout</span><span class="token punctuation">(</span>inDebounce<span class="token punctuation">)</span> inDebounce <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">,</span> delay <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now we can debounce our event listener for every 100 millisecond:</p> <div class="gatsby-code-button-container" data-toaster-id="89680252233830470000" data-toaster-class="gatsby-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 efficientScrollListener = debounce( function() { console.log('page scrolled') }, 100 ) window.addEventListener( 'scroll', efficientScrollListener )`, `89680252233830470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> efficientScrollListener <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'page scrolled'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">100</span> <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'scroll'</span><span class="token punctuation">,</span> efficientScrollListener <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="throttle" style="position:relative;"><a href="#throttle" aria-label="throttle permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Throttle</h2> <p>Throttling is similar to debounce but different since it will enforce the maximum number of times a function can be called over a period of time. For example execute this function once every 100 millisecond.</p> <p>Here is a simple implementation:</p> <div class="gatsby-code-button-container" data-toaster-id="75573897677419150000" data-toaster-class="gatsby-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 throttle = (func, limit) => { let inThrottle return function() { const args = arguments const context = this if (!inThrottle) { func.apply(context, args) inThrottle = true setTimeout( () => (inThrottle = false), limit ) } } }`, `75573897677419150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">throttle</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> limit</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> inThrottle <span class="token keyword">return</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">const</span> args <span class="token operator">=</span> arguments <span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>inThrottle<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> args<span class="token punctuation">)</span> inThrottle <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token function">setTimeout</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>inThrottle <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span> limit <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now we can throttle our scroll event listener:</p> <div class="gatsby-code-button-container" data-toaster-id="20859003883924586000" data-toaster-class="gatsby-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 efficientScrollListener = throttle( function() { console.log('page scrolled') }, 100 ) window.addEventListener( 'scroll', efficientScrollListener )`, `20859003883924586000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> efficientScrollListener <span class="token operator">=</span> <span class="token function">throttle</span><span class="token punctuation">(</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'page scrolled'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">100</span> <span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token string">'scroll'</span><span class="token punctuation">,</span> efficientScrollListener <span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h1 id="so-what" style="position:relative;"><a href="#so-what" aria-label="so 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>So what</h1> <p>I hope I have given you enough information on just some of the areas you can focus to improve your applications performance when using JavaScript. If you would like to have other topics covered please comment below and I will add them here or in another post.</p> <p>And as always don’t forget to share the ❤️.</p><![CDATA[How to use Preload/Prefetch to boost load time]]>https://yashints.dev/blog/2018/10/06/web-perf-2https://yashints.dev/blog/2018/10/06/web-perf-2Sat, 06 Oct 2018 00:00:00 GMT<p>Recently I had a chance to present a talk at <a href="https://ndcsydney.com/talk/need-for-speed-8-performance-tuning-of-your-web-application/" target="_blank" rel="nofollow noopener noreferrer">NDC Sydney</a> about web performance and it received a great feedback.</p> <!--more--> <p>That inspired me to write up a series of posts on each topic I covered in that talk, and who knows, maybe each of these posts would be a talk some day by their own 😃.</p> <p>Link to all other parts:</p> <p><a href="/blog/2018/09/29/web-perf-1">Part 1 on HTML and CSS</a></p> <p><a href="/blog/2018/10/12/web-perf-3">Part 3 JavaScript tips and tricks</a></p> <p><a href="/blog/2018/11/12/web-perf-4">Part 4 Image optimisation</a></p> <p><a href="/blog/2018/11/23/web-perf-5">Part 5 Web font optimisation</a></p> <p>OK, just to recap, here are the rules from part 1:</p> <ul> <li>Stream HTML to client</li> <li>Send minimal CSS and send it fast</li> </ul> <p>In this part, we’re going to see how we can request our resources before we need them. You might be wondering why we want to do so, and the answer is, if you want to send minimal CSS to client, or any other resource for that matter, you need to break them into smaller pieces and load them separately.</p> <p>There are some techniques which allow you to do it like lazy loading, but with lazy loading, user has to wait (most probably watching a spinner 😏) until the resource is loaded.</p> <p>But, we can do better. One of the letters from <a href="https://developers.google.com/web/fundamentals/performance/prpl-pattern/" target="_blank" rel="nofollow noopener noreferrer">PRPL pattern</a> stands for <code class="language-text">pre-cache</code>. An effective way to load your resources before they are required, cache them and then use them when they are needed. We can achieve this using <code class="language-text">preload</code> and <code class="language-text">prefetch</code> features of browsers.</p> <p>Before we go further into how, let me explain their difference:</p> <h3 id="preload" style="position:relative;"><a href="#preload" aria-label="preload permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Preload</h3> <p><code class="language-text">&lt;link rel="preload"></code> tells the browser that the resource should be loaded as part of the current navigation and it should start fetching it ASAP. This attribute can be applied to CSS, fonts, images, JavaScript files and more. When using this attribute you will also tell the browser what file type this file has, which can be set in an <code class="language-text">as</code> attribute:</p> <div class="gatsby-code-button-container" data-toaster-id="66134669378534320000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<link rel=&quot;preload&quot; as=&quot;script&quot; href=&quot;super-important.js&quot; /> <link rel=&quot;preload&quot; as=&quot;style&quot; href=&quot;critical.css&quot; />`, `66134669378534320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></span> <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>script<span class="token punctuation">"</span></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>super-important.js<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>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></span> <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>style<span class="token punctuation">"</span></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>critical.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>So by now you should have guessed that <code class="language-text">preload</code> is used in the current route and resources fetched via this technique are very important. The difference between using <code class="language-text">rel=preload</code> and <code class="language-text">rel=stylesheet</code> is that browser will know about that resource way ahead of time allowing the download to start sooner.</p> <p>If you are trying this for your stylesheet and don’t see your styles get applied, it is because there is a catch when using <code class="language-text">preload</code> which is the browser downloads the resource but won’t apply it until we tell it to. To get it working you will need a bit of JavaScript:</p> <div class="gatsby-code-button-container" data-toaster-id="84852829673115190000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<link rel=&quot;preload&quot; as=&quot;style&quot; href=&quot;critical.css&quot; onload=&quot;this.rel='stylesheet'&quot; />`, `84852829673115190000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></span> <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>style<span class="token punctuation">"</span></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>critical.css<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onload</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>rel<span class="token operator">=</span><span class="token string">'stylesheet'</span></span><span class="token punctuation">"</span></span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>What happens now is that the styles get applied as soon as the file is loaded.</p> <h3 id="prefetch" style="position:relative;"><a href="#prefetch" aria-label="prefetch permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prefetch</h3> <p><code class="language-text">&lt;link rel="prefetch"></code> is different from <code class="language-text">&lt;link rel="preload"></code> in that it is not trying to load a critical resource faster, it is trying to load a non-critical resource sooner.</p> <p>Resources loaded by this technique are loaded after current page is loaded, page load event is finished and bandwidth is available. This means it is ideal for lazy loading future routes’ resources or resources that user might need later. Some use cases are fetching a next page if pagination is used:</p> <div class="gatsby-code-button-container" data-toaster-id="23704520466324830000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<link rel=&quot;prefetch&quot; href=&quot;page-2.html&quot; />`, `23704520466324830000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>prefetch<span class="token punctuation">"</span></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>page-2.html<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>By the time user clicks on next page button, the page is already loaded and the app feels real fast.</p> <p>To read more about the usage of these features and also know about other useful features, have a look at <a href="https://developers.google.com/web/fundamentals/performance/resource-prioritization" target="_blank" rel="nofollow noopener noreferrer">Google developer’s resource prioritisation page.</a></p> <p>Same catch applied for <code class="language-text">prefetch</code> as well. But since we are loading a resource which is required potentially for a different route, you might have a separate <code class="language-text">rel=stylesheet</code> on that page which uses this in memory file or in case of a SPA just set the <code class="language-text">rel</code> to <code class="language-text">stylesheet</code> when the route is loaded.</p> <h2 id="when-to-use-these" style="position:relative;"><a href="#when-to-use-these" aria-label="when to use these permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 to use these</h2> <p>So to emphasise why we need to know about these techniques, let me take you back to part one. CSS is a render blocking element, so we need to break it down to the smallest possible chunk which is required to render our main route. Then we can use the above techniques to either load the resource later in the same page without blocking the rendering or to load the resource which is required for our possible next route beforehand and use it when needed.</p> <p>Hope this has helped you to get started with optimising your HTML and CSS loading so far.</p> <p>Next post will be on <code class="language-text">JavaScript</code> and what we can do there to improve our web application’s performance.</p> <p>Alla prossima 😎.</p><![CDATA[Improve HTML and CSS performance]]>https://yashints.dev/blog/2018/09/29/web-perf-1https://yashints.dev/blog/2018/09/29/web-perf-1Sat, 29 Sep 2018 00:00:00 GMT<p>Recently I had a chance to present a talk at <a href="https://ndcsydney.com/talk/need-for-speed-8-performance-tuning-of-your-web-application/" target="_blank" rel="nofollow noopener noreferrer">NDC Sydney</a> about web performance and it received a great feedback.</p> <!--more--> <p>That inspired me to write up a series of posts on each topic I covered in that talk, and who knows, maybe each of these posts would be a talk some day by their own 😃.</p> <p>Link to all other parts:</p> <p><a href="/blog/2018/10/06/web-perf-2">Part 2 use Preload/Prefetch to boost load time</a></p> <p><a href="/blog/2018/10/12/web-perf-3">Part 3 JavaScript tips and tricks</a></p> <p><a href="/blog/2018/11/12/web-perf-4">Part 4 Image optimisation</a></p> <p><a href="/blog/2018/11/23/web-perf-5">Part 5 Web font optimisation</a></p> <p>So here we go, part one is about tips and tricks on HTML and CSS to improve the performance.</p> <p>But before we jump into this, you will need to know how browsers render your page. This involves <a href="https://en.wikipedia.org/wiki/HTML" target="_blank" rel="nofollow noopener noreferrer">HTML</a>, <a href="https://en.wikipedia.org/wiki/Cascading_Style_Sheets" target="_blank" rel="nofollow noopener noreferrer">CSS</a> and <a href="https://en.wikipedia.org/wiki/JavaScript" target="_blank" rel="nofollow noopener noreferrer">JavaScript</a> and steps every browser takes to show your web page to end user.</p> <h2 id="the-critical-rendering-path" style="position:relative;"><a href="#the-critical-rendering-path" aria-label="the critical rendering path permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 Critical Rendering Path</h2> <p>The <a href="https://css-tricks.com/understanding-critical-rendering-path/" target="_blank" rel="nofollow noopener noreferrer">Critical Rendering Path</a> consists of five steps which are best to be seen in visual:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 700px; " > <a class="gatsby-resp-image-link" href="/static/f85f1171d19386f6bdde3c2463b18ef2/29d31/crp.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 27.40740740740741%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABuABP/8QAGBAAAgMAAAAAAAAAAAAAAAAAAAECEjH/2gAIAQEAAQUCZHKn/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxAAAwEAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAQAGPwKaz//EABkQAQADAQEAAAAAAAAAAAAAAAEAESGBMf/aAAgBAQABPyEadgzr4RurX2f/2gAMAwEAAgADAAAAEPAf/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAEDAQE/EGR//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGhABAAIDAQAAAAAAAAAAAAAAAREhADFBsf/aAAgBAQABPxDtTVneuOLLMJQ+415OFDP/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Critical Rendering Path" title="" src="/static/f85f1171d19386f6bdde3c2463b18ef2/29d31/crp.jpg" srcset="/static/f85f1171d19386f6bdde3c2463b18ef2/6f81f/crp.jpg 270w, /static/f85f1171d19386f6bdde3c2463b18ef2/09d21/crp.jpg 540w, /static/f85f1171d19386f6bdde3c2463b18ef2/29d31/crp.jpg 700w" sizes="(max-width: 700px) 100vw, 700px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Alright now that you saw it in a picture, let me explain each step in more details.</p> <h3 id="building-dom-and-cccom" style="position:relative;"><a href="#building-dom-and-cccom" aria-label="building dom and cccom permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Building DOM and CCCOM</h3> <p>As most of the pages consist of HTML, CSS and JavaScript. Web browsers need to know what and how to show to users and they do this by parsing the HTML page sent over network and constructing a Document Object Model (DOM). They look at HTML tags (<code class="language-text">&lt;p>&lt;/p></code>, <code class="language-text">&lt;div>&lt;/div></code>, <code class="language-text">&lt;h1>&lt;/h1></code>) and convert them to tokens. These tokens are then converted to nodes in parallel.</p> <p>By processing the start and end tags for each token in order, the browser then establishes their hierarchy (parent and child).</p> <p>This is way simpler than it looks, in the picture above imagine DOM to be a bit tree with all the nodes (branches) and their children (leaves). This tree contains all the dependencies of nodes to construct our HTML:</p> <p><img src="/2c902bcd526dc480e0cd902e1381fcc1/DOM.gif" alt="Document Object Model"></p> <p><i>Image from <a href="https://www.w3schools.com/js/pic_htmltree.gif" target="_blank" rel="nofollow noopener noreferrer">W3C website</a></i></p> <p>The DOM represents your whole markup and is built incrementally by the browser. As of HTML5 the browsers support streaming HTML instead of waiting for the whole page to get sent to browser in one go. This is great because it helps the rendering to be done at the same time as the bytes are arrived.</p> <p>After constructing the DOM, browser looks at any style which is referenced in the page to build the CSS Object Model (CCCOM). CCCOM describes the style rules that need to be applied to the document. This is very similar to how DOM was built, however, in this process each child inherits the styles applied to its parent - hence the name cascading style sheets.</p> <p>Partial processing of styles is not possible so browsers need to wait for all the style rules to be sent over before they can start inferring what rule is applied to which nodes. This is the reason why CSS is a render blocking element.</p> <p>Mix of DOM and CCCOM is something called the Render Tree. This tree includes all the nodes and their dependencies plus all the CSS rules which are applied to those.</p> <h3 id="render-tree" style="position:relative;"><a href="#render-tree" aria-label="render tree permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Render Tree</h3> <p>After constructing all the nodes, browser needs to know which ones to show on the page. Render Tree is exactly the representation <strong>visible</strong> content on the page.</p> <p>The browser stars from the root and then copies all the <strong>visible</strong> nodes from DOM and CCCOM. The steps taken are roughly as below:</p> <ul> <li>Starting at the root, traverse each visible node <ul> <li>Some nodes are not visible like meta tags, links, etc.</li> <li>Some nodes are hidden using CSS like <code class="language-text">display: none</code></li> </ul> </li> <li>For each node find the matching CSS rule and apply it</li> <li>Emit visible nodes with content and they styles</li> </ul> <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/1ff69ed70a06bcffbf7d84dce1e72381/5a190/render-tree.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 46.666666666666664%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAACi0lEQVR42k1SXUgUURQeLRVs26UMLTQwo8QwEMKHXqK3eg/yQXopMglcesgVsRrRxURETdeFqQ1CEWQMdwlb0QmmXWdnZmfu7MzOz87uOjO246qEZhC9TzPiSh+ce+/HOfe7555zIMhGMTlS8wkZvtqHAI/DJWq6QyWH1/P5eTd0DFn+6Vr8HL4XXl29a1lW5TbtazBJf73js3nZ8V4OadpcrUqPBDP06DhJoucxADwp6oNXjA9Ogh1QvbYmnDmg77slfbc9nSuEUqo+SglcR4Z86xc2xl7HYu+vLC/P1Kh4R6Ml36iEsiTsU4ihXpUeG02DhemcMNe/SQ0sEQzTHN7Yv5ViFp5vkq9oLbPYSqW2r33nirc3Gf9SnuztToKVhwqL8Lz47ZmcDDGiiHWepAt+/L3E5famgJwdFhIBjBcJNCHtTSjS6iODfvFSVMVOXskWKCHPiXI8JIOP64qxTSRlLSEa+yFW1mJJaSsC4Th+GsdRVz4frXKEaVF/TAo6EmOzT1DLOlWqIWzHvZuPunFebUwpGkfxWY5TjR7H52jAMOxYORSNRqtWVhbOBYMTTbOTky2BQMDlBJF8rj7BcXdwwWxl0sVmQRIeUCJVdyRuX+zqgioQBK7G8S8XbA03hqGeSCRytpQA5PV663w+XwOKop60ajSnc+aarO+GRZXrNgziqblTnJC2/rQUGLjplzRwGfoPTtlK5nBnKYOdltsg+K22BMsacZpWMWD26vxsUOOmsK9x/TouWy6DG4mbqaE5+3yRkaR2gpfbEARUHGuXnbxy9H+nOcCqSAh7tahsVSrazriQ350RjIM3QNbDaf3wZoHtG8yRAz10xvTTHPub5KUNoB96SvP4D9Ugj125mX4nAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Render Tree" title="" src="/static/1ff69ed70a06bcffbf7d84dce1e72381/5a190/render-tree.png" srcset="/static/1ff69ed70a06bcffbf7d84dce1e72381/01bf6/render-tree.png 270w, /static/1ff69ed70a06bcffbf7d84dce1e72381/07484/render-tree.png 540w, /static/1ff69ed70a06bcffbf7d84dce1e72381/5a190/render-tree.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" decoding="async" /> </a> </span></p> <p><em>Image from <a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/images/render-tree-construction.png" target="_blank" rel="nofollow noopener noreferrer">Google Developers</a></em></p> <h3 id="layout" style="position:relative;"><a href="#layout" aria-label="layout permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Layout</h3> <p>Now that we have all the nodes with their styles, it’s time to figure out where to put them on screen. This is exactly what layout step is. The first thing which is needed is the browser window size. This is the basis for all the following calculations, since the layout depends on it to know the position and dimension of each element.</p> <p>The output of this step is the <a href="https://www.w3schools.com/css/css_boxmodel.asp" target="_blank" rel="nofollow noopener noreferrer">Box Model</a> which captures the exact position and size of it, plus their margin, padding, border and etc.</p> <p>This step will be repeated by each change to size or when we switch between landscape and portrait on a mobile device.</p> <h3 id="paint" style="position:relative;"><a href="#paint" aria-label="paint permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Paint</h3> <p>This step is the last one where pixels are painted on screen which can take some time because the browser has quite a lot of work to do. This time depends on window size, how much style is applied to each node, the hardware used on device and so on.</p> <p>When this step is finished, the page is finally visible in the viewport.</p> <h2 id="so-what" style="position:relative;"><a href="#so-what" aria-label="so 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>So what</h2> <p>Ok, enough with Critical Rendering Path, let’s see how we can improve the web performance with tweaks on HTML and CSS.</p> <h3 id="stream-html-to-client" style="position:relative;"><a href="#stream-html-to-client" aria-label="stream html to client permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Stream HTML to client</h3> <p>When sending HTML to client try to flush the buffer often instead of once at the end. This means chunks of HTML would arrive and browser can parse them as they arrive not at the end. This will help to boost the performance.</p> <p>As an example, when <code class="language-text">HEAD</code> tag is arrived browser can send other requests for assets while the rest of the HTML is arriving.</p> <h3 id="size-matters" style="position:relative;"><a href="#size-matters" aria-label="size matters permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Size matters</h3> <p>Minifying and compressing is really important since it can reduce the payload size and reduce the HTTP response time which in turn results in better load time.</p> <p>These techniques along with the right caching strategy can massively help the web performance to be improved.</p> <h3 id="send-the-css-early-and-keep-it-minimal" style="position:relative;"><a href="#send-the-css-early-and-keep-it-minimal" aria-label="send the css early and keep it minimal permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Send the CSS early and keep it minimal</h3> <p>As you saw CSS is a render blocking element, so it should be sent down to client as early as possible. Also think of how much CSS is needed on first page load, extract the unused CSS from the main file and load them separately and later when needed.</p> <p>You can also use pre-loading/pre-caching to improve the performance. These are part of <a href="https://developers.google.com/web/fundamentals/performance/prpl-pattern/" target="_blank" rel="nofollow noopener noreferrer">PRPL pattern which was introduced by Google in 2016</a>.</p> <p>Another technique which is not used as often by developers is to use link tags inside body along with content. This is really useful as you can send a minimum amount of CSS to client even inside your HTML in a <code class="language-text">style tag</code> and then load the rest later when needed to improve the render time.</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>In short, keep your recourses minimum and send them fast and optimum. Try to cut down unused CSS rules and use minification and compression to speed up the transfer.</p> <p>Hope you’ve enjoyed reading this and are looking forward for the rest of the series 😉.</p> <h3 id="resources" style="position:relative;"><a href="#resources" aria-label="resources permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Resources</h3> <ul> <li>Web Performance Matters on <a href="https://developers.google.com/web/fundamentals/performance/why-performance-matters/" target="_blank" rel="nofollow noopener noreferrer">Google Developers</a></li> <li>Understanding Critical Rendering Path on <a href="https://css-tricks.com/understanding-critical-rendering-path/" target="_blank" rel="nofollow noopener noreferrer">CSS Tricks</a></li> </ul><![CDATA[Destructuring in JavaScript]]>https://yashints.dev/blog/2018/09/12/destructuring-in-jshttps://yashints.dev/blog/2018/09/12/destructuring-in-jsWed, 12 Sep 2018 00:00:00 GMT<p>With improvements on JavaScript and ECMAScript many awesome features are added which we don’t normally use. However, when you read other people’s code from OSS to doing a simple code review, you might face these features used and not know what they do.</p> <!--more--> <p>One of these cool features is destructuring which was added to ES6 a while back. By that I mean it’s not something new, but it is not used regularly either.</p> <h2 id="what-is-it" style="position:relative;"><a href="#what-is-it" aria-label="what is 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>What is it</h2> <p>The object and array literal expressions provide an easy way to create packages of data:</p> <div class="gatsby-code-button-container" data-toaster-id="17169352251575876000" data-toaster-class="gatsby-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 = [1, 2, 3, 4]; let y = { prop1: 'value1', prop2: 1233, };`, `17169352251575876000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> x <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 number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">let</span> y <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">prop1</span><span class="token operator">:</span> <span class="token string">'value1'</span><span class="token punctuation">,</span> <span class="token literal-property property">prop2</span><span class="token operator">:</span> <span class="token number">1233</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The destructuring assignment uses similar syntax to extract one or multiple of these literals into letiables on the left hand side:</p> <div class="gatsby-code-button-container" data-toaster-id="25546739222592250000" data-toaster-class="gatsby-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 = [1, 2, 3, 4]; // Previously let b = x[0]; let c = x[1]; // Destructuring let [d, e] = x; console.log(d); // 1 console.log(e); // 2 let y = { prop1: 'value 1', prop2: 1233, }; // Previously let f = y.prop1; let g = y.prop2; // Destructuring let { f, g } = y; console.log(f); // value 1 console.log(g); // 1234`, `25546739222592250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">let</span> x <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 number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Previously</span> <span class="token keyword">let</span> b <span class="token operator">=</span> x<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">let</span> c <span class="token operator">=</span> x<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Destructuring</span> <span class="token keyword">let</span> <span class="token punctuation">[</span>d<span class="token punctuation">,</span> e<span class="token punctuation">]</span> <span class="token operator">=</span> x<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>d<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>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2</span> <span class="token keyword">let</span> y <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">prop1</span><span class="token operator">:</span> <span class="token string">'value 1'</span><span class="token punctuation">,</span> <span class="token literal-property property">prop2</span><span class="token operator">:</span> <span class="token number">1233</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Previously</span> <span class="token keyword">let</span> f <span class="token operator">=</span> y<span class="token punctuation">.</span>prop1<span class="token punctuation">;</span> <span class="token keyword">let</span> g <span class="token operator">=</span> y<span class="token punctuation">.</span>prop2<span class="token punctuation">;</span> <span class="token comment">// Destructuring</span> <span class="token keyword">let</span> <span class="token punctuation">{</span> f<span class="token punctuation">,</span> g <span class="token punctuation">}</span> <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>f<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// value 1</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>g<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1234</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This is very similar to existing features of <code class="language-text">Python</code> or <code class="language-text">Perl</code> and is very handy at times which I mention later.</p> <h2 id="arrays" style="position:relative;"><a href="#arrays" aria-label="arrays permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Arrays</h2> <p>When destructuring arrays you have some flexibility to what you want to extract but not too much. For example you can extract item <code class="language-text">1</code> to <code class="language-text">n</code> of an array by using <code class="language-text">n</code> number of variables in the left hand side (you can use <code class="language-text">var</code>, <code class="language-text">let</code> and <code class="language-text">const</code>).</p> <p>However, extracting certain elements might be a bit easier. Here is what I mean:</p> <div class="gatsby-code-button-container" data-toaster-id="12604895738854083000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// ... in below line means you have to repeat the variable names there let [var1, var2, var3, ..., varN] = array; // However, extracting certain elements is easier const list = [1, 2, 3, 4, 5]; const [a, , , b] = list; console.log(a); // 1 console.log(b); // 4`, `12604895738854083000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// ... in below line means you have to repeat the variable names there</span> <span class="token keyword">let</span> <span class="token punctuation">[</span>var1<span class="token punctuation">,</span> var2<span class="token punctuation">,</span> var3<span class="token punctuation">,</span> <span class="token operator">...</span><span class="token punctuation">,</span> varN<span class="token punctuation">]</span> <span class="token operator">=</span> array<span class="token punctuation">;</span> <span class="token comment">// However, extracting certain elements is easier</span> <span class="token keyword">const</span> list <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 number">4</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 keyword">const</span> <span class="token punctuation">[</span>a<span class="token punctuation">,</span> <span class="token punctuation">,</span> <span class="token punctuation">,</span> b<span class="token punctuation">]</span> <span class="token operator">=</span> list<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 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>b<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 4</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see you can skip the unwanted literals easily.</p> <p>You can also nest pattern as many as you like:</p> <div class="gatsby-code-button-container" data-toaster-id="40124392862558690000" data-toaster-class="gatsby-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 [a, [[b], c]] = [1, [[2], 3]]; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3`, `40124392862558690000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> <span class="token punctuation">[</span>a<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">[</span>b<span class="token punctuation">]</span><span class="token punctuation">,</span> c<span class="token punctuation">]</span><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 punctuation">[</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</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> 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 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>b<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="rest-pattern" style="position:relative;"><a href="#rest-pattern" aria-label="rest pattern permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>rest pattern</h3> <p>You can capture the trailing elements of an array using <code class="language-text">rest</code> operator:</p> <div class="gatsby-code-button-container" data-toaster-id="40082170089443795000" data-toaster-class="gatsby-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 [a, ...b] = [1, 2, 3, 4]; console.log(b); // [2, 3, 4]`, `40082170089443795000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> <span class="token punctuation">[</span>a<span class="token punctuation">,</span> <span class="token operator">...</span>b<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 number">4</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>b<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [2, 3, 4]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>Bare in mind that if you try to get items outside of array boundary, you will get our friend <code class="language-text">undefined</code> 😏.</p> <h2 id="objects" style="position:relative;"><a href="#objects" aria-label="objects permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Objects</h2> <p>When destructuring objects you can leave the name of the variable to come from property name or you can specify you own name:</p> <div class="gatsby-code-button-container" data-toaster-id="27733853777320960000" data-toaster-class="gatsby-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 obj = { foo: 'lorem', bar: 'ipsum' }; const { foo, bar } = obj; console.log(foo); // lorem const { myFoo: foo, myBar: bar } = obj; console.log(myFoo); // lorem`, `27733853777320960000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token string">'lorem'</span><span class="token punctuation">,</span> <span class="token literal-property property">bar</span><span class="token operator">:</span> <span class="token string">'ipsum'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> foo<span class="token punctuation">,</span> bar <span class="token punctuation">}</span> <span class="token operator">=</span> obj<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>foo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// lorem</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> <span class="token literal-property property">myFoo</span><span class="token operator">:</span> foo<span class="token punctuation">,</span> <span class="token literal-property property">myBar</span><span class="token operator">:</span> bar <span class="token punctuation">}</span> <span class="token operator">=</span> obj<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>myFoo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// lorem</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Like arrays you can nest and combine as many levels as you like:</p> <div class="gatsby-code-button-container" data-toaster-id="76046012472667110000" data-toaster-class="gatsby-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 complexObj = { first: { prop1: 'lorem ipsum', }, arrayProp: ['lorem', { second: 'ipsum' }], }; let { first: { prop1 }, arrayProp: [, { second }], } = complexObj; console.log(prop1); // &quot;lorem ipsum&quot; console.log(first); // &quot;lorem&quot; console.log(second); // &quot;ipsum&quot;`, `76046012472667110000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> complexObj <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">first</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">prop1</span><span class="token operator">:</span> <span class="token string">'lorem ipsum'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">arrayProp</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'lorem'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">second</span><span class="token operator">:</span> <span class="token string">'ipsum'</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">let</span> <span class="token punctuation">{</span> <span class="token literal-property property">first</span><span class="token operator">:</span> <span class="token punctuation">{</span> prop1 <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">arrayProp</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> second <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token operator">=</span> complexObj<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>prop1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "lorem ipsum"</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>first<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "lorem"</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>second<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "ipsum"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>There is a catch when destructuring objects which is you have to use either var, let or const otherwise you will get error.</p> <div class="gatsby-code-button-container" data-toaster-id="83976666008058450000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ prop1 } = {prop1 : &quot;lorem&quot;}; // Syntax error`, `83976666008058450000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">{</span> prop1 <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">prop1</span> <span class="token operator">:</span> <span class="token string">"lorem"</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Syntax error</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This happens because JavaScript engine thinks this is block statement with <code class="language-text">{</code>. The solution is to wrap it in parentheses:</p> <div class="gatsby-code-button-container" data-toaster-id="21320881078214330000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`({ prop1 } = { prop1: 'lorem' }); // No errors`, `21320881078214330000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token punctuation">(</span><span class="token punctuation">{</span> prop1 <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">prop1</span><span class="token operator">:</span> <span class="token string">'lorem'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// No errors</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Last point in destructuring is that you cannot destructure <code class="language-text">null</code> or <code class="language-text">undefined</code> or you get a type error:</p> <div class="gatsby-code-button-container" data-toaster-id="2010439582925771500" data-toaster-class="gatsby-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 { oops } = null; // TypeError: null has no properties`, `2010439582925771500`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">var</span> <span class="token punctuation">{</span> oops <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment">// TypeError: null has no properties</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>The reason is simple, when using an object assignment, the value which is destructured should be convertible to object. <code class="language-text">null</code> and <code class="language-text">undefined</code> are simply not. When destructuring arrays, the value should have an iterator.</p> <h2 id="where-we-should-use-this-pattern" style="position:relative;"><a href="#where-we-should-use-this-pattern" aria-label="where we should use this pattern permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 we should use this pattern</h2> <h4 id="simplifying-apis" style="position:relative;"><a href="#simplifying-apis" aria-label="simplifying apis permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Simplifying APIs</h4> <p>When you are exposing a function, it is always good to expose it in a way which gets a single parameter instead of multi, since the consumers then have to remember the order of params and whether or not they are optional.</p> <p>This way you can use one parameter and then destructure it and you can have the benefit of using you code as if you had multiple parameter. This is simpler with an example:</p> <div class="gatsby-code-button-container" data-toaster-id="18096722563963685000" data-toaster-class="gatsby-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 function worstMethodEver(param1, param2, param3, ...) { if (param1) { switch(param2) { case param3: return; } } } // The user calls this like worstMethodEver(1, 2, 3, ...); // After function awesomeMethod({param1, param2, param3, ...}) { if (param1) { switch(param2) { case param3: return; } } } // The user calls this like awesomeMethod(obj); `, `18096722563963685000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token comment">// Before</span> <span class="token keyword">function</span> <span class="token function">worstMethodEver</span><span class="token punctuation">(</span><span class="token parameter">param1<span class="token punctuation">,</span> param2<span class="token punctuation">,</span> param3<span class="token punctuation">,</span> <span class="token operator">...</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>param1<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span><span class="token punctuation">(</span>param2<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token literal-property property">param3</span><span class="token operator">:</span> <span class="token keyword">return</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">// The user calls this like worstMethodEver(1, 2, 3, ...);</span> <span class="token comment">// After</span> <span class="token keyword">function</span> <span class="token function">awesomeMethod</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>param1<span class="token punctuation">,</span> param2<span class="token punctuation">,</span> param3<span class="token punctuation">,</span> <span class="token operator">...</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>param1<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span><span class="token punctuation">(</span>param2<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token literal-property property">param3</span><span class="token operator">:</span> <span class="token keyword">return</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">// The user calls this like awesomeMethod(obj);</span> </code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>On top of the previous example we can also provide default value when destructuring:</p> <div class="gatsby-code-button-container" data-toaster-id="41520181355905630000" data-toaster-class="gatsby-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 awesomeMethod({param1 = &quot;Default lorem&quot;, param2, param3, ...}) { if (param1) { switch(param2) { case param3: return; } } }`, `41520181355905630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">awesomeMethod</span><span class="token punctuation">(</span><span class="token punctuation">{</span>param1 <span class="token operator">=</span> <span class="token string">"Default lorem"</span><span class="token punctuation">,</span> param2<span class="token punctuation">,</span> param3<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 keyword">if</span> <span class="token punctuation">(</span>param1<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span><span class="token punctuation">(</span>param2<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token literal-property property">param3</span><span class="token operator">:</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h4 id="returning-multiple-values" style="position:relative;"><a href="#returning-multiple-values" aria-label="returning multiple values permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Returning multiple values</h4> <p>Although multiple return values aren’t baked into the JS eco system properly, you can return an array and destructure the result:</p> <div class="gatsby-code-button-container" data-toaster-id="10960892964432456000" data-toaster-class="gatsby-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 returnMultipleValues() { return [1, 2]; } const [foo, bar] = returnMultipleValues();`, `10960892964432456000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">returnMultipleValues</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</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 punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>foo<span class="token punctuation">,</span> bar<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">returnMultipleValues</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Or with an object:</p> <div class="gatsby-code-button-container" data-toaster-id="18005029499547920000" data-toaster-class="gatsby-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 returnObject() { return { foo: 1, bar: 2, }; } const { foo, bar } = returnObject();`, `18005029499547920000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">function</span> <span class="token function">returnObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">bar</span><span class="token operator">:</span> <span class="token number">2</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> <span class="token punctuation">{</span> foo<span class="token punctuation">,</span> bar <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">returnObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h4 id="importing-names-from-commonjs-modules" style="position:relative;"><a href="#importing-names-from-commonjs-modules" aria-label="importing names from commonjs 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>importing names from CommonJs modules</h4> <p>This one you’ve probably used a lot:</p> <div class="gatsby-code-button-container" data-toaster-id="93707583750933100000" data-toaster-class="gatsby-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, b } = require('module');`, `93707583750933100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-js line-numbers"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> a<span class="token punctuation">,</span> b <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">'module'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And with this we’re done, hope you now think of ways to use this feature and make your life and others easier 😜.</p><![CDATA[I am a proud lazy developer]]>https://yashints.dev/blog/2018/08/20/windows-shortcutshttps://yashints.dev/blog/2018/08/20/windows-shortcutsMon, 20 Aug 2018 00:00:00 GMT<p>I saw a quote today on Twitter:</p> <blockquote> <p>As a developer I don’t feel bad about being lazy. If I can make a computer to repeat something for me, why should I do it myself?</p> </blockquote> <!--more--> <p>When I saw this, I thought about things that are on my day to day work, and are done in that way just because being lazy is not a bad thing in my opinion too.</p> <p>That’s why I want to share with you some of the short keys on Windows 10, which helps me do stuff way faster that normal. So here we go 😎:</p> <h3 id="1-ctrlbackspace" style="position:relative;"><a href="#1-ctrlbackspace" aria-label="1 ctrlbackspace permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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: Ctrl+Backspace</h3> <p>This trivial combination will help you delete a word at a time instead of a character compared to when you just hit backspace. I love this as it boost my speed in fixing my writings faster 😁.</p> <h3 id="2-winnumber" style="position:relative;"><a href="#2-winnumber" aria-label="2 winnumber permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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: Win+Number</h3> <p>If you keep icons on your taskbar like me and order them by their importance, this is for you. By pressing win key and a number, it’s like clicking that icon on the taskbar and opening the program behind it.</p> <p>For example, I have Chrome as first icon, so I just press <code class="language-text">win+1</code>.</p> <h3 id="3-ctrlshiftv" style="position:relative;"><a href="#3-ctrlshiftv" aria-label="3 ctrlshiftv permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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: Ctrl+Shift+V</h3> <p>Often times, when you have some text with formatting somewhere and you need to send it in an email or use it a different application, you copy the text and paste it.</p> <p>However, most of the times the text comes with its formatting. If you don’t want the formatting and care about the text only instead of <code class="language-text">Ctrl+V</code> use <code class="language-text">Ctrl+Shift+V</code> and voila, you have the pure text without any formatting. This one works mostly in browsers, but there are some apps that support it too.</p> <h3 id="4-ctrlshiftt" style="position:relative;"><a href="#4-ctrlshiftt" aria-label="4 ctrlshiftt permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4: Ctrl+Shift+T</h3> <p>I’ve been bitten many times when cleaning my open tabs on a browser by closing the most important tab which I needed it the most.</p> <p>Trying different approaches like typing in address bar in hope of finding it in the history or other ways has been unsuccessful many times, until I came across this combination.</p> <p>This one opens up your last closed tab in most major browsers (<a href="https://www.google.com/chrome/" target="_blank" rel="nofollow noopener noreferrer">Chrome</a>, <a href="https://www.mozilla.org/en-US/firefox/new/" target="_blank" rel="nofollow noopener noreferrer">Firefox</a>, <a href="https://www.microsoft.com/en-au/windows/microsoft-edge" target="_blank" rel="nofollow noopener noreferrer">Edge</a>).</p> <h3 id="5-winp" style="position:relative;"><a href="#5-winp" aria-label="5 winp permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>5: Win+P</h3> <p>When you want to project to another screen instead of trying to find the related key specific to your laptop brand just use this combination. Fast and furiously project without hustle 🙃.</p> <h3 id="6-winx" style="position:relative;"><a href="#6-winx" aria-label="6 winx permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>6: Win+X</h3> <p>This shortcut will bring up the quick link menu which for me are the most important list of windows tools. From power options to disk and computer management, event viewer, task manager and many more. Try it out, this one is awesome.</p> <h3 id="7-win" style="position:relative;"><a href="#7-win" aria-label="7 win permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>7: Win+,</h3> <p>If you want to quickly have a look at your desktop without minimising the applications then use this combo, if you really want to minimise everything, use <code class="language-text">win+m</code>.</p> <h3 id="8-win-" style="position:relative;"><a href="#8-win-" aria-label="8 win permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>8: Win+(+/-)</h3> <p>If you’re presenting and want to zoom in on a specific area of the screen using magnifier, use <code class="language-text">win + "+"</code>, for zooming out use <code class="language-text">win + "-"</code>.</p> <h3 id="9-win" style="position:relative;"><a href="#9-win" aria-label="9 win permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>9: Win+.</h3> <p>This is by far the most important shortcut you need to know 😁🔥🔥🔥. I just used it to add these emojis. And yes you guessed it right, this will bring up the emoji list and you can continue typing to find the one you need.</p> <h3 id="10-ctrlc" style="position:relative;"><a href="#10-ctrlc" aria-label="10 ctrlc permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>10: Ctrl+C</h3> <p>You may now see this and think WTH, everyone knows this one. However, I am not talking about copying anything into clipboard here. How many times you faced an error and you couldn’t copy the error text because it wasn’t selectable?</p> <p>Well use our favourite <code class="language-text">Win+C</code> when you see an error message and the whole message will get copied to clipboard which you can then send to related party to investigate or just simply google it to see how it can be fixed.</p> <p>Hope these shortcuts help you work more efficiently like me 😉, and till next post, adiós.</p><![CDATA[Use an Angular component inside a React application]]>https://yashints.dev/blog/2018/07/28/angular-reacthttps://yashints.dev/blog/2018/07/28/angular-reactSat, 28 Jul 2018 00:00:00 GMT<p>With release of <a href="https://blog.angular.io/version-6-of-angular-now-available-cc56b0efa7a4" target="_blank" rel="nofollow noopener noreferrer">Angular 6</a>, the team released <code class="language-text">Angular Elements</code> which allows you to bootstrap Angular components within an existing Angular application by registering them as <em>Custom Components</em>.</p> <!--more--> <p>This opens a whole lot of opportunities to web developers who are used to argue about superiority of Angular vs React. Some people believe Angular is suitable for developing enterprise applications, while others prefer React because of it’s speed and bundle size. Meanwhile, Angular team has been working hard to bring this feature into V6 release and let Angular lovers create Custom Components which can be used in other framework.</p> <p>The result component will be like a web component for the React application like any other HTML components like <code class="language-text">button</code> or <code class="language-text">input</code>. Plus, finally I found some time to play with the concepts and get a quick demo ready and it was pretty easy as expected. So let’s get started.</p> <p>For the purpose of this post, I will create a book list component in Angular which accepts a list of books and shows them in the page. This component is ported into a React application which will send the list of books as props to it. Once a book is added to card the changes will be propagated to React app.</p> <h2 id="create-your-angular-component" style="position:relative;"><a href="#create-your-angular-component" aria-label="create your angular 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>Create your Angular component</h2> <p>First let’s create a new Angular application using Angular CLI:</p> <div class="gatsby-code-button-container" data-toaster-id="27860054597142380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng new book-list`, `27860054597142380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng new book-list</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can go ahead and delete the default app component and create a new component called book list:</p> <div class="gatsby-code-button-container" data-toaster-id="6216536788873061000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng g c book-list`, `6216536788873061000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng g c book-list</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Since we want to evaluate the communication between our Angular and React applications, we will pass the book list as input. Just to test the other way around, we define an output as an <code class="language-text">EventEmitter</code> that gets triggered whenever a book is selected from the list. So the component code will look like this:</p> <div class="gatsby-code-button-container" data-toaster-id="50926337153849156000" data-toaster-class="gatsby-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 { Component, Input, Output, EventEmitter } from '@angular/core' @Component({ selector: 'book-list', templateUrl: './book-list.component.html', styleUrls: ['./book-list.component.css'], }) export class BookListComponent { public booksList: any[] @Input('books') set books(books: string) { this.booksList = JSON.parse(books) } @Output('bookSelected') bookSelected = new EventEmitter<any>() constructor() {} selected(book: any) { this.bookSelected.emit(JSON.stringify(book)) } }`, `50926337153849156000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> Input<span class="token punctuation">,</span> Output<span class="token punctuation">,</span> EventEmitter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Component</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> selector<span class="token operator">:</span> <span class="token string">'book-list'</span><span class="token punctuation">,</span> templateUrl<span class="token operator">:</span> <span class="token string">'./book-list.component.html'</span><span class="token punctuation">,</span> styleUrls<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'./book-list.component.css'</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">export</span> <span class="token keyword">class</span> <span class="token class-name">BookListComponent</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> booksList<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Input</span></span><span class="token punctuation">(</span><span class="token string">'books'</span><span class="token punctuation">)</span> <span class="token keyword">set</span> <span class="token function">books</span><span class="token punctuation">(</span>books<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>booksList <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>books<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Output</span></span><span class="token punctuation">(</span><span class="token string">'bookSelected'</span><span class="token punctuation">)</span> bookSelected <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EventEmitter<span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token function">constructor</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">selected</span><span class="token punctuation">(</span>book<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>bookSelected<span class="token punctuation">.</span><span class="token function">emit</span><span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>book<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> Currently passing a complex object like array into a web component is a bit of grey area. So we just pass a JSON string for the purpose of this post. If someone knows a way to to this please comment below and I will update the post (thank you in advance 🙏).</div></div> <p>And the HTML is pretty simple:</p> <div class="gatsby-code-button-container" data-toaster-id="3671866880023100400" data-toaster-class="gatsby-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>List of recent books</h1> <div *ngFor=&quot;let book of booksList&quot;> <strong>{{book.name}}</strong> <p>{{book.description}}</p> <label class=&quot;container&quot; >Add to card <input type=&quot;checkbox&quot; (change)=&quot;selected(book)&quot; /> <span class=&quot;checkmark&quot;></span> </label> </div>`, `3671866880023100400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>List of recent books<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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">*ngFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>let book of booksList<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>strong</span><span class="token punctuation">></span></span>{{book.name}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>strong</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>{{book.description}}<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>label</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>container<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span>Add to card <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>checkbox<span class="token punctuation">"</span></span> <span class="token attr-name">(change)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>selected(book)<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>checkmark<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 punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="bootstrapping-the-component-as-an-element" style="position:relative;"><a href="#bootstrapping-the-component-as-an-element" aria-label="bootstrapping the component as an 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>Bootstrapping the component as an element</h3> <p>Now that we have created our component, it’s time to bootstrap our component as an Angular element:</p> <div class="gatsby-code-button-container" data-toaster-id="11474819031916294000" data-toaster-class="gatsby-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 { BrowserModule } from '@angular/platform-browser' import { NgModule, Injector } from '@angular/core' import { createCustomElement } from '@angular/elements' import { BookListComponent } from './book-list/book-list.component' @NgModule({ declarations: [BookListComponent], imports: [BrowserModule], providers: [], bootstrap: [], entryComponents: [BookListComponent], }) export class AppModule { constructor(private injector: Injector) { const customElement = createCustomElement(BookListComponent, { injector }) customElements.define('book-list', customElement) } ngDoBootstrap() {} }`, `11474819031916294000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> BrowserModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/platform-browser'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> NgModule<span class="token punctuation">,</span> Injector <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> createCustomElement <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/elements'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> BookListComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./book-list/book-list.component'</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> declarations<span class="token operator">:</span> <span class="token punctuation">[</span>BookListComponent<span class="token punctuation">]</span><span class="token punctuation">,</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span>BrowserModule<span class="token punctuation">]</span><span class="token punctuation">,</span> providers<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> bootstrap<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> entryComponents<span class="token operator">:</span> <span class="token punctuation">[</span>BookListComponent<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">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> injector<span class="token operator">:</span> Injector<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> customElement <span class="token operator">=</span> <span class="token function">createCustomElement</span><span class="token punctuation">(</span>BookListComponent<span class="token punctuation">,</span> <span class="token punctuation">{</span> injector <span class="token punctuation">}</span><span class="token punctuation">)</span> customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">'book-list'</span><span class="token punctuation">,</span> customElement<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">ngDoBootstrap</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>To create a custom element from the book list component, we should invoke the new <code class="language-text">createCustomElement</code> method which doesn’t insert the newly created component inside <em>CustomElementRegistry</em>, hence using AppModule constructor to do it manually. Maybe in future that will happen automatically but until then it is our job to do it.</p> <p>At this point the element is ready. It’s time to build our element:</p> <div class="gatsby-code-button-container" data-toaster-id="84411153759354620000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng build --prod --output-hashing none`, `84411153759354620000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng build <span class="token parameter variable">--prod</span> --output-hashing none</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>If you have a look at your <code class="language-text">dist/book-list</code> folder now, you should see three JS files generated for you, <code class="language-text">main.js</code>, <code class="language-text">polyfills.js</code>, <code class="language-text">runtime.js</code>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 522px; " > <a class="gatsby-resp-image-link" href="/static/f1d5941b7b12ca2b1d89f6ce09ef5544/04df2/booklist-element-dist.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 107.40740740740742%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAVABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAeZEIg0DIP/EABgQAAMBAQAAAAAAAAAAAAAAAAABEBEx/9oACAEBAAEFAlzIhxDn/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAFhAAAwAAAAAAAAAAAAAAAAAAARAg/9oACAEBAAY/Ama//8QAGhAAAgIDAAAAAAAAAAAAAAAAAREAECFhgf/aAAgBAQABPyFimcQ8cigsaCxJ7t//2gAMAwEAAgADAAAAEBPAAP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8QH//EABURAQEAAAAAAAAAAAAAAAAAABEg/9oACAECAQE/EGP/xAAgEAEAAQQBBQEAAAAAAAAAAAABEQAhMVEQQXGBsdHB/9oACAEBAAE/EE9iL8rljdq6/sphhnxRJW4Jc2b/ACphYI7HDkkwQcbpWj584//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Folder structure" title="" src="/static/f1d5941b7b12ca2b1d89f6ce09ef5544/04df2/booklist-element-dist.jpg" srcset="/static/f1d5941b7b12ca2b1d89f6ce09ef5544/6f81f/booklist-element-dist.jpg 270w, /static/f1d5941b7b12ca2b1d89f6ce09ef5544/04df2/booklist-element-dist.jpg 522w" sizes="(max-width: 522px) 100vw, 522px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="hosting-our-book-list-inside-a-react-app" style="position:relative;"><a href="#hosting-our-book-list-inside-a-react-app" aria-label="hosting our book list inside a react 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>Hosting our book list inside a React app</h2> <p>It’s time to create our React app. We can start by creating one using React CLI:</p> <div class="gatsby-code-button-container" data-toaster-id="15013335789413396000" data-toaster-class="gatsby-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 create-react-app react-host`, `15013335789413396000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">npx create-react-app react-host</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>When the command finished you should have the initial React app template setup. If you run <code class="language-text">npm start</code> from inside the <em>react-host</em> folder, you should see the default app:</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/1aa3e4bb8b646f1c8379e1258247303a/ac614/reactdefault.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 48.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUBBP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAeraokqw/8QAFxAAAwEAAAAAAAAAAAAAAAAAAAMUIP/aAAgBAQABBQKBZAsgXj//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAAjIg/9oACAEBAAY/AqYpimx//8QAGRAAAgMBAAAAAAAAAAAAAAAAAAERIPHR/9oACAEBAAE/Id1EvRG6qf/aAAwDAQACAAMAAAAQgw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAABBAMAAAAAAAAAAAAAAAABABHB8CCB0f/aAAgBAQABPxCoQiQ508FUIw//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="react default app" title="" src="/static/1aa3e4bb8b646f1c8379e1258247303a/47311/reactdefault.jpg" srcset="/static/1aa3e4bb8b646f1c8379e1258247303a/6f81f/reactdefault.jpg 270w, /static/1aa3e4bb8b646f1c8379e1258247303a/09d21/reactdefault.jpg 540w, /static/1aa3e4bb8b646f1c8379e1258247303a/47311/reactdefault.jpg 1080w, /static/1aa3e4bb8b646f1c8379e1258247303a/ac614/reactdefault.jpg 1272w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>We can copy the three files created by Angular CLI into the public folder of our React app and reference them inside <code class="language-text">index.html</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="16812882826082464000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<body> <noscript> You need to enable JavaScript to run this app. </noscript> <div id=&quot;root&quot;></div> <script type=&quot;text/javascript&quot; src=&quot;./book-list/runtime.js&quot;></script> <script type=&quot;text/javascript&quot; src=&quot;./book-list/polyfills.js&quot;></script> <script type=&quot;text/javascript&quot; src=&quot;./book-list/main.js&quot;></script> </body>`, `16812882826082464000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>noscript</span><span class="token punctuation">></span></span> You need to enable JavaScript to run this app. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>noscript</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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>root<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>script</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>text/javascript<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>./book-list/runtime.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>text/javascript<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>./book-list/polyfills.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</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>text/javascript<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>./book-list/main.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="using-the-book-list-component" style="position:relative;"><a href="#using-the-book-list-component" aria-label="using the book list 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>Using the book list component</h3> <p>Now that we have everything in place, let’s start by modifying our app component and add a list of books as it’s state so we can pass it down to our book list:</p> <div class="gatsby-code-button-container" data-toaster-id="71087082876870250000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`constructor(props){ super(props) this.state = { books: [ { name: '10% Happier', description: \`Practicing meditation and mindfulness will make you at least 10 percent happier.\` }, { name: 'The 10X Rule', description: \`The biggest mistake most people make in life is not setting goals high enough.\` }, { name: 'A Short Guide to a Happy Life', description: \`The only thing you have that nobody else has is control of your life.\` } ] }; }`, `71087082876870250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">books</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'10% Happier'</span><span class="token punctuation">,</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Practicing meditation and mindfulness will make you at least 10 percent happier.</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 literal-property property">name</span><span class="token operator">:</span> <span class="token string">'The 10X Rule'</span><span class="token punctuation">,</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The biggest mistake most people make in life is not setting goals high enough.</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 literal-property property">name</span><span class="token operator">:</span> <span class="token string">'A Short Guide to a Happy Life'</span><span class="token punctuation">,</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The only thing you have that nobody else has is control of your life.</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now we can use our book list component and pass the books down as property:</p> <div class="gatsby-code-button-container" data-toaster-id="19294627736507273000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`render() { return ( <div className=&quot;App&quot;> <header className=&quot;App-header&quot;> <img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /> <h1 className=&quot;App-title&quot;>Welcome to React</h1> </header> <div className=&quot;book-list&quot;> <book-list ref={elem => this.nv = elem} books={JSON.stringify(this.state.books)}></book-list> </div> <div className=&quot;selected-books&quot;> <h1>Shopping card</h1> {this.renderSelectedBooks()} </div> </div> ); }`, `19294627736507273000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator">&lt;</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span> <span class="token operator">&lt;</span>img src<span class="token operator">=</span><span class="token punctuation">{</span>logo<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"App-logo"</span> alt<span class="token operator">=</span><span class="token string">"logo"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator">&lt;</span>h1 className<span class="token operator">=</span><span class="token string">"App-title"</span><span class="token operator">></span>Welcome to React<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>header<span class="token operator">></span> <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"book-list"</span><span class="token operator">></span> <span class="token operator">&lt;</span>book<span class="token operator">-</span>list ref<span class="token operator">=</span><span class="token punctuation">{</span><span class="token parameter">elem</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span>nv <span class="token operator">=</span> elem<span class="token punctuation">}</span> books<span class="token operator">=</span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>books<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>book<span class="token operator">-</span>list<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token string">"selected-books"</span><span class="token operator">></span> <span class="token operator">&lt;</span>h1<span class="token operator">></span>Shopping card<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">renderSelectedBooks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> As I mentioned above, we need to pass a string to our custom component or it won’t receive the correct data.</div></div> <p>We used a method to render the selected books, so let’s define it:</p> <div class="gatsby-code-button-container" data-toaster-id="39367769674391904000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`renderSelectedBooks() { return( <div> { this.state.selectedBooks.map(function(book, index){ return <div><strong key={ index }>{book.name}</strong></div>; }) } </div> ) }`, `39367769674391904000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">renderSelectedBooks</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span><span class="token punctuation">(</span> <span class="token operator">&lt;</span>div<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>selectedBooks<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">book<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>div<span class="token operator">></span><span class="token operator">&lt;</span>strong key<span class="token operator">=</span><span class="token punctuation">{</span> index <span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>book<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>div<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 operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I am using internal state here, but note that this is not a React post and I am not following any practice here.</p> <p>Also we used a variable called <code class="language-text">nv</code> to have a reference to the component. We will add an event listener to it which listens to <code class="language-text">bookSelected</code> event and called a method to handle the event.</p> <div class="gatsby-code-button-container" data-toaster-id="14655893303309631000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`componentDidMount() { this.nv.addEventListener(&quot;bookSelected&quot;, this.handleBookSelected); }`, `14655893303309631000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">componentDidMount</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>nv<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"bookSelected"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleBookSelected<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <div class="custom-block warning"><div class="custom-block-body"><strong>Warning:</strong> The name of the event should match the name of event that you used when defining the Angular element.</div></div> <p>Let’s initialise our state in our event handler:</p> <div class="gatsby-code-button-container" data-toaster-id="84940869744983670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`handleBookSelected = event => { const book = JSON.parse(event.detail) let selectedBookList = [] if (this.state.selectedBooks.find(x => x.name === book.name)) { selectedBookList = this.state.selectedBooks.filter( x => x.name !== book.name ) } else { selectedBookList = [...this.state.selectedBooks, book] } this.setState({ ...this.state, selectedBooks: [...selectedBookList], }) }`, `84940869744983670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function-variable function">handleBookSelected</span> <span class="token operator">=</span> <span class="token parameter">event</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> book <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>event<span class="token punctuation">.</span>detail<span class="token punctuation">)</span> <span class="token keyword">let</span> selectedBookList <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><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>selectedBooks<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> x<span class="token punctuation">.</span>name <span class="token operator">===</span> book<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> selectedBookList <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>selectedBooks<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token operator">=></span> x<span class="token punctuation">.</span>name <span class="token operator">!==</span> book<span class="token punctuation">.</span>name <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> selectedBookList <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>selectedBooks<span class="token punctuation">,</span> book<span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">,</span> <span class="token literal-property property">selectedBooks</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span>selectedBookList<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The above code looks a bit busy, but it is very simple. We first check if the book is already selected and remove it if it is. If the book is not in selected list we add it and update the state. Once the state is updated React will reload the page and shows the updated selected books.</p> <p>If you run the app now you should see a screen like this:</p> <video width="600px" controls> <source src="/106d1f77f71c863bd6a066aceaf9b7d6/ReactApp.mp4" type="video/mp4"> </video> <p>And that’s it you’re officially running an Angular element inside a React app and they get along really well 😁🔥💯.</p> <p>You can find the source code <a href="https://github.com/yashints/AngularInsideReact" target="_blank" rel="nofollow noopener noreferrer">on my GitHub repository</a>.</p> <p>Hope you’ve enjoyed the reading.</p><![CDATA[Boost up your performance using Angular preloading strategy]]>https://yashints.dev/blog/2018/06/06/angular-preloadinghttps://yashints.dev/blog/2018/06/06/angular-preloadingWed, 06 Jun 2018 00:00:00 GMT<p><a href="https://angular.io/api/router/Router" target="_blank" rel="nofollow noopener noreferrer">Angular Router</a> has been supporting lazy loading of child modules for a long time. What’s even more cool is that later on they added <code class="language-text">PreloadAllModules</code> strategy so you can preload all of the modules in the background asynchronously. This will help boost up the loading time and performance tremendously.</p> <!--more--> <p>To use this feature your <code class="language-text">RouterModule</code> will look like this:</p> <div class="gatsby-code-button-container" data-toaster-id="98003688739195200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`routes: Routes = [ ... ] @NgModule({ imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })], exports: [RouterModule] }) export class AppRoutingModule { }`, `98003688739195200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript">routes<span class="token operator">:</span> Routes <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token operator">...</span> <span class="token punctuation">]</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span>RouterModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span>routes<span class="token punctuation">,</span> <span class="token punctuation">{</span> preloadingStrategy<span class="token operator">:</span> PreloadAllModules <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> exports<span class="token operator">:</span> <span class="token punctuation">[</span>RouterModule<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">class</span> <span class="token class-name">AppRoutingModule</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="implementing-your-own-preloading-strategy" style="position:relative;"><a href="#implementing-your-own-preloading-strategy" aria-label="implementing your own preloading strategy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Implementing your own preloading strategy</h2> <p>The above feature is great, however, in real world and most of the times the application is too big and loading all the modules in the background is just adding extra traffic while in reality users might not navigate to all of your child routes. <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular</a> does not have any other predefined strategy, but it allows you to customise the preloading by implementing its <code class="language-text">PreloadingStrategy</code> class.</p> <p>This will allow you to preload your core modules, the ones your users use the most, and let the other modules be loaded on demand. Reminds me of that old saying:</p> <blockquote> <p>Moderation in all the things is the best policy.</p> </blockquote> <p>So let’s get implementing 👨‍💻.</p> <h3 id="1--add-a-flag-to-routes" style="position:relative;"><a href="#1--add-a-flag-to-routes" aria-label="1 add a flag to routes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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- Add a flag to routes</h3> <p>First we need to add a flag to our routes so that we know which ones to preload and which to not. We assume we have four routes called <code class="language-text">Home</code>, <code class="language-text">Shop</code>, <code class="language-text">About</code>, and <code class="language-text">Contact</code> from which the first two are the most frequently visited routes.</p> <div class="gatsby-code-button-container" data-toaster-id="21666564742833283000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`routes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full', }, { path: 'home', component: HomeComponent, }, { path: 'shop', loadChildren: './shop/shop.module#ShopModule', data: { preload: true }, // flag we will use to track what route to be preloaded }, { path: 'about', loadChildren: './about/about.module#AboutModule', }, { path: 'contact', loadChildren: './contact/contact.module#ContactModule', }, ]`, `21666564742833283000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript">routes<span class="token operator">:</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> redirectTo<span class="token operator">:</span> <span class="token string">'home'</span><span class="token punctuation">,</span> pathMatch<span class="token operator">:</span> <span class="token string">'full'</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">'home'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> HomeComponent<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">'shop'</span><span class="token punctuation">,</span> loadChildren<span class="token operator">:</span> <span class="token string">'./shop/shop.module#ShopModule'</span><span class="token punctuation">,</span> data<span class="token operator">:</span> <span class="token punctuation">{</span> preload<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// flag we will use to track what route to be preloaded</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">'about'</span><span class="token punctuation">,</span> loadChildren<span class="token operator">:</span> <span class="token string">'./about/about.module#AboutModule'</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">'contact'</span><span class="token punctuation">,</span> loadChildren<span class="token operator">:</span> <span class="token string">'./contact/contact.module#ContactModule'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note</strong> The data property is reserved by the router to allow developers to add their custom values to their route configs.</div></div> <p>As you can see we used the data property to be able to define our flag. This will get used in our strategy later.</p> <h3 id="2--create-our-custom-strategy" style="position:relative;"><a href="#2--create-our-custom-strategy" aria-label="2 create our custom strategy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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- Create our custom strategy</h3> <p>Ok now it’s time to create our custom strategy:</p> <div class="gatsby-code-button-container" data-toaster-id="26303095312560054000" data-toaster-class="gatsby-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 { PreloadingStrategy, Route } from '@angular/router' import { Observable, of } from 'rxjs' export class CustomPreloadingStrategy implements PreloadingStrategy { preload(route: Route, load: Function): Observable<any> { return route.data && route.data.preload ? load() : of(null) } }`, `26303095312560054000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> PreloadingStrategy<span class="token punctuation">,</span> Route <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Observable<span class="token punctuation">,</span> <span class="token keyword">of</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs'</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">CustomPreloadingStrategy</span> <span class="token keyword">implements</span> <span class="token class-name">PreloadingStrategy</span> <span class="token punctuation">{</span> <span class="token function">preload</span><span class="token punctuation">(</span>route<span class="token operator">:</span> Route<span class="token punctuation">,</span> load<span class="token operator">:</span> <span class="token builtin">Function</span><span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> route<span class="token punctuation">.</span>data <span class="token operator">&amp;&amp;</span> route<span class="token punctuation">.</span>data<span class="token punctuation">.</span>preload <span class="token operator">?</span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token keyword">of</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>What is happening is that we just check the flag we added and preload the route if that is set to true. A preloading strategy expects a class with a method <code class="language-text">preload()</code>. The preload method should return an <code class="language-text">Observable</code> calling the load parameter or an <code class="language-text">Observable</code> of null. Now that we have the strategy defined lets use it.</p> <h3 id="3--use-the-custom-strategy-in-our-routing-module" style="position:relative;"><a href="#3--use-the-custom-strategy-in-our-routing-module" aria-label="3 use the custom strategy in our routing module permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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- Use the custom strategy in our routing module</h3> <p>Now that we have the basics lets use this custom strategy in our routing module:</p> <div class="gatsby-code-button-container" data-toaster-id="83215387219873090000" data-toaster-class="gatsby-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 { NgModule } from '@angular/core' import { Routes, RouterModule } from '@angular/router' import { HomeComponent } from './home/home.component' import { CustomPreloadingStrategy } from './custom-preloading-strategy' routes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full', }, { path: 'home', component: HomeComponent, }, { path: 'shop', loadChildren: './shop/shop.module#ShopModule', data: { preload: true }, // flag we will use to track what route to be preloaded }, { path: 'about', loadChildren: './about/about.module#AboutModule', }, { path: 'contact', loadChildren: './contact/contact.module#ContactModule', }, ] @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: CustomPreloadingStrategy, }), ], // Using our own custom preloader exports: [RouterModule], providers: [CustomPreloadingStrategy], }) export class AppRoutingModule {}`, `83215387219873090000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> NgModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Routes<span class="token punctuation">,</span> RouterModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> HomeComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./home/home.component'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> CustomPreloadingStrategy <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./custom-preloading-strategy'</span> routes<span class="token operator">:</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> redirectTo<span class="token operator">:</span> <span class="token string">'home'</span><span class="token punctuation">,</span> pathMatch<span class="token operator">:</span> <span class="token string">'full'</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">'home'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> HomeComponent<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">'shop'</span><span class="token punctuation">,</span> loadChildren<span class="token operator">:</span> <span class="token string">'./shop/shop.module#ShopModule'</span><span class="token punctuation">,</span> data<span class="token operator">:</span> <span class="token punctuation">{</span> preload<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// flag we will use to track what route to be preloaded</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">'about'</span><span class="token punctuation">,</span> loadChildren<span class="token operator">:</span> <span class="token string">'./about/about.module#AboutModule'</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">'contact'</span><span class="token punctuation">,</span> loadChildren<span class="token operator">:</span> <span class="token string">'./contact/contact.module#ContactModule'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span> RouterModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span>routes<span class="token punctuation">,</span> <span class="token punctuation">{</span> preloadingStrategy<span class="token operator">:</span> CustomPreloadingStrategy<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 comment">// Using our own custom preloader</span> exports<span class="token operator">:</span> <span class="token punctuation">[</span>RouterModule<span class="token punctuation">]</span><span class="token punctuation">,</span> providers<span class="token operator">:</span> <span class="token punctuation">[</span>CustomPreloadingStrategy<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">class</span> <span class="token class-name">AppRoutingModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And that’s it. Now if you run your application, the home component will load within the main bundle, shop component will load asynchronously in the background. It means that by the time user clicks the shop from the nav menu, it’s already loaded and it feels super fast.</p> <p>If user clicks on any of the about or contact, however, there would be another script loaded containing that component and you will need to handle the waiting time by showing a spinner or something. I am joking, I hate spinners, I will write another blog post soon on how to improve the performance so you won’t need a spinner.</p> <p>Hope this helps to increase your applications performance and make you curious enough to dive deeper in Angular and its awesome new features.</p> <p>Until next post, adiós.</p><![CDATA[How to migrate from WordPress to Jekyll and GitHub Pages]]>https://yashints.dev/blog/2018/06/06/blog-migrationhttps://yashints.dev/blog/2018/06/06/blog-migrationWed, 06 Jun 2018 00:00:00 GMT<p>I restarted my blogging around 2016 after loosing all of my previous content and chose <a href="https://wordpress.com" target="_blank" rel="nofollow noopener noreferrer">WordPress</a> because I wanted to focus on content rather than managing the site.</p> <!--more--> <p>However, after two years I realised there are a couple of issues really hurting user experience. There were limitations on page load speed because of plugins, managing the plugins and updating them regularly was another one 🔌.</p> <p>Apart from these the security wasn’t that good, the site was served over https, but because of nature of running content out of MySql there were serious risks I had to deal with using other plugins 🔐.</p> <p>Anyway, I decided to move to <a href="https://pages.github.com" target="_blank" rel="nofollow noopener noreferrer">GitHub Pages</a> and chose <a href="https://jekyllrb.com/" target="_blank" rel="nofollow noopener noreferrer">Jekyll</a> as the static resource generator.</p> <p>Again since I didn’t want to spend a lot of time, searching on google was the starting point. There are many good Jekyll templates which are already on GitHub and ready to use.</p> <p>I chose <a href="https://github.com/daattali/beautiful-jekyll" target="_blank" rel="nofollow noopener noreferrer">Beautiful Jekyll</a> which to me stood out from others.</p> <p><a href="https://mehraban.com.au" target="_blank" rel="nofollow noopener noreferrer">My website</a> is now up and running, but since I had to deal with a couple of tricks, I thought it would be useful to share my experience.</p> <h2 id="starting-point" style="position:relative;"><a href="#starting-point" aria-label="starting point permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 point</h2> <p>Fork the <a href="https://github.com/daattali/beautiful-jekyll" target="_blank" rel="nofollow noopener noreferrer">Beautiful Jekyll</a> repository on GitHub and rename it to <code class="language-text">yourusername.github.io</code>.</p> <p>The repository had a very detailed read me that you can follow for customising the site with your information. Most of the configs are in <code class="language-text">_config.yaml</code> file in the root.</p> <h2 id="next-step-exporting-wordpress" style="position:relative;"><a href="#next-step-exporting-wordpress" aria-label="next step exporting wordpress permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Next step exporting WordPress</h2> <p>This was a bit tricky for me since there is not an easy way to export your content and the media uploaded. So first I exported the content as an <code class="language-text">XML</code> file and then downloaded my photos from my hosting provider’s <code class="language-text">cPanel</code>.</p> <h2 id="converting-the-posts" style="position:relative;"><a href="#converting-the-posts" aria-label="converting the posts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Converting the posts</h2> <p>Since I hadn’t used <a href="https://en.wikipedia.org/wiki/Markdown" target="_blank" rel="nofollow noopener noreferrer">Markdown</a> format from beginning there was a lot of garbage in my posts including <code class="language-text">inline css</code>, <code class="language-text">pre</code> and <code class="language-text">code</code> tags, etc. If you are already using Markdown in your WordPress site, your job would be easier than mine.</p> <p>If not, you have some manual processing to do after converting the posts to Markdown.</p> <h3 id="what-tool-should-you-use-for-conversion" style="position:relative;"><a href="#what-tool-should-you-use-for-conversion" aria-label="what tool should you use for 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>What tool should you use for conversion</h3> <p>I did a search on tools to convert the exported site to Markdown, but many of them failed for me. The one that didn’t disappoint me is <code class="language-text">wpXml2Jekyll</code> which you can find <a href="https://github.com/theaob/wpXml2Jekyll/" target="_blank" rel="nofollow noopener noreferrer">on GitHub</a>.</p> <p>You have the option to download the source or you can download the binary and run it. It has an <code class="language-text">exe</code> file which you can use. A single command will convert your posts to Markdown and puts them in a folder.</p> <div class="gatsby-code-button-container" data-toaster-id="73325999543046190000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`wpXml2Jekyll [wordpress export file] [output folder]`, `73325999543046190000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">wpXml2Jekyll <span class="token punctuation">[</span>wordpress <span class="token builtin class-name">export</span> file<span class="token punctuation">]</span> <span class="token punctuation">[</span>output folder<span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>After running this command you would have a folder with all your posts as separate Markdown files.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 400px; " > <a class="gatsby-resp-image-link" href="/static/dda4302f1fc61771c61272dfebb19418/e17e5/postsmarkdown.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 134.44444444444446%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAIAAADzvTiPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC0ElEQVR42m2Ui3aqQAxF/f8vbHkKAyogII+2+KQ7ib2iV1fWGMdJcnJOZlZNe5iOp3meby+feb7ebtfrFWdps25e1FZd3+2KsmlbrOv79nDoOlnNbH9fN9V+Txl2cL6+v8krwfz4+PTidRLF6zCKMRw/DD3f//R8l+UkkxTk6jr8um2/f37uwfu69vwg5dRmk6RunaT4xLssA9H5fJ7/+zxgF1VFhcQ5YoIwIkUQRaTqh2EYx/Hrqxt6/H4cBzX8EykvF2xVlJUXBAQDmLAwjr0gjJPEDyPSbXc7wbTd7orCDB/Y0/GIrfZNE0Qx51LnOGXICQA2/D1UUMBG+OUfbHo2YvLtloVAGk6zDIe/ZhNM6TGo2FMwhIHLKU8Ylc3IWFZ7Qb0rkee2SPRUmROc9oOQkFTIc2QEeT+Mh45l/JkmjG6x4+l0D0ZnCIIY7XlDNRz0EsEFhG0KczohNQST7DEkMAyNWjxZIIfwUFzncGChbpq6aZHqAZtkMhJ5zt/EUI1pwyEXDiv/MphgZ85eg+k5UEkBzFFWlPvrPEMCoUqVut+NF8JEZ9GG/nJqghU/Vrp1Qnb8pLs3UrGrk0xYovxIvAFeawoMaMBeivSobEWwP3kzeCLXfWBoIMsZ8jfBEKY4HcjtPjodL+sZ5cuqgi4ejJdIDa412DkWNINtYizXtigYDG7Qcp7fwIYWoVobNp64WGRkPAcBfF3y9BRMwWyzsYLcDS6dvQd0QV5mg24JtsF+mPVMNYZOA2KlXTgz8sgEBFpgNrnADDays8Kf3Gek4jCX3Z4xY8vq86VNCG3cE3aKsuRtYoVFRk1hRzGTwCnwcxqRVKoUeU1nTvMwTNM0/w2ZXU8qNx+eRzVT1dQ69D3AyM0qD62+3sv34P6GyWMQhMqw9KkKy0wK3HxDq4TZi/eGbV5jsNIJBud0K6FFkeiTRjuMGHQCmyzny1PwL6bH2+5CVzlRAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Posts Converted to Markdown" title="" src="/static/dda4302f1fc61771c61272dfebb19418/e17e5/postsmarkdown.png" srcset="/static/dda4302f1fc61771c61272dfebb19418/01bf6/postsmarkdown.png 270w, /static/dda4302f1fc61771c61272dfebb19418/e17e5/postsmarkdown.png 400w" sizes="(max-width: 400px) 100vw, 400px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="copy-the-posts-to-your-site" style="position:relative;"><a href="#copy-the-posts-to-your-site" aria-label="copy the posts to your site permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Copy the posts to your site</h2> <p>Now you need to copy these files to your <code class="language-text">_posts</code> folder in the Jekyll site. You might need to check the content a bit to make sure everything looks as it should. Also fixing image paths should be in your mind, unless you decide to stick with WordPress file structure.</p> <h2 id="run-the-site-locally" style="position:relative;"><a href="#run-the-site-locally" aria-label="run the site 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>Run the site locally</h2> <p>If you want to run the site locally, there are two options. First and easiest is to install Jekyll on your system. I used <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10" target="_blank" rel="nofollow noopener noreferrer">WSL on windows</a> and more specifically <code class="language-text">Ubuntu</code> for this which is very easy to setup.</p> <p>After installing <code class="language-text">Ubuntu</code>, just follow the <a href="https://jekyllrb.com/docs/installation/#ubuntu" target="_blank" rel="nofollow noopener noreferrer">instructions</a> on Jekyll docs to install it.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note</strong>: Remember to update the WSL OS before installing Ruby and Jekyll. by running below command:</div></div> <div class="gatsby-code-button-container" data-toaster-id="49531215074579096000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`sudo apt-get update -y && sudo apt-get upgrade -y`, `49531215074579096000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt-get</span> update <span class="token parameter variable">-y</span> <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">apt-get</span> upgrade <span class="token parameter variable">-y</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once finished, you can go into your Ubuntu’s terminal and navigate to <code class="language-text">/mnt/{drive}/{yourrepofolder}</code> and run:</p> <div class="gatsby-code-button-container" data-toaster-id="26624566378248460000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`bundle exec jekyll serve`, `26624566378248460000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">bundle <span class="token builtin class-name">exec</span> jekyll serve</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This command will build your site and starts a server where you can view your site at <code class="language-text">localhost:4000</code>.</p> <h2 id="push-the-changes" style="position:relative;"><a href="#push-the-changes" aria-label="push the changes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Push the changes</h2> <p>Once happy push your changes to your <code class="language-text">master</code> branch and wait for a minute for the site to be generated. Now you can navigate to <code class="language-text">yourusername.github.io</code> and see how it looks like.</p> <h2 id="maintaining-the-links" style="position:relative;"><a href="#maintaining-the-links" aria-label="maintaining the 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>Maintaining the links</h2> <p>If you use a specific routing for your blog and want to maintain that so that after migration your old links still work, go into the <code class="language-text">_config.yaml</code> file and change the <code class="language-text">permalink</code> to match your URL pattern.</p> <p>In my case I got rid of my <code class="language-text">subdomain</code> as well and created a <code class="language-text">.htaccess</code> file in the root of my blog to change the domain and keep the path. This way it the old links will redirect to the main domain but still work. Here is how the <code class="language-text">.htaccess</code> file looks like:</p> <div class="gatsby-code-button-container" data-toaster-id="59276183571509320000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule (.*) https://mehraban.com.au/\$1 [R=301,L] </IfModule>`, `59276183571509320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token operator">&lt;</span>IfModule mod_rewrite.c<span class="token operator">></span> RewriteEngine On RewriteBase / RewriteRule <span class="token punctuation">(</span>.*<span class="token punctuation">)</span> https://mehraban.com.au/<span class="token variable">$1</span> <span class="token punctuation">[</span>R<span class="token operator">=</span><span class="token number">301</span>,L<span class="token punctuation">]</span> <span class="token operator">&lt;</span>/IfModule<span class="token operator">></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see I am doing a permanent redirect to my website. This way the back button won’t work and users will start using my main domain. After a while, I will delete the blog all together 😊.</p> <h2 id="some-improvements" style="position:relative;"><a href="#some-improvements" aria-label="some improvements permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Some improvements</h2> <h3 id="custom-domain" style="position:relative;"><a href="#custom-domain" aria-label="custom domain permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Custom domain</h3> <p>First thing for me was to use my custom domain on GitHub Pages. This part is very easy, you just need to update your DNS <code class="language-text">A records</code> to point to GitHub servers. You will find more information on <a href="https://help.github.com/articles/using-a-custom-domain-with-github-pages/" target="_blank" rel="nofollow noopener noreferrer">GitHub docs</a>.</p> <h3 id="enable-https" style="position:relative;"><a href="#enable-https" aria-label="enable https permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Enable HTTPS</h3> <p>When you’re finished wait for the DNS changes to finish, then you can tick the <code class="language-text">Enforce HTTPS</code> on GitHub which enables HTTPS for your site using <a href="https://letsencrypt.org/getting-started/" target="_blank" rel="nofollow noopener noreferrer">Let’s Encrypt</a> certificates.</p> <h3 id="add-comment-ability-to-posts" style="position:relative;"><a href="#add-comment-ability-to-posts" aria-label="add comment ability to posts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Add comment ability to posts</h3> <p>I needed to let users comment on my posts and with GitHub and Jekyll setup, the easiest way was to use <a href="https://disqus.com/" target="_blank" rel="nofollow noopener noreferrer">DISQUS</a>.</p> <p>If you don’t have an account, just open a free account and create a website. Once done, get your website name and update the <code class="language-text">_config.yaml</code> file:</p> <div class="gatsby-code-button-container" data-toaster-id="97397782409352280000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`# --- Misc --- # # Fill in your Disqus shortname (NOT the userid) if you want to support Disqus comments disqus: &quot;yashints&quot;`, `97397782409352280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"># --- Misc --- # # Fill in your Disqus shortname (NOT the userid) if you want to support Disqus comments disqus<span class="token operator">:</span> <span class="token string">"yashints"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>That’s it, you can see the comment box on each post and users can comment on them which is great with almost no effort.</p> <h3 id="add-share-icons-to-posts" style="position:relative;"><a href="#add-share-icons-to-posts" aria-label="add share icons to posts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Add share icons to posts</h3> <p>If you want to see share icons at the end of each post, just go to the <code class="language-text">share-links-active</code> section on the config file and set the desired social media flag to <code class="language-text">true</code>.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note</strong>: In order for the share icons to work, you will need to fill in the <code class="language-text">social-network-links</code> part in the config as well.</div></div> <h3 id="estimated-read-time" style="position:relative;"><a href="#estimated-read-time" aria-label="estimated read time permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Estimated read time</h3> <p>I used to have a plugin on the old blog which showed people how much time they have to spend reading the post. So I took the challenge and implemented mine. Here is how I did it:</p> <ol> <li>Add an html file to <code class="language-text">_include</code> folder named <code class="language-text">read-time.html</code></li> <li>Put the code below inside the file:</li> </ol> <div class="gatsby-code-button-container" data-toaster-id="15647092783169670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<span class=&quot;post-meta&quot; title=&quot;Estimated read time&quot;> - <i class=&quot;fa fa-clock-o&quot;></i> { % assign words = include.content | number_of_words % } { % if words < 360 % } 1 min { % else % } {{ words | divided_by:180 }} mins { % endif % } read </span>`, `15647092783169670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><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>post-meta<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Estimated read time<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>i</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>fa fa-clock-o<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>i</span><span class="token punctuation">></span></span> { % assign words = include.content | number_of_words % } { % if words &lt; 360 % } 1 min { % else % } {{ words | divided_by:180 }} mins { % endif % } read <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The code above takes the count of words of each post and divides it by 180 (average speed of a normal user). Nothing fancy here. I’ve also done some styling with the added class as well.</p> <ol start="3"> <li>Add a reference to the read time file in the header template in <code class="language-text">_include</code> folder:</li> </ol> <div class="gatsby-code-button-container" data-toaster-id="7136675860529329000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`{ % include read_time.html content=content % }`, `7136675860529329000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html">{ % include read_time.html content=content % }</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once done, you will have an estimate under post title like me:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 351px; " > <a class="gatsby-resp-image-link" href="/static/dfaf780dc8664cff146e7da99ebc46fe/08050/postreadtime.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 10.370370370370372%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAACABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAduQqD//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAWEAADAAAAAAAAAAAAAAAAAAABEDH/2gAIAQEAAT8hEf8A/9oADAMBAAIAAwAAABADz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABgQAAMBAQAAAAAAAAAAAAAAAAABMXFB/9oACAEBAAE/EIYjo3MP/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Reead time" title="" src="/static/dfaf780dc8664cff146e7da99ebc46fe/08050/postreadtime.jpg" srcset="/static/dfaf780dc8664cff146e7da99ebc46fe/6f81f/postreadtime.jpg 270w, /static/dfaf780dc8664cff146e7da99ebc46fe/08050/postreadtime.jpg 351w" sizes="(max-width: 351px) 100vw, 351px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Cool isn’t it? 😉</p> <h3 id="some-performance-tuning" style="position:relative;"><a href="#some-performance-tuning" aria-label="some performance tuning permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Some performance tuning</h3> <p>All the styles sheets are added to head in this template and since it is using <code class="language-text">bootstrap</code> the render blocking scripts are too much. So I added <code class="language-text">pre-loading</code> to all the style sheets.</p> <p>The only thing you need to do is to search for all link tags and change them to something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="58146174930491720000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<link rel=&quot;preload&quot; as=&quot;style&quot; onload=&quot;this.rel='stylesheet'&quot; href=&quot;{{ css | prepend: site.baseurl | replace: '//', '/' }}&quot; />`, `58146174930491720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></span> <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>style<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onload</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>rel<span class="token operator">=</span><span class="token string">'stylesheet'</span></span><span class="token punctuation">"</span></span></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>{{ css | prepend: site.baseurl | replace: '//', '/' }}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This is just an example, but what is happening is that we are telling the browser to pre load the <code class="language-text">css</code> file which doesn’t block the rendering. Once finished it changed the <code class="language-text">rel</code> attribute to <code class="language-text">stylesheet</code> so that the CSS get’s applied.</p> <p>This simple step has boosted up the performance by <strong>30%</strong> on Google page speed analyser.</p> <h3 id="add-search-to-your-entire-site" style="position:relative;"><a href="#add-search-to-your-entire-site" aria-label="add search to your entire site permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Add search to your entire site</h3> <p>I decided to use Google search for my site. So I created a new page called <code class="language-text">search.md</code> first:</p> <div class="gatsby-code-button-container" data-toaster-id="77748928443872430000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`--- layout: default title: 'Search the entire site' css: '/css/search.css' --- ## Search ### Using the Google <div class=&quot;google-custom-search&quot;></div>`, `77748928443872430000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html">--- layout: default title: 'Search the entire site' css: '/css/search.css' --- ## Search ### Using the Google <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>google-custom-search<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The next step is to create a site in <a href="https://cse.google.com/all" target="_blank" rel="nofollow noopener noreferrer">Google search</a>. Once done, it will give you a code snippet (clicking on get code) that you can simply put into your search page:</p> <div class="gatsby-code-button-container" data-toaster-id="24252014682168955000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<script> (function() { var cx = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; var gcse = document.createElement('script'); gcse.type = 'text/javascript'; gcse.async = true; gcse.src = 'https://cse.google.com/cse.js?cx=' + cx; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(gcse, s); })(); </script> <gcse:search></gcse:search>`, `24252014682168955000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token operator">&lt;</span>script<span class="token operator">></span> <span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> cx <span class="token operator">=</span> <span class="token string">'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'</span><span class="token punctuation">;</span> <span class="token keyword">var</span> gcse <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> gcse<span class="token punctuation">.</span>type <span class="token operator">=</span> <span class="token string">'text/javascript'</span><span class="token punctuation">;</span> gcse<span class="token punctuation">.</span>async <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> gcse<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'https://cse.google.com/cse.js?cx='</span> <span class="token operator">+</span> cx<span class="token punctuation">;</span> <span class="token keyword">var</span> s <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">'script'</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> s<span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>gcse<span class="token punctuation">,</span> s<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 operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator">&lt;</span>gcse<span class="token operator">:</span>search<span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>gcse<span class="token operator">:</span>search<span class="token operator">></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note</strong>: Do not use the above code as I have masked the unique identifier Google has issued specific to me.</div></div> <p>Hope you have a good migration and I will update this article as I customise the template even more 🔥.</p><![CDATA[I gave a talk in an official conference]]>https://yashints.dev/blog/2018/05/08/i-gave-a-talk-in-an-official-conferencehttps://yashints.dev/blog/2018/05/08/i-gave-a-talk-in-an-official-conferenceTue, 08 May 2018 00:00:00 GMT<p>I’ve been trying to actively improve my public speaking skills (one of the reasons why I blog less these days 😁) and started from local meetups and user groups. However, my goal was to give a talk in an official conference this year.</p> <!--more--> <p>I started to read blog posts from famous speakers around how to respond to <code class="language-text">CFP</code> (call for proposals) and practice at home. Choosing a topic can be very hard so I was trying to find something interesting that I feel comfortable talking about in front of audience.</p> <p>At the same time, I started doing brown bag sessions (short sessions sharing something you know in your own company or somewhere you work for) at Readify - where I work as a consultant - and got some internal feedback around what I should improve and areas that needed more focus.</p> <p>Let me tell you that what you read on internet or hear from others might not work for you, so you need to find the sweet spot and customise it for yourself wherever you can. That’s how I did it when I was responding to CFPs for different conferences.</p> <p>Since I was looking for improvement, I took part in an internal program called speak easy where we try to gather in our office at least once a month and focus on an area.</p> <p>We try to make it fun as well by doing something like PowerPoint karaoke where you need to talk from a slide deck that you haven’t seen at all and topics are usually chosen at random. It as been so much fun that we’ve made it a part of program to keep the fun side of learning as well.</p> <p>Long story short I got heaps of feedback from my short presentations on how do I talk, how is my physical movements, how slides are arranged and their logical correlation and many other aspects where every speaker should really care about.</p> <p>I’ve learnt to research about the audience in a conference and choose a topic that matches so that it would be interesting for people and they don’t feel their time is wasted.</p> <p>But the reason for writing this post is not to tell you my stories, but to share with you all the things that I’ve learnt by submitting talks to conferences and how I got to talk to an official conference as a first time speaker. So let’s begin.</p> <h3 id="choose-a-catchy-title-for-your-talk" style="position:relative;"><a href="#choose-a-catchy-title-for-your-talk" aria-label="choose a catchy title for your talk permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Choose a catchy title for your talk</h3> <p>When submitting a talk to a conference you have to be aware that more than 70 percent of your chance of getting accepted is around your title. It has to have enough information to let the reviewer know that what this is about, what you’re trying to deliver and who is your audience.</p> <p>I have near 20 failed attempts where I had to sit and think about what should I have done to make it more clear for the conference organisers what I am going to present but in a short sentence or two.</p> <p>Think of this as your 30 second elevator pitch for the subject you are trying to present. It has to be <strong>catchy</strong> and <strong>informative</strong>.</p> <h3 id="keep-rewriting-your-abstract-until-youre-happy" style="position:relative;"><a href="#keep-rewriting-your-abstract-until-youre-happy" aria-label="keep rewriting your abstract until youre happy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Keep rewriting your abstract until you’re happy</h3> <p>When you are finished your title, it is time to start writing your abstract. Here is your chance to point out more details about the talk and its structure. You can put something that you couldn’t put in title but was important to mention in here.</p> <p>There is a really good resource from NDC conferences that I used around this which has tons of good points on how to write it and what is its structure. It is titled <a href="https://blog.ndcconferences.com/make-me-an-offer-i-cant-refuse-writing-an-abstracts-for-a-cfp/" target="_blank" rel="nofollow noopener noreferrer">Make me an offer I can’t refuse</a>. I highly recommend you read this before submitting your abstract.</p> <p>It not only covers the abstract, but also goes through title and some examples of good ones, then it talks about how agenda committees narrow down and choose talks for a conference, and many more useful points.</p> <h2 id="bio" style="position:relative;"><a href="#bio" aria-label="bio permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Bio</h2> <p>This might seem trivial, but I assure you it is as important as rest the information about your talk. Specially if you are a first time speaker like me, this plays a key role in accepting or rejecting your talk.</p> <p>People who are reviewing the proposals won’t know you. So you have to let them know who you are, what you do and why they should choose you to give that talk rather than another speaker.</p> <p>I have near 86 different bio’s which I’ve written in near 4 month of trying and then I became happy with it. I used that one and believe it helped me with my talk getting accepted.</p> <h2 id="practice-practice-practice" style="position:relative;"><a href="#practice-practice-practice" aria-label="practice practice practice permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Practice practice practice</h2> <p>Knowing how much time do you have for a talk and preparing for that plays a key role on what content you put into your talk.</p> <p>I’ve listened to many great speakers and don’t prepare my content before I know it is accepted. This has helped me to not spend time on something that might take so much of my free time and I won’t be able to use it.</p> <p>There is a reverse relationship between time and deliver in my point of view. The shorter the time, the harder is to prepare for it. As an example I struggle to give lightning talks where as I feel comfortable giving a long one like 30 minute or an hour.</p> <p>The point here is that no matter how much time do you have, you have to practice so many times that you would feel comfortable giving this talk.</p> <p>I know it might sound silly but talking in front of mirror is a great way to practice. You can see yourself and your movements, how you talk and when you stumble upon something.</p> <p>How much eh, ah, hmm you use when you talk and so on would be very obvious after you watch yourself talking. Another way is to record your talk and watch it later if you don’t feel mirror is your friend.</p> <p>There would be still a couple of points to consider when practising. First is that consider the possibility that your talk might start a bit later than schedule and you have less time that what you practised for.</p> <p>This happened to me and I had to rush through my content, so much that I overkilled it and finished very early (almost 10 min).</p> <p>I find it if you make your talk modular (a point taken from <a href="https://tatham.blog/" target="_blank" rel="nofollow noopener noreferrer">Tatham Oddie</a> our CEO) it would be much easier to skip a section or two to make up for lost time.</p> <p>It also helps if you want to shuffle stuff around after practising because you realised that the relevance of a specific item is not correct where it is in your timeline.</p> <h3 id="do-not-eat-fatty-food-before-you-talk" style="position:relative;"><a href="#do-not-eat-fatty-food-before-you-talk" aria-label="do not eat fatty food before you talk permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Do not eat fatty food before you talk</h3> <p>My talk was right after lunch and I tried to not eat too much just in case it affects my voice. This is so true as I’ve been in a meetup where I had pizza before my talk and I struggled with my voice during presentation.</p> <h3 id="upload-your-slides-and-references-somewhere" style="position:relative;"><a href="#upload-your-slides-and-references-somewhere" aria-label="upload your slides and references somewhere permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Upload your slides and references somewhere</h3> <p>Usually people expect you to give your slides and references to them at the end of your talk. I had my slides uploaded but forgot to show where they can get it.</p> <p>This might affect the feedback you get from the talk because they feel you haven’t provided enough information so they can follow the topic further.</p> <p>Remember your talk is usually introducing something and you want your audience to go and explore it later. So give them somewhere they can start.</p> <h3 id="try-to-get-feedback" style="position:relative;"><a href="#try-to-get-feedback" aria-label="try to get feedback permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Try to get feedback</h3> <p>Almost all of the official conferences have a way for you to get feedback on your talk. This is very important for future because you can keep the good points and improve the weak ones.</p> <p>Try to contact the organisers beforehand and ask them what is the feedback mechanism. For my talk unfortunately I didn’t receive any feedback from audience and no one from the panel was there as well. So I leant what to do for my next time.</p> <h3 id="ask-for-recording" style="position:relative;"><a href="#ask-for-recording" aria-label="ask for recording permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Ask for recording</h3> <p>If they record your talk it is OK to ask for it later from them. Most of the conferences will do this for you and upload the video somewhere, but just in case you ask for it to have a reference for your next submission. I figured most of CFPs have a place for a link to one of your previous talks recording.</p> <h3 id="manage-your-stress-level" style="position:relative;"><a href="#manage-your-stress-level" aria-label="manage your stress level permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Manage your stress level</h3> <p>Although I had given talks to user groups and meetups, I was a bit nervous on the day. It was my first time and I didn’t know how many people will turn up. I started to walk 15 min before my talk and went into the room to get familiar to my surroundings.</p> <p>Check my connectivity and see if I can project to screens. I checked whether my slides aspect ratio matched the display or not. I started my presentation and checked whether my pre-recorded will play in good quality.</p> <p>This will help you to feel more relaxed when you begin. It eliminates the need to worry about the small things that can go wrong.</p> <h3 id="dont-do-live-coding" style="position:relative;"><a href="#dont-do-live-coding" aria-label="dont do live coding permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Don’t do live coding</h3> <p>If you happened to watch <a href="https://www.hanselman.com/" target="_blank" rel="nofollow noopener noreferrer">Scott Hanselman</a> and his talks, you will see he usually has live demos and writes code on the fly.</p> <p>Some other big names do the same. But those are in this field for a long time. We can’t compare ourselves with them. Of course it doesn’t mean you shouldn’t try, but not until you feel you have <code class="language-text">enough confidence</code> and a good <code class="language-text">backup plan</code>.</p> <p>There are a million thing that can go wrong from connectivity issues to demo Gods preventing you from showing something which works as you expect.</p> <p>Again I listened to my mentors and pre-recorded all of my demos and put the video’s in my slides. It worked very well and I didn’t have any stress whatsoever that something might go wrong when showing my audience how something works.</p> <h3 id="conclusion" style="position:relative;"><a href="#conclusion" aria-label="conclusion permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conclusion</h3> <p>Read and study around public speaking. It seems simple when you watch people on stage but I assure you it is very difficult and requires a lot of time and effort to get it right.</p> <p>Practice your talk multiple times until you feel comfortable and your speech is fluent enough and you don’t stumble between or in the middle of sentences.</p> <p>Get a mentor if you can and get help from them. Someone who has done public speaking can help you go a long way compared to when you prepare by yourself.</p> <h3 id="references" style="position:relative;"><a href="#references" aria-label="references permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>References</h3> <p>This are my goto places when it comes to gathering information about how to respond to proposals:</p> <ul> <li><a href="https://blog.ndcconferences.com/make-me-an-offer-i-cant-refuse-writing-an-abstracts-for-a-cfp/" target="_blank" rel="nofollow noopener noreferrer">https://blog.ndcconferences.com/make-me-an-offer-i-cant-refuse-writing-an-abstracts-for-a-cfp/</a></li> <li><a href="https://www.linkedin.com/pulse/getting-started-public-speaking-kristine-howard/" target="_blank" rel="nofollow noopener noreferrer">https://www.linkedin.com/pulse/getting-started-public-speaking-kristine-howard/</a></li> </ul> <p>And at the end if you are looking for conferences in Australia you can use <a href="https://github.com/Readify/DevEvents/" target="_blank" rel="nofollow noopener noreferrer">this Github repo</a> created by one my friends <a href="https://twitter.com/alexjmackey" target="_blank" rel="nofollow noopener noreferrer">Alex Mackey</a>.</p><![CDATA[Switching between VirtualBox and Hyper V]]>https://yashints.dev/blog/2018/04/13/switching-between-virtualbox-and-hyper-vhttps://yashints.dev/blog/2018/04/13/switching-between-virtualbox-and-hyper-vFri, 13 Apr 2018 00:00:00 GMT<p>Recently I had to switch between <a href="https://www.virtualbox.org/" target="_blank" rel="nofollow noopener noreferrer">VirtualBox</a> and <a href="https://en.wikipedia.org/wiki/Hyper-V" target="_blank" rel="nofollow noopener noreferrer">Hyper-V</a> and unfortunately these two don’t get along well 😉. So I started googling for a solution and this one was the one that got my attention.</p> <!--more--> <p>This solution uses a tool called <code class="language-text">bcdedit</code> on windows. The way it works is by duplicating your windows profile and set <code class="language-text">hypervisorlaunchtype</code> mode off in one of them. This way you don’t have to uninstall Hyper-V and restart to be able to start a VirtualBox virtual machine. So in this article I will show you how it is done.</p> <p>First let’s start by taking a backup just in case we mess it up.</p> <div class="gatsby-code-button-container" data-toaster-id="77396805479252740000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`bcdedit /export filepath\filename`, `77396805479252740000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">bcdedit /export filepath<span class="token punctuation">\</span>filename</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Note: if you don’t specify a path it will be saved wherever you are running the script (in case you are looking for it afterwards and you don’t remember where it was like me).</p> <p>Then we will create a copy of the current settings:</p> <div class="gatsby-code-button-container" data-toaster-id="61425356931648635000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`bcdedit /copy {current} /d &quot;Windows 10 No Hyper-V&quot;`, `61425356931648635000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">bcdedit /copy <span class="token punctuation">{</span>current<span class="token punctuation">}</span> /d <span class="token string">"Windows 10 No Hyper-V"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This command will output a <code class="language-text">GUID</code> which is the identifier of your newly created profile.</p> <div class="gatsby-code-button-container" data-toaster-id="6852761403995644000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`The entry was successfully copied to {271c695f-3ddb-11e8-877f-44850042c8be}.`, `6852761403995644000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">The entry was successfully copied to <span class="token punctuation">{</span>271c695f-3ddb-11e8-877f-44850042c8be<span class="token punctuation">}</span>.</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You will need this identifier to change the settings. If for any reason you didn’t manage to copy this you can get it by running <code class="language-text">bcdedit /enum</code> command.</p> <p>Now we will set the <code class="language-text">hypervisorlaunchtype</code> mode on this profile to <code class="language-text">off</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="77465811883125870000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`bcdedit /set {271c695f-3ddb-11e8-877f-44850042c8be} hypervisorlaunchtype off`, `77465811883125870000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">bcdedit /set <span class="token punctuation">{</span>271c695f-3ddb-11e8-877f-44850042c8be<span class="token punctuation">}</span> hypervisorlaunchtype off</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And the output will be something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="60826162083614065000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`The operation completed successfully.`, `60826162083614065000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">The operation completed successfully.</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now if you hold the shift key when restarting your windows you will have the option to boot into a windows with Hyper-V off and VirtualBox runs with no issues.</p> <p><img src="/0986f7995482b28bc0492456a142c667/windowsboot.gif" alt="Windows boot menu"></p> <p>You can take this even further by setting a default so you won’t have to switch too frequently:</p> <div class="gatsby-code-button-container" data-toaster-id="62854492527646610000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`bcdedit /default {271c695f-3ddb-11e8-877f-44850042c8be}`, `62854492527646610000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">bcdedit /default <span class="token punctuation">{</span>271c695f-3ddb-11e8-877f-44850042c8be<span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Hope this saves you some time so you can code instead of figuring this sort of stuff out.</p><![CDATA[IoT and some misconeptions]]>https://yashints.dev/blog/2018/03/21/iot-and-some-misconeptionshttps://yashints.dev/blog/2018/03/21/iot-and-some-misconeptionsWed, 21 Mar 2018 00:00:00 GMT<p>I’ve being reading around <a href="https://en.wikipedia.org/wiki/Internet_of_things" target="_blank" rel="nofollow noopener noreferrer">internet of things (IoT)</a> and playing with some of the kits available, however, this post is not about how to setup a device and read the data from sensors.</p> <!--more--> <p>After talking to some of my family and friends about this and asking what their take on the subject is, I figured most of the people have some misconceptions around it.</p> <p>In this article I want to explain what is IoT and some of the usage and concerns around it, but before I start, let me mention some of those misconceptions:</p> <p><strong>No 1 - IoT is a new phenomenon</strong></p> <p>I agree that the buzzword is fairly used recently, but what if I told you that the word internet of things (IoT) was coined in 1999 at MIT. Although at that time it described a network of connected RFID devices.</p> <p><strong>No 2 - It is all about sensors</strong></p> <p>Although most of the data gathered from devices are mostly produced by sensors, and it is a big part of IoT, however, there is much more to IoT than that. In short, It involves a lot of things such as APIs, networks, gateways, hubs, cloud, software, and the communication between the physical objects.</p> <p><strong>No 3 - IoT is not safe</strong></p> <p>Security will be a tricky subject with IoT devices as it is with any computer or embedded device. When we talk about sending data to cloud, one cannot deny the high possibility of attacks. However, a lot of work is already being done by the industry leaders in this space. network security protocols and government regulations like <a href="https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act" target="_blank" rel="nofollow noopener noreferrer">HIPAA (Health Insurance Portability and Accountability Act of 1996)</a> are forcing the industry to take more measures towards securing private data.</p> <p><strong>No 4 – It is all about wearables</strong></p> <p>Wearables might be the sexiest sort of IoT, and the most personal ones (two of five wearable users claim they feel naked without their devices!), but thy are a tiny portion of IoT settings in which it offers impressive value creation opportunities. Below you can find these from a report published by <a href="http://www.mckinsey.com/insights/business_technology/the_internet_of_things_the_value_of_digitizing_the_physical_world" target="_blank" rel="nofollow noopener noreferrer">MGI reports</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/510b72eaef9cc2e28fb64104499c31f3/0f529/iotinfo.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 95.55555555555554%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAACXBIWXMAAAsTAAALEwEAmpwYAAACfElEQVR42n2T6ZKaQBSFef9XM7ESZyou7LKJ0M0mi4CYr7trpvIrR6QucNdzT1tRFLmue7/f0zS9Xq++QpDn9zzPgyBwXKcoiiRO0iwtihK3LMv6vn+/36/Xy3Ich7CuVViXZb/f73a7IAzLsvgNDoc4jnHgDakTDZImSfp6bRZF0jSbpmnbNpLVClVZlkKIMAhOp9PxePz8+IjjhJe32y3nuudCCopbQsjrNeoUHgRTh97wk1IKUdIk/fOG5ouymOeZmI0f922zSHQ8nd8ar3VlHtPCuq7bP/h+YzyNYWW3/BpF9EPzRHquez6fKcUgvu+dzxea9zwvCEJFreMyMAT3/aCCm6alw6ZpaJVgzbYvZTVNI06Xy4V+hYasFBeA1OM4qmACkjTl3g/Dsq7QA/9Mucwz9Dqu62mQkVzcyUWluqrVzHAAI2RiVcuyZFlKkXEYmbCqKiGlZk6yAvUoRGvQdczFnr3fh0+CoZuAPxpkgaIwDG3bsW2bghSnsv57tuP4QTAMg8XD7sdP0pjKtyxDBlTDfjweZoVAF+saDWM8n08LrRwOH/P8bJTCViOgqq7pgspBgFh9xbDnoZ6ua00wuZ7zUymMNVD50fdGYXznmyrbtt+lVEDXdl/AQbWNeMhKD3gTzGzwCffdo/s6J36kDeqHGhh8GsfJMtPibeSt1sBV1zyy0lzDSNocqZtCXpSlYpsjsN//wpqXhb1PGmRlhfAMHXEclUWR33SWPM9SMmR0ro6kFJKx2aWsFMO2wgU/bEbApk1XwzdtBwp8glqLY348npjZHAwWirZRJXrwtE28kR0iQVi1kUtVwZE1aJiVMrwR7fe5+T/+AlqLHNjKHuMPAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="IoT Setting" title="" src="/static/510b72eaef9cc2e28fb64104499c31f3/302a4/iotinfo.png" srcset="/static/510b72eaef9cc2e28fb64104499c31f3/01bf6/iotinfo.png 270w, /static/510b72eaef9cc2e28fb64104499c31f3/07484/iotinfo.png 540w, /static/510b72eaef9cc2e28fb64104499c31f3/302a4/iotinfo.png 1080w, /static/510b72eaef9cc2e28fb64104499c31f3/0f529/iotinfo.png 1259w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>No 5 - IoT is About the Things</strong></p> <p>Because of the “Things” in the term, people usually tent to focus on that, however, IoT is about the business services that pull data from those IoT networks. Think of it as every single invention mankind has ever made is done to add value in one way or the other. There is no invention for the sake of creating something new.</p> <h1 id="definition" style="position:relative;"><a href="#definition" aria-label="definition permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Definition</h1> <p>The Internet of Things, or IoT, refers to billions of mechanical and digital machines, objects, animals and people with unique identifiers around the world that are now connected to the internet, collecting and sharing data without the need for human-to-human or human-to-computer interaction.</p> <p>If you are wondering how a human or an animal can be part of the network, imagine a human with a heart implant or a farm animal with a bio transponder which are in a network and being monitored for various reasons.</p> <p>IoT has evolved from the convergence of <a href="http://searchmobilecomputing.techtarget.com/definition/wireless" target="_blank" rel="nofollow noopener noreferrer">wireless</a> technologies, micro-electromechanical systems (<a href="http://searchcio-midmarket.techtarget.com/definition/micro-electromechanical-systems" target="_blank" rel="nofollow noopener noreferrer">MEMS</a>), <a href="http://searchsoa.techtarget.com/definition/microservices" target="_blank" rel="nofollow noopener noreferrer">microservices</a> and the internet.</p> <p>Kevin Ashton, cofounder of the Auto-ID Centre at MIT, first mentioned the Internet of Things in a presentation he made to Procter &#x26; Gamble in 1999. Here’s how he explained it:</p> <blockquote> <p>Today computers — and, therefore, the internet — are almost wholly dependent on human beings for information. Nearly all of the roughly 50 <a href="http://searchstorage.techtarget.com/definition/petabyte" target="_blank" rel="nofollow noopener noreferrer">petabytes</a> (a petabyte is 1,024 <a href="http://searchstorage.techtarget.com/definition/terabyte" target="_blank" rel="nofollow noopener noreferrer">terabytes</a>) of data available on the internet were first captured and created by human beings by typing, pressing a record button, taking a digital picture or scanning a bar code.</p> </blockquote> <p>The problem is, people have limited time, attention and accuracy, all of which means they are not very good at capturing data about things in the real world.</p> <p>If we had computers that knew everything there was to know about things - using data they gathered without any help from us - we would be able to track and count everything and greatly reduce waste, loss and cost. We would know when things needed replacing, repairing or recalling and whether they were fresh or past their best.</p> <h1 id="examples-of-its-usage" style="position:relative;"><a href="#examples-of-its-usage" aria-label="examples of its 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>Examples of its usage</h1> <p>While an IoT device can be as fluffy as a child’s toy to a very serious autonomous car, there are many more usages that people are currently adopting into their life style.</p> <h2 id="smart-homes" style="position:relative;"><a href="#smart-homes" aria-label="smart homes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Smart homes</h2> <p>Smart home technology, which co-ordinates and controls lights, televisions, security and air conditioning, is becoming mainstream, while at the top end, luxury homes are pushing the boundaries of technological innovation, particularly in the realms of entertainment.</p> <p>A touch-screen control panel in the kitchen controls the heating, cooling, security, blinds, music and other systems. Security is a key feature of the technology. The alarm can be deactivated from a smart phone or the keypad at the entrance. When the alarm is deactivated, four entrance doors automatically open and all blinds rise up.</p> <h2 id="wearables" style="position:relative;"><a href="#wearables" aria-label="wearables permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Wearables</h2> <p>There were<a href="http://expandedramblings.com/index.php/wearables-statistics/" target="_blank" rel="nofollow noopener noreferrer"> 78.1 million wearables sold</a> in 2015 and the market is expected to grow to 411 million by 2020. All wearable technologies including smart watches, fitness trackers, VR headsets and more, generate a ton of data that businesses are just beginning to understand the possibilities and potential applications for.</p> <h1 id="side-notes" style="position:relative;"><a href="#side-notes" aria-label="side notes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Side notes</h1> <h2 id="security" style="position:relative;"><a href="#security" aria-label="security permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Security</h2> <p>Security is one the biggest issues with the IoT. In many cased the sensors gather extremely sensitive information which should be secured to gain the consumer’s trust. Many IoT devices are given little thought to basics of security, like encrypting data in transit and at rest.</p> <p>Software bugs – even well-maintained code – are regularly found and fixed, however in case of IoT devices, many are not patchable.</p> <h2 id="data-privacy" style="position:relative;"><a href="#data-privacy" aria-label="data privacy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Data privacy</h2> <p>With all those sensors collecting data on everything you do, the IoT is a potentially vast privacy risk.</p> <p>Take the smart home:</p> <ul> <li>It can tell when you wake up (when the smart coffee machine is activated)</li> <li>How well you brush your teeth (thanks to your smart toothbrush)</li> <li>What radio station you listen to (thanks to your smart speaker)</li> <li>What type of food you eat (thanks to your smart oven or fridge)</li> <li>What your children think (thanks to their smart toys),</li> <li>Who visits you and passes by your house (thanks to your smart doorbell).</li> </ul> <p>What happens if this data reaches to thief’s or other types of criminals. Even if we don’t think that extreme, your data can be sold to other companies for things like advertisement which can get annoying too easily if you start getting targeted ads based on your daily activities.</p> <h2 id="big-data" style="position:relative;"><a href="#big-data" aria-label="big data permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Big data</h2> <p>The data generated by IoT is huge. This means that IoT can be a significant driver of big data projects because it allows companies to create giant data sets and analyse them.</p> <p>Giving a manufacturer vast amounts of data about how its components behave in real-world situations can help them to make improvements much more rapidly, while data culled from sensors around a city could help planners make traffic flow more efficiently.</p> <h2 id="smart-cities" style="position:relative;"><a href="#smart-cities" aria-label="smart cities permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Smart cities</h2> <p>By spreading a vast number of sensors over a town or city, planners can get a better idea of what’s really happening, in real time. As a result, smart cities projects are a key feature of the IoT.</p> <p>Cities already generate large amounts of data (from security cameras and environmental sensors) and already contain big infrastructure networks (like those controlling traffic lights). IoT projects aim to connect these up, and then add further intelligence into the system.</p> <h2 id="what-next" style="position:relative;"><a href="#what-next" aria-label="what 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>What next</h2> <p>As the price of hardware and communications continue to drop, it becomes cost-effective to add more devices to the IoT, even if in some cases there’s little obvious benefit to consumers.</p> <p>As the number of connected devices continues to rise, our living and working environments will become filled with smart products, assuming we are willing to accept the security and privacy trade-offs. Some will welcome the new era of smart things. Others will pine for the days when a washing machine was simply a machine and didn’t order powder from internet.</p><![CDATA[Angular and PWA, the life ahead of us]]>https://yashints.dev/blog/2018/02/09/angular-pwahttps://yashints.dev/blog/2018/02/09/angular-pwaFri, 09 Feb 2018 00:00:00 GMT<p><a href="https://developers.google.com/web/progressive-web-apps/" target="_blank" rel="nofollow noopener noreferrer">Progressive Web Applications (PWA)</a> are getting more and more attractions by day. With recent move from DevKit team, adding service worker support to the latest version of Safari, and <a href="https://www.windowscentral.com/first-batch-windows-10-progressive-web-apps-here" target="_blank" rel="nofollow noopener noreferrer">Microsoft adding progressive web applications to their store</a>, we can see the importance of the key role PWAs play in today’s market.</p> <!--more--> <p>With <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular version 5.0.0</a>, the team introduced a new version of their <a href="https://angular.io/guide/service-worker-intro" target="_blank" rel="nofollow noopener noreferrer">service worker aka (ngsw)</a> which has a ton of goodies from a fully functional service worker to full support for push notifications. In this post I will iterate through them and turn an existing application into a PWA.</p> <p>The demo application I’ve prepared can be found on <a href="https://github.com/yashints/Angular-PWA" target="_blank" rel="nofollow noopener noreferrer">my GitHub repo here</a>.</p> <h2 id="table-of-content" style="position:relative;"><a href="#table-of-content" aria-label="table of 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>Table of content</h2> <ol> <li><a href="#wispwa">What is a progressive web application?</a></li> <li><a href="#support">Current state of support in major browsers</a></li> <li><a href="#keycomponents">Key components</a></li> <li><a href="#lighthouse">How to evaluate your current application?</a></li> <li><a href="#appmanifest">Application manifest</a></li> <li><a href="#angularpwa">Angular and PWA</a></li> <li><a href="#ngsw">Angular Service Worker aka (ngsw)</a></li> <li><a href="#hood">Under the hood</a></li> <li><a href="#push">Push notifications</a></li> </ol> <h2 id="a-idwispwaawhat-is-a-progressive-web-application" style="position:relative;"><a href="#a-idwispwaawhat-is-a-progressive-web-application" aria-label="a idwispwaawhat is a progressive web 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><a id="wispwa"></a>What is a progressive web application?</h2> <p>In 2015, designer <strong>Frances Berriman</strong> and <a href="https://en.wikipedia.org/wiki/Google_Chrome" target="_blank" rel="nofollow noopener noreferrer">Google Chrome</a> engineer <strong>Alex Russell</strong> coined the term <code class="language-text">progressive web apps</code>.  These are applications which leverage new features supported by modern browsers such as <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest" target="_blank" rel="nofollow noopener noreferrer">application manifest</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" target="_blank" rel="nofollow noopener noreferrer">service worker</a> allowing us to create faster, more engaging and reliable applications.</p> <p>They have the following characteristics:</p> <ul> <li><strong>Progressive</strong> - Work for every user, regardless of browser choice because they’re built with <a href="https://en.wikipedia.org/wiki/Progressive_enhancement" target="_blank" rel="nofollow noopener noreferrer">progressive enhancement</a> as a core tenet.</li> <li><strong>Responsive</strong> - Fit any form factor: desktop, mobile, tablet, or forms yet to emerge.</li> <li><strong>Connectivity independent</strong> - <a href="https://en.wikipedia.org/wiki/Progressive_web_app#Service_Workers" target="_blank" rel="nofollow noopener noreferrer">Service workers</a> allow work offline, or on low quality networks.</li> <li><strong>App-like</strong> - Feel like an app to the user with app-style interactions and navigation.</li> <li><strong>Fresh</strong> - Always up-to-date thanks to the service worker update process.</li> <li><strong>Safe</strong> - Served via HTTPS to prevent snooping and ensure content hasn’t been tampered with.</li> <li><strong>Discoverable</strong> - Are identifiable as “applications” thanks to W3C manifests<sup><a href="https://en.wikipedia.org/wiki/Progressive_web_app#cite_note-w3cmanifest-6" target="_blank" rel="nofollow noopener noreferrer">[6]</a></sup> and service worker registration scope allowing search engines to find them.</li> <li><strong>Re-engageable</strong> - Make re-engagement easy through features like <a href="https://en.wikipedia.org/wiki/Push_technology" target="_blank" rel="nofollow noopener noreferrer">push notifications</a>.</li> <li><strong>Installable</strong> - Allow users to “keep” apps they find most useful on their home screen without the hassle of an app store.</li> <li><strong>Linkable</strong> - Easily shared via a URL and do not require complex installation. These applications look very similar to a native mobile application and offer some features that makes user very happy. The most important one is ability to add the application to your device’s home screen. Accessing device’s hardware like location, camera and etc. is another thing where it gives a native experience to users.</li> </ul> <h2 id="a-idkeycomponentsakey-components" style="position:relative;"><a href="#a-idkeycomponentsakey-components" aria-label="a idkeycomponentsakey 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><a id="keycomponents"></a>Key components</h2> <p>There are three key components you will have to add to your project to be able to say your web application is progressive.</p> <h3 id="application-manifest" style="position:relative;"><a href="#application-manifest" aria-label="application manifest permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 manifest</h3> <p>From <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest" target="_blank" rel="nofollow noopener noreferrer">Mozilla documents</a>:</p> <blockquote> <p>The web app manifest provides information about an application (such as name, author, icon, and description) in a <code class="language-text">JSON</code> text file. The purpose of the manifest is to install web applications to the homescreen of a device, providing users with quicker access and a richer experience.</p> </blockquote> <h3 id="service-worker" style="position:relative;"><a href="#service-worker" aria-label="service worker permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 worker</h3> <p>A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don’t need a web page or user interaction. It includes offline support, request caching, <a href="https://developers.google.com/web/updates/2015/03/push-notifications-on-the-open-web" target="_blank" rel="nofollow noopener noreferrer">push notifications</a> and <a href="https://developers.google.com/web/updates/2015/12/background-sync" target="_blank" rel="nofollow noopener noreferrer">background sync</a>.</p> <h3 id="app-shell" style="position:relative;"><a href="#app-shell" aria-label="app shell permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>App shell</h3> <p>An <strong>application shell</strong> (or app shell) architecture is one way to build a Progressive Web App that reliably and instantly loads on your users’ screens, similar to what you see in native applications.</p> <h2 id="a-idsupportacurrent-state-of-support-in-major-browsers" style="position:relative;"><a href="#a-idsupportacurrent-state-of-support-in-major-browsers" aria-label="a idsupportacurrent state of support in major browsers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a id="support"></a>Current state of support in major browsers</h2> <p>Most of the major browsers have been trying to add support for application manifest and service workers. By the start of the last year <a href="https://www.google.ca/chrome/browser/desktop/index.html" target="_blank" rel="nofollow noopener noreferrer">Chrome</a> and <a href="https://play.google.com/store/apps/details?id=com.android.chrome&#x26;hl=en" target="_blank" rel="nofollow noopener noreferrer">Chrome mobile</a> had full support, whereas <a href="https://www.apple.com/au/safari/" target="_blank" rel="nofollow noopener noreferrer">Safari</a> wasn’t even looking into it. <a href="https://www.microsoft.com/en-au/windows/microsoft-edge" target="_blank" rel="nofollow noopener noreferrer">Microsoft Edge</a> not only were working on it, but also looking into adding PWA’s to their store with the help of <a href="https://electronjs.org" target="_blank" rel="nofollow noopener noreferrer">ElectronJS</a>. Mozilla’s <a href="https://www.mozilla.org/en-US/firefox/new" target="_blank" rel="nofollow noopener noreferrer">FireFox</a> team was supporting most of the features as well but they were a bit behind <a href="https://www.google.com" target="_blank" rel="nofollow noopener noreferrer">Google</a> on that.</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/579975b09e1d944583efe49ea3a50784/00d43/pwasupport2016.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 12.962962962962962%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAwklEQVR42gG3AEj/AGJsVXBqUm97UoqbXYKNVH2GXYWWWLe3ptjW2JSejF1lSGVxVJmJUqGRSJOMbqmaacLAqtTU2bq7t5acmQBQekeGfm+fnT+Hb1CbpkqffkSIilnMzqrMztqgmIViLxeRej32u3j/xka1jrKyid3k3bDIytLp6OiBrNYAdJ1ydqd6pbNvuphQvrlcwa1cuqNS2d7F4d7jr7WhdW5TrKpy/sl4/s1m38Wg0rWq6eO+1tfb7OrmwtLi/cZthwzG6RcAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="PWA support 2016" title="" src="/static/579975b09e1d944583efe49ea3a50784/00d43/pwasupport2016.png" srcset="/static/579975b09e1d944583efe49ea3a50784/01bf6/pwasupport2016.png 270w, /static/579975b09e1d944583efe49ea3a50784/07484/pwasupport2016.png 540w, /static/579975b09e1d944583efe49ea3a50784/00d43/pwasupport2016.png 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" decoding="async" /> </a> </span></p> <p>Later in the year there was a massive effort put into supporting the new APIs and surprisingly Apple started working on it seriously. Microsoft Edge got it in preview and Safari added some basic support as well.</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/d8bdd16fdb6e0488bcc1658019525f35/00d43/pwasupport2017.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 12.222222222222221%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAhUlEQVR42gF6AIX/AHp5XnJuTG9uWH5zSomRV4eVW4WEUYiZZcnGusXKyXBiSGNcPqWTWbOaSXFsj4aBjI2lcquxdaqlT6qsawBmmniCmWZhk2+OpWqsjkSqn0u0mESnmlXa3c7N0NJ3Y0h5bELrw2/lvWSCfLSblK+Suou6zIvMy1/DyXywKkFvZdf/awAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="PWA support 2017" title="" src="/static/d8bdd16fdb6e0488bcc1658019525f35/00d43/pwasupport2017.png" srcset="/static/d8bdd16fdb6e0488bcc1658019525f35/01bf6/pwasupport2017.png 270w, /static/d8bdd16fdb6e0488bcc1658019525f35/07484/pwasupport2017.png 540w, /static/d8bdd16fdb6e0488bcc1658019525f35/00d43/pwasupport2017.png 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" decoding="async" /> </a> </span></p> <blockquote> <h6 id="photo-from-httpsispwareadytoxicjohanncom" style="position:relative;"><a href="#photo-from-httpsispwareadytoxicjohanncom" aria-label="photo from httpsispwareadytoxicjohanncom permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Photo from : <a href="https://ispwaready.toxicjohann.com/" target="_blank" rel="nofollow noopener noreferrer">https://ispwaready.toxicjohann.com</a></h6> </blockquote> <h2 id="a-idlighthouseahow-to-evaluate-your-current-application" style="position:relative;"><a href="#a-idlighthouseahow-to-evaluate-your-current-application" aria-label="a idlighthouseahow to evaluate your current 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><a id="lighthouse"></a>How to evaluate your current application?</h2> <p>Your question now might be where to start. There are some tools that allow you to evaluate your application against the PWA requirements. However the most easy to use is <a href="https://developers.google.com/web/tools/lighthouse/" target="_blank" rel="nofollow noopener noreferrer">Lighthouse</a> which is now built in <a href="https://developer.chrome.com/devtools" target="_blank" rel="nofollow noopener noreferrer">Chrome DevTools</a>.</p> <p>If you open up your developer tools and go to Audits tab, you will see its logo in the middle of the page and there is an audit button which you can click to get started with your application.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 602px; " > <a class="gatsby-resp-image-link" href="/static/8723f124fef37585cdf45c604147a4c8/32056/lighthouse.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 67.77777777777777%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAAsTAAALEwEAmpwYAAABdElEQVR42qWSTUrEMBTH5wieYE7g2o0H8AYyICiC4EIdGBDdiAdw50oUdDZuXSgoiuNWFBXRTUVFLLZNmqadtmNnpm1eYvoxgjhf4j+lCS/vl5fX/gsYY4tSwzAopQhhQoj2oVFqI4QMXQbtfAvL2bCTHMMk9E1FhDoFxmLG8pdUq9Vy3ToAJLE4zhbfAjnS1CiSExTEP9QH5okAOHAGf4SBSzo9Iz9pKDjJ4pEr2Kv36T5d3SunF4+qjMJQcFrEelEeppf1jZWjrcXtYknUbhIYYNC1sxvOr8PImJidU9cWnovjYrLM8i54bzjb8wM+VRETFa28vzlT3RtdVUpLgrp8AJyJAaeO8GLHEYrG0TtDvi9i1rfnOIoyY2TOCNvAQgGRYGHqjo6ToNP6D9jEWE/NiE2TENwOnDCw2w0SBo5meqpeD1LJAl3g1BSyrGwLLDeu1vxd+Zx7O2e+Stjvv93zazsNOLwOjm+bJ3fNg8sA17vAX2TVG5JB58YtAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Lighthouse" title="" src="/static/8723f124fef37585cdf45c604147a4c8/32056/lighthouse.png" srcset="/static/8723f124fef37585cdf45c604147a4c8/01bf6/lighthouse.png 270w, /static/8723f124fef37585cdf45c604147a4c8/07484/lighthouse.png 540w, /static/8723f124fef37585cdf45c604147a4c8/32056/lighthouse.png 602w" sizes="(max-width: 602px) 100vw, 602px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Even without doing anything you could browse your application and audit it to see how compliant your app is. When you run the report you will see a report like below and there are even hints on how to fix some of those.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 721px; " > <a class="gatsby-resp-image-link" href="/static/f5a8ebf12e6bcd382cfc09b40397955c/01dae/score.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 70.37037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAAsTAAALEwEAmpwYAAABm0lEQVR42pVS25KdIBDk/38yR1cURFRm0FWu2+qm8nC2kkpXS40wl2YGUWsttSbSNez1RkxxZFNKfn75YOOn+hvrvtJBd1QRJWdm7ybFq035CnDsGtWEEB5vs5oP3ZVSrrwxSSPHZXyORDhPJvLbzt4/ATnnFJHnuzJssFz66nUSIogtVBVqGGTXyb5vm2YczbbthFzes+dt25y7bM+0uE3P5+zO55phUWWb78rs4ZcS0lfIS9+I1xfjs4SLOcZcbkBBzUmc56mVGvp+nme3OudW+NZ/ApViFHCdrDXGaDOO06SNsdbu+yf2zxDA8g4IxP55CoiapDRNo16vEdduW9O2sNe+X5Rah+Hu1BtiRPw9Kim56+ijc72kYSCsUgZrC3Mml4gT0cPoXFpdPg70BsoFRsIo8vrl1LCT42XB5I59R1K07o3xIiIxyCfYzzOD00Rak53QejyyvzTrujNko2G4s+06K7ul70kpB2odliVBMFNmn5h/SHDrEtvmjdZGKYY3hnRL+qPzscuPLa/iOD4dETPjKeF51f/BF063LK+/37xzAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Lightouse score" title="" src="/static/f5a8ebf12e6bcd382cfc09b40397955c/01dae/score.png" srcset="/static/f5a8ebf12e6bcd382cfc09b40397955c/01bf6/score.png 270w, /static/f5a8ebf12e6bcd382cfc09b40397955c/07484/score.png 540w, /static/f5a8ebf12e6bcd382cfc09b40397955c/01dae/score.png 721w" sizes="(max-width: 721px) 100vw, 721px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>You can see how detail the report is and if you open those red items you will see what is missing.</p> <h2 id="a-idappmanifestaapplication-manifest" style="position:relative;"><a href="#a-idappmanifestaapplication-manifest" aria-label="a idappmanifestaapplication manifest permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a id="appmanifest"></a>Application manifest</h2> <p>Application manifest is a normal <code class="language-text">JSON</code> file containing the initial flags and attributes a PWA needs. They vary from theme colour to short name which appears below the icon on your device home screen when you add it (amazingly it supports emoji’s).</p> <p>Theme colour tells the browser what colour to choose for background on address bar and toolbar. A sample is shown in below picture.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 894px; " > <a class="gatsby-resp-image-link" href="/static/0cdc81b7d96549c0e928b890d4c70dbc/38af3/themecolor.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 76.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAADKElEQVR42rWUa0iTYRTH32Xb3M2Z6eZ0NcPKDCKzYk5D0k2zQqEPdlmlFlg2r3NasxpkN4eXeYPKxCztQhZdqKiWBIKklNDF+SFzXyP6EOV96338905zvl2gTx14OB/O7/lxDud9Xor6H6HVaper1eqWqDVRDyIiIuxSqfQJl8t9yOSSnwhnlt0Ury7cGLP6flx05ONV4SF2uXj+I6WU1xauDFrqFaanp+8ymUqQazCQvPx8ZGdnE4PBgNTUVCdblklRvhsP2fo1pbcQmdNKFmc1ITTjAq3YYYNKk7bTKzQaC/ZMTLpAAy4A3zGT8dRuH2LKPNYwQsvNvv7mQaDyFVynevDd+hqTJ7qGkZRh3OOlUlKSD9iqrKg4c5I+Zi6FucRIqipOo8CQ4xFSjHu2S/+y4nznxYZKWMuPkLPHTagqN9P11hNI25qS7hUqN2zbJz38En7mN0Rk6oWgqIcIywYQsPu8k5oxTgvTKErin9HyXmwZhLD4JeEX9YJb3EeLCrsgT9i33StcGJellzW6sbQVRHN9CrE3CNHcAYIKnjjZy4uhKIG0uLs/rA2IbidEfW0KMR2gV54fhkhnYgv36oUVXxFQN0mC60YRWDNCJA2AMPv+tHBtE4Sx9yBhZhIIcjsdfo2ArHaEyGtHsaDOTfue/IQF2rwdXqGMEXJOD4NX7SaKhgkE2MYIZQMEjBCsLRsZIT/3ucNTC6gdJ8H1E+BW0zSn/DPkyYVzQmW8Xk9ZvkB73UU6HBNo7B0jPjUAb//dP4Q+B+0OYT1Q82KM3B4YR/xVN00d/YiQZFaHioS9en69C5ImkPArUwhtIYTbDIjzH/8i9IwsLul28Jiahwm/POW5Q/Orv0G+mdXhsnWJO3XGc9CWXnInmZrpBONF9+aj7Vi/vegD+8Nmwlez2/w2haklMoyOYXWlra7EggZExm2ZW4pMFrhLzPeBmMshYt68mczlwF8kGGI/vczMTF8/If+dmMeBaJrleFhawtyVBwbOCVUqVaRi8ZKOYKXKzjqdIcowy+9vOVS1pCxYGdb5k3nmyYpFYbcVKtWKv/0nOKzzr/gr9wPX/oFWpdI7FAAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Theme colour" title="" src="/static/0cdc81b7d96549c0e928b890d4c70dbc/38af3/themecolor.png" srcset="/static/0cdc81b7d96549c0e928b890d4c70dbc/01bf6/themecolor.png 270w, /static/0cdc81b7d96549c0e928b890d4c70dbc/07484/themecolor.png 540w, /static/0cdc81b7d96549c0e928b890d4c70dbc/38af3/themecolor.png 894w" sizes="(max-width: 894px) 100vw, 894px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <blockquote> <h6 id="httpsdevelopersgooglecomwebupdates201508using-manifest-to-set-sitewide-theme-color------" style="position:relative;"><a href="#httpsdevelopersgooglecomwebupdates201508using-manifest-to-set-sitewide-theme-color------" aria-label="httpsdevelopersgooglecomwebupdates201508using manifest to set sitewide theme color permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>*<a href="https://developers.google.com/web/updates/2015/08/using-manifest-to-set-sitewide-theme-color*%C2%A0" target="_blank" rel="nofollow noopener noreferrer">https://developers.google.com/web/updates/2015/08/using-manifest-to-set-sitewide-theme-color* </a>            </h6> </blockquote> <p>As you can see in the right side, the background colour of the address bar is replaced with the application’s theme colour to maintain the consistency of the user experience and make it more interesting. Just note that this is only supported when you open your application from home screen.</p> <p>The most important attribute on application manifest is the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest#display" target="_blank" rel="nofollow noopener noreferrer">display mode</a>. This defines how your application is displayed when opened from home screen. There currently four modes in the specification:</p> <ul> <li><strong>fullscreen</strong>: All of the available display area is used and no user agent <a href="https://developer.mozilla.org/en-US/docs/Glossary/chrome" target="_blank" rel="nofollow noopener noreferrer">chrome</a> is shown.</li> <li><strong>standalone</strong>: The application will look and feel like a standalone application. This can include the application having a different window, its own icon in the application launcher, etc. In this mode, the user agent will exclude UI elements for controlling navigation, but can include other UI elements such as a status bar.</li> <li><strong>minimal-ui</strong>: The application will look and feel like a standalone application, but will have a minimal set of UI elements for controlling navigation. The elements will vary by browser.</li> <li><strong>browser</strong>: The application opens in a conventional browser tab or new window, depending on the browser and platform. This is the default. To get a better understanding of their difference have a look at the how the application is displayed in different modes. From left to right they are <code class="language-text">minimum-ui</code>, <code class="language-text">standalone</code>, and <code class="language-text">full screen</code>.</li> </ul> <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/e0046107a5c07e5f011f9686ba208635/105d8/launchfullscreen.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,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAACRElEQVR42jWRzWsTQRjG9w/x6tWDJy+CJ8FLwKzBQKxopRZLKniSQi+KKGqVgheh4ndTK6FWm/QjTa20TUub9NNWSprs5mProqlp0mR3Zt6Z3fFNQ4bhZfjN884884zyuGfyTttwt3/wdiAUvBzqUkOp+XzvlWjwQvjW+eEbZ0M3z33q8Y9tLZp9nSv93cnnXclH15bu+ROvejeVuxd/BE6NtZ+ZuHo66js56jkRTsbNxUhh8kMmNqRFXu99G0jHPmar/8gfo2IWK/uFyn7+8He+XDKPlFTcmP+qL4/nF0e02bA+90WvlIiU0nUdLLIx3OZ0pcApG9VpLpTmBki33tLhoIRxgFiaRjeOcM0oE8JhDIDDcpHulZgjgDGucAblOvQv2Pff7aVydRebON7J54vwdNx8MZiazqIRzhC6EMnAw9H9vs+7+iFIhyuIVk3xbEqfjs+8TNmog2PdsiHezCZDC8m5AtoBdnzi+00amfk+MPtr66+LGkVwsIgzup4bSv7MHLiSEXTI8X7CN3IHa3qZ2pxTihCVlRqf2MmvaGV0ghqFMUYs266SapmQmk0xKAefx2yLcHy5RW1CMRGEAEAtSutAahQpnq9I2UoUCwEeXZVctGCDugdHfGrj2DrGwbmAhi8hhOsqhmFks5qW1fRcLru9u/Xgbe2wWjQMrQmLhfTS2s6TQRCNFgycEQZSWnPb9ZElJRgMejweVVUvqapXVX3X2xKJREdHB0KvF4Hq9amBznbTNNEFND4L0JiVNurrmf/HUCgR0k1pKgAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Lunch full screen" title="" src="/static/e0046107a5c07e5f011f9686ba208635/302a4/launchfullscreen.png" srcset="/static/e0046107a5c07e5f011f9686ba208635/01bf6/launchfullscreen.png 270w, /static/e0046107a5c07e5f011f9686ba208635/07484/launchfullscreen.png 540w, /static/e0046107a5c07e5f011f9686ba208635/302a4/launchfullscreen.png 1080w, /static/e0046107a5c07e5f011f9686ba208635/105d8/launchfullscreen.png 1170w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <blockquote> <h6 id="photo-from-chromium-blog" style="position:relative;"><a href="#photo-from-chromium-blog" aria-label="photo from chromium blog permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>photo from Chromium Blog</h6> </blockquote> <p>The easiest way to create your application’s manifest file is to use some of the tools out there. The one I like is called <em>App Manifest Generator</em> and you can find it <a href="https://app-manifest.firebaseapp.com/" target="_blank" rel="nofollow noopener noreferrer">here</a>.</p> <h2 id="a-idangularpwaaangular-and-pwa" style="position:relative;"><a href="#a-idangularpwaaangular-and-pwa" aria-label="a idangularpwaaangular and pwa permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a id="angularpwa"></a>Angular and PWA</h2> <p>With the introduction of <a href="https://angular.io/guide/service-worker-intro" target="_blank" rel="nofollow noopener noreferrer">Angular Service Worker</a> after releasing their version <code class="language-text">5.0.0</code> and the Angular CLI built-in PWA support, it’s now easier than ever to make your web application faster, more reliable, more engaging, and installable like a native one.</p> <p>Let’s see what they say about their new addition to the family:</p> <blockquote> <p>Angular’s service worker is designed to optimize the end user experience of using an application over a slow or unreliable network connection, while also minimizing the risks of serving outdated content.</p> </blockquote> <p>To use Angular service workers, you must have the following Angular and CLI versions:</p> <ul> <li>Angular 5.0.0 or later.</li> <li>Angular CLI 1.6.0 or later.</li> </ul> <h2 id="a-idngswaangular-service-worker-aka-ngsw" style="position:relative;"><a href="#a-idngswaangular-service-worker-aka-ngsw" aria-label="a idngswaangular service worker aka ngsw permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a id="ngsw"></a>Angular Service Worker aka (ngsw)</h2> <p>In previous versions of Angular, you had to use a third party library like <code class="language-text">sw-precache</code> or <a href="https://developers.google.com/web/tools/workbox/" target="_blank" rel="nofollow noopener noreferrer">workbox</a> to add a service worker to your application. <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular</a> team have spent a fair amount of time on creating their own service worker aka <code class="language-text">ngsw</code> and adding the support to its CLI which you can add to your project with a couple of commands. The first one would be obviously to install it:</p> <div class="gatsby-code-button-container" data-toaster-id="74057005434153810000" data-toaster-class="gatsby-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 @angular/service-worker --save`, `74057005434153810000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @angular/service-worker <span class="token parameter variable">--save</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>At this point there would be two possible scenario, either you already have an Angular application and want to add PWA support to it, or you are creating a new application. I will go through the former in another post.</p> <p>In terms of the later, it would be very easy:</p> <div class="gatsby-code-button-container" data-toaster-id="26938396685779263000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng new angular-pwa-app --service-worker`, `26938396685779263000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng new angular-pwa-app --service-worker</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And you’ve got the basic generated for you to <em>progressify</em> your application. This means you now should have configuration file <code class="language-text">ngsw-config.json</code> in your project which tell service worker what to do. You should also have the service worker itself <code class="language-text">ngsw-worker.js</code> in your <code class="language-text">node_module</code> folder.</p> <p>Here is what’s inside the configuration file:</p> <div class="gatsby-code-button-container" data-toaster-id="8728622609436520000" data-toaster-class="gatsby-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;index&quot;: &quot;/index.html&quot;, &quot;assetGroups&quot;: [ { &quot;name&quot;: &quot;app&quot;, &quot;installMode&quot;: &quot;prefetch&quot;, &quot;resources&quot;: { &quot;files&quot;: [&quot;/favicon.ico&quot;, &quot;/index.html&quot;], &quot;versionedFiles&quot;: [&quot;/*.bundle.css&quot;, &quot;/*.bundle.js&quot;, &quot;/*.chunk.js&quot;] } }, { &quot;name&quot;: &quot;assets&quot;, &quot;installMode&quot;: &quot;lazy&quot;, &quot;updateMode&quot;: &quot;prefetch&quot;, &quot;resources&quot;: { &quot;files&quot;: [&quot;/assets/**&quot;] } } ] }`, `8728622609436520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"index"</span><span class="token operator">:</span> <span class="token string">"/index.html"</span><span class="token punctuation">,</span> <span class="token property">"assetGroups"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"app"</span><span class="token punctuation">,</span> <span class="token property">"installMode"</span><span class="token operator">:</span> <span class="token string">"prefetch"</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 property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/favicon.ico"</span><span class="token punctuation">,</span> <span class="token string">"/index.html"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"versionedFiles"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/*.bundle.css"</span><span class="token punctuation">,</span> <span class="token string">"/*.bundle.js"</span><span class="token punctuation">,</span> <span class="token string">"/*.chunk.js"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"assets"</span><span class="token punctuation">,</span> <span class="token property">"installMode"</span><span class="token operator">:</span> <span class="token string">"lazy"</span><span class="token punctuation">,</span> <span class="token property">"updateMode"</span><span class="token operator">:</span> <span class="token string">"prefetch"</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 property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/assets/**"</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see the most important part in this file is about caching mechanism and which files to cache for the application. We will go through these in details later.</p> <p>You will also have a flag set in your <code class="language-text">.angular-cli.json</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="29566873289673090000" data-toaster-class="gatsby-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;serviceWorker&quot;: true`, `29566873289673090000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"serviceWorker"</span><span class="token operator">:</span> <span class="token boolean">true</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>This flag will cause the production build to include a couple of extra files in the output dist folder:</p> <ul> <li>The Angular Service Worker file <code class="language-text">ngsw-worker.js</code></li> <li>The runtime configuration of the Angular Service Worker <code class="language-text">ngsw.json</code></li> </ul> <p>The last bit but also important is that it will add the <code class="language-text">ServiceWorkerModule</code> to your <code class="language-text">app.module.ts</code> file and configure it for production.</p> <div class="gatsby-code-button-container" data-toaster-id="64566397323964230000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@NgModule({ declarations: [AppComponent], imports: [ BrowserModule, AppRoutingModule, ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production, }), ], providers: [], bootstrap: [AppComponent], }) export class AppModule {}`, `64566397323964230000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> declarations<span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<span class="token punctuation">]</span><span class="token punctuation">,</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span> BrowserModule<span class="token punctuation">,</span> AppRoutingModule<span class="token punctuation">,</span> ServiceWorkerModule<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'/ngsw-worker.js'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> enabled<span class="token operator">:</span> environment<span class="token punctuation">.</span>production<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> providers<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> bootstrap<span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<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">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This module provides a couple of injectable services:</p> <ul> <li><code class="language-text">SwUpdate</code> for managing application version updates</li> <li><code class="language-text">SwPush</code> for doing server Web Push notifications You won’t need to know what is inside the service worker file itself and you cannot change that either (it will be overwritten by each build), but I recommend you have a look at <a href="https://github.com/angular/angular/tree/master/packages/service-worker/worker/src" target="_blank" rel="nofollow noopener noreferrer">the code</a> to understand some of the techniques which is used, interesting stuff.</li> </ul> <blockquote> <p>This file has its own HTTP request so that the browser would know which if there is a newer version of the service worker available.</p> </blockquote> <p>The Angular Service Worker is nothing but a javascript file subscribing to service worker life cycles and handling different stuff in there.</p> <h2 id="a-idhoodaunder-the-hood" style="position:relative;"><a href="#a-idhoodaunder-the-hood" aria-label="a idhoodaunder 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><a id="hood"></a>Under the hood</h2> <p>The Angular Service Worker can cache all sorts of files/content in the browser’s <a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage" target="_blank" rel="nofollow noopener noreferrer">Cache Storage</a>. It doesn’t use the normal caching mechanism which is used in the standard browsers called <code class="language-text">cache-control</code> so it can be used in conjunction with that.</p> <p>There were two sections in the  <code class="language-text">assetGroup</code> in configuration file’s, the <code class="language-text">app</code> and <code class="language-text">assets</code>. The former is used to let Angular Service Worker know what files need to be cached from application’s main files.</p> <p>This usually include <code class="language-text">index.html</code>, css files and main bundles. The assets section is used for anything that doesn’t need to be loaded at first like images and other assets which would be loaded later on demand.</p> <p>There were also two different install/update mode mentioned in the configuration, <code class="language-text">prefetch</code> and <code class="language-text">lazy</code>.</p> <p><strong>Prefetch</strong> means that the files are cached ahead of time and <strong><em>lazy</em></strong> is used for on demand caching, meaning they will be cached on their first usage.</p> <p>OK let’s build the application and have a look at what will be generated in the dist folder:</p> <div class="gatsby-code-button-container" data-toaster-id="66255906569090040000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng build --prod`, `66255906569090040000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng build <span class="token parameter variable">--prod</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>If you now open your dist folder you will see something similar to this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1016px; " > <a class="gatsby-resp-image-link" href="/static/54c1bc5923ebb74b7d31af0f3bdada4c/f4281/ngswpwadist.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 52.59259259259259%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAABXUlEQVR42n1RWW6DQBTjJCFhXwYGhmEWZoEE0t6gH73/QeoEqUppVcmyrAcPbL8gKVoj3WQXf3sn3RjnBBMgysglrf9HEMbVICwbDVde2at2N6FnMS2EinNSR1nzjUtKDghOGf2c3WoX6e7arky4OKdp2YOBpOiAKGt3jfkrgjBpBl4KJZVduXTGr2KaR+3BsABTAIQy17IZYBVxvgHbhPF8lCOXHjvaXmEem2C73O287dr4DcthXP7IjGB1W9KBc+WUWUblSSfSkhaEFaQvGzDLqq4kDC2ek+pQGGn7oudc6GUQBva6QeOl3/iz7Zqygktp/F1oP0iLP+PBYW3n6LB8TkhFsm7gk9+kWSrKk6LJ6x4+87qD2G2nFW16UVP+Gjs4RRXTjGutzG1UDsWaeUNDk1/BSDE9L4860CU+FL74D0Ice/1g7k2ox0lQeMc1/KM5RHjc7KnROeaHzF9/bXiGu/elIgAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="NGSW dist folder" title="" src="/static/54c1bc5923ebb74b7d31af0f3bdada4c/f4281/ngswpwadist.png" srcset="/static/54c1bc5923ebb74b7d31af0f3bdada4c/01bf6/ngswpwadist.png 270w, /static/54c1bc5923ebb74b7d31af0f3bdada4c/07484/ngswpwadist.png 540w, /static/54c1bc5923ebb74b7d31af0f3bdada4c/f4281/ngswpwadist.png 1016w" sizes="(max-width: 1016px) 100vw, 1016px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>We’ve talk’ed about the service worker itself, so let’s have a look at the <code class="language-text">ngsw.json</code> to see how ‘the template helped to generate this file.</p> <p>This is the <em>runtime</em> configuration file that the Angular Service Worker will use and is built based on the <code class="language-text">ngsw-config.json</code>.</p> <p>It contains all the information needed by the Angular Service Worker to know at runtime about which files it needs to cache, and when.</p> <div class="gatsby-code-button-container" data-toaster-id="64050146151682250000" data-toaster-class="gatsby-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;configVersion&quot;: 1, &quot;index&quot;: &quot;/index.html&quot;, &quot;assetGroups&quot;: [ { &quot;name&quot;: &quot;app&quot;, &quot;installMode&quot;: &quot;prefetch&quot;, &quot;updateMode&quot;: &quot;prefetch&quot;, &quot;urls&quot;: [ &quot;/favicon.ico&quot;, &quot;/index.html&quot;, &quot;/inline.5646543f86fbfdc19b11.bundle.js&quot;, &quot;/main.3bb4e08c826e33bb0fca.bundle.js&quot;, &quot;/polyfills.55440df0c9305462dd41.bundle.js&quot;, &quot;/styles.1862c2c45c11dc3dbcf3.bundle.css&quot; ], &quot;patterns&quot;: [] }, { &quot;name&quot;: &quot;assets&quot;, &quot;installMode&quot;: &quot;lazy&quot;, &quot;updateMode&quot;: &quot;prefetch&quot;, &quot;urls&quot;: [], &quot;patterns&quot;: [] } ], &quot;dataGroups&quot;: [], &quot;hashTable&quot;: { &quot;/inline.5646543f86fbfdc19b11.bundle.js&quot;: &quot;1028ce05cb8393bd53706064e3a8dc8f646c8039&quot;, &quot;/main.3bb4e08c826e33bb0fca.bundle.js&quot;: &quot;ae15cc3875440d0185b46b4b73bfa731961872e0&quot;, &quot;/polyfills.55440df0c9305462dd41.bundle.js&quot;: &quot;c3b13e2980f9515f4726fd2621440bd7068baa3b&quot;, &quot;/styles.1862c2c45c11dc3dbcf3.bundle.css&quot;: &quot;3318b88e1200c77a5ff691c03ca5d5682a19b196&quot;, &quot;/favicon.ico&quot;: &quot;84161b857f5c547e3699ddfbffc6d8d737542e01&quot;, &quot;/index.html&quot;: &quot;cfdca0ab1cec8379bbbf8ce4af2eaa295a3f3827&quot; } }`, `64050146151682250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"configVersion"</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"index"</span><span class="token operator">:</span> <span class="token string">"/index.html"</span><span class="token punctuation">,</span> <span class="token property">"assetGroups"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"app"</span><span class="token punctuation">,</span> <span class="token property">"installMode"</span><span class="token operator">:</span> <span class="token string">"prefetch"</span><span class="token punctuation">,</span> <span class="token property">"updateMode"</span><span class="token operator">:</span> <span class="token string">"prefetch"</span><span class="token punctuation">,</span> <span class="token property">"urls"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"/favicon.ico"</span><span class="token punctuation">,</span> <span class="token string">"/index.html"</span><span class="token punctuation">,</span> <span class="token string">"/inline.5646543f86fbfdc19b11.bundle.js"</span><span class="token punctuation">,</span> <span class="token string">"/main.3bb4e08c826e33bb0fca.bundle.js"</span><span class="token punctuation">,</span> <span class="token string">"/polyfills.55440df0c9305462dd41.bundle.js"</span><span class="token punctuation">,</span> <span class="token string">"/styles.1862c2c45c11dc3dbcf3.bundle.css"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"patterns"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"assets"</span><span class="token punctuation">,</span> <span class="token property">"installMode"</span><span class="token operator">:</span> <span class="token string">"lazy"</span><span class="token punctuation">,</span> <span class="token property">"updateMode"</span><span class="token operator">:</span> <span class="token string">"prefetch"</span><span class="token punctuation">,</span> <span class="token property">"urls"</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">"patterns"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"dataGroups"</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">"hashTable"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"/inline.5646543f86fbfdc19b11.bundle.js"</span><span class="token operator">:</span> <span class="token string">"1028ce05cb8393bd53706064e3a8dc8f646c8039"</span><span class="token punctuation">,</span> <span class="token property">"/main.3bb4e08c826e33bb0fca.bundle.js"</span><span class="token operator">:</span> <span class="token string">"ae15cc3875440d0185b46b4b73bfa731961872e0"</span><span class="token punctuation">,</span> <span class="token property">"/polyfills.55440df0c9305462dd41.bundle.js"</span><span class="token operator">:</span> <span class="token string">"c3b13e2980f9515f4726fd2621440bd7068baa3b"</span><span class="token punctuation">,</span> <span class="token property">"/styles.1862c2c45c11dc3dbcf3.bundle.css"</span><span class="token operator">:</span> <span class="token string">"3318b88e1200c77a5ff691c03ca5d5682a19b196"</span><span class="token punctuation">,</span> <span class="token property">"/favicon.ico"</span><span class="token operator">:</span> <span class="token string">"84161b857f5c547e3699ddfbffc6d8d737542e01"</span><span class="token punctuation">,</span> <span class="token property">"/index.html"</span><span class="token operator">:</span> <span class="token string">"cfdca0ab1cec8379bbbf8ce4af2eaa295a3f3827"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>First of all there is the assetGroup section which now contains all the required files with their bundle id’s included. Then you can see there is a hash table generated containing the file names and a hash value generated based on the name. This hash table is used for versioning purposes.</p> <p>Let’s say you update your main style file, what happens next is that it’s id will change. As a result the hash value will change and service worker knows then that it needs to be requested again instead of responding with the cached version.</p> <p>You might ask where that <code class="language-text">manifest.json</code> came from. That is not something that Angular generates, it is the application manifest that you should generate and put in your project and then reference it in your <code class="language-text">.angular-cli.json</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="50783068333779970000" data-toaster-class="gatsby-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;apps&quot;: [ { &quot;root&quot;: &quot;src&quot;, &quot;outDir&quot;: &quot;dist&quot;, &quot;assets&quot;: [ &quot;assets&quot;, &quot;favicon.ico&quot;, &quot;assets\\manifest.json&quot; ], } ... ]`, `50783068333779970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"apps"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"root"</span><span class="token operator">:</span> <span class="token string">"src"</span><span class="token punctuation">,</span> <span class="token property">"outDir"</span><span class="token operator">:</span> <span class="token string">"dist"</span><span class="token punctuation">,</span> <span class="token property">"assets"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"assets"</span><span class="token punctuation">,</span> <span class="token string">"favicon.ico"</span><span class="token punctuation">,</span> <span class="token string">"assets\\manifest.json"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> ... <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you want to run your application to see whether the service worker is registered or not, be mindful of the fact that you cannot do it in non prod mode and you will need a web server for it.</p> <p>You could use the CLI dev server but that is not also not recommended but also it won’t pass the security part of the audit step in lighthouse.</p> <p>The best and simplest option is to install the <a href="https://www.npmjs.com/package/http-server" target="_blank" rel="nofollow noopener noreferrer">http-server</a> and use that, but first we need to install it globally:</p> <div class="gatsby-code-button-container" data-toaster-id="3930737632398084600" data-toaster-class="gatsby-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 http-server`, `3930737632398084600`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> http-server</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now let’s then go into the <code class="language-text">dist</code> folder, and start the application in production mode:</p> <div class="gatsby-code-button-container" data-toaster-id="75037446992419520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`cd dist http-server -c-1 .`, `75037446992419520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token builtin class-name">cd</span> dist http-server -c-1 <span class="token builtin class-name">.</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>At this point the server will be initialised and serving from this folder as base, you can browse <u>_<a href="http://127.0.0.1:8080_" target="_blank" rel="nofollow noopener noreferrer">http://127.0.0.1:8080_</a></u> or <u>_<a href="http://localhost:8080_" target="_blank" rel="nofollow noopener noreferrer">http://localhost:8080_</a></u> to see your application and run the audit to see what else is remaining.</p> <p>If you open the developer tools, you should see the service worker registered for your application by going into application tab:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 682px; " > <a class="gatsby-resp-image-link" href="/static/7dd2c124e0f90017f7eb4d8683f9b197/160a3/ngsw.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsTAAALEwEAmpwYAAABhElEQVR42mWQy6rWMBSF+/4PIIoggmNn3gaKlwPHiYr8ovRvtbe0adKmubZJ2/Tibg8o6Mcigw0ra+8VlBWuCYUnywpcN2leVDXNcsRYV2HMeYcxJnVNW379iX7lREjV970xRggRNDjHKLVGbN6u87AvdvPDvjprh5oQ2sC/1WDtvu/Lui7rth46gEnw4Fn86MX1yZvs6S19+Kq6/7K897x8/BqbwRFCGGNKyo5zpdSRpxUESqUg+TC/+4Lef87efkpvvha339nNt/bDpf34g7lxgvB+6LdtB51R2x+OEZh5W2vJZteDlumv5nnuuo61LaW0rrH3a8NHrudWTMp40o2tGIMoisPwmqRALpVW2txpWY4bvfewrdaWMJeUphN2mpfBTW7yftmDoijCMIyiqEBIncfcAeb9XHQaR2lUiipUUgKl846xRkhuxyVIkuRyucRxDIbemH/MgITCBCcUw/KoRBUmLYcuBmmmoGkaaBXOA4PW+n+zP5lOnHPjOA9uPfvafwN3I/VWLmPFEwAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="NGSW" title="" src="/static/7dd2c124e0f90017f7eb4d8683f9b197/160a3/ngsw.png" srcset="/static/7dd2c124e0f90017f7eb4d8683f9b197/01bf6/ngsw.png 270w, /static/7dd2c124e0f90017f7eb4d8683f9b197/07484/ngsw.png 540w, /static/7dd2c124e0f90017f7eb4d8683f9b197/160a3/ngsw.png 682w" sizes="(max-width: 682px) 100vw, 682px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>You can see what fi’les have been cached so far by opening the cache section:’</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/9838f150120a2dc207e69fbe40ee94b2/098c1/ngswcache.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 49.62962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAABkElEQVR42o1Qa3ObMBDk//+XziS2P7bThzPuJNiTcdqMsbERIDBIIATiISAFuuTxPaubY/VYbu8M13UppeUHqqrKhOBXqiTXZdZrheiaAlkkEY+CXMQpv/I4SFhoeJ53OFi+7xdFAXFdVyHLVhuyemCL+3RxnyBWZrraZssNvV07N7/jL7+8xZ2z2FAjiiLGmBACSgVxVbFEfjXd25/WzY/Dcm0v7+yHU/6Hduun6zeTPJLq+2MAsn6KDEJIEARxHCulZttlmec5cT2HkPPFAXFdL5NymibGE58GXd+H18jzKbbG5XLZ7/d4+iae66uy0V3TdrVu62aOpu1fhkm3PU7AkHCLQwPdHo9HVMOo3vRKFegc/pumaYEOS+tWt4iua98JVmuEYQglZHVd47XWGpNDI5xzmckiU3mSiETKWOZcFoKn4KLMmMCkDMdx/j4/W5ZFXwEj+B1cTK8YgWEYh3H8N84ZG+Rhmr/DMNvebrdoe7fbgZimCQ7z0ydgpGl6Op1QH5Ozbft8PoOgi8+I/wPQEybpDecThwAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Cache" title="" src="/static/9838f150120a2dc207e69fbe40ee94b2/302a4/ngswcache.png" srcset="/static/9838f150120a2dc207e69fbe40ee94b2/01bf6/ngswcache.png 270w, /static/9838f150120a2dc207e69fbe40ee94b2/07484/ngswcache.png 540w, /static/9838f150120a2dc207e69fbe40ee94b2/302a4/ngswcache.png 1080w, /static/9838f150120a2dc207e69fbe40ee94b2/098c1/ngswcache.png 1578w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>The Angular Serv’ice Worker will start serving the application files the next time you load the ‘page. If you hit refresh, you will notice that the application starts much faster this time (note that the first time the service worker gets registered, so caching starts after that).</p> <h2 id="a-idotherresourceaextending-the-configuration-caching-other-resources" style="position:relative;"><a href="#a-idotherresourceaextending-the-configuration-caching-other-resources" aria-label="a idotherresourceaextending the configuration caching other resources permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a id="otherresource"></a>Extending the configuration, caching other resources</h2> <p>When you are adding Angular Service Worker to your existing application or when you have a more complex project calling web API endpoints to get data or maybe you are including some static resources from an <a href="https://en.wikipedia.org/wiki/Content_delivery_network" target="_blank" rel="nofollow noopener noreferrer">external CDN</a>.</p> <p>You can cache those items easily by extending the configuration file. If you remember from the snippet above, there was an empty section called <code class="language-text">dataGroups</code>.</p> <p>In this section you can easily add these kind of resources and set a whole bunch of caching configuration for them. So let’s see what is available.</p> <p>We start with fonts which are the most obvious case, this would also go in <code class="language-text">assetGroup</code> section. I’m using google fonts but this can be from anywhere. All you need to do is to add the <code class="language-text">urls</code> property in the assets with lazy install mode since you don’t want to slow down your application load time by loading the fonts first.</p> <div class="gatsby-code-button-container" data-toaster-id="37568231399260290000" data-toaster-class="gatsby-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;name&quot;: &quot;assets&quot;, &quot;installMode&quot;: &quot;lazy&quot;, &quot;updateMode&quot;: &quot;prefetch&quot;, &quot;resources&quot;: { &quot;files&quot;: [&quot;/assets/**&quot;], &quot;urls&quot;: [&quot;https://fonts.googleapis.com/**&quot;] } }`, `37568231399260290000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"assets"</span><span class="token punctuation">,</span> <span class="token property">"installMode"</span><span class="token operator">:</span> <span class="token string">"lazy"</span><span class="token punctuation">,</span> <span class="token property">"updateMode"</span><span class="token operator">:</span> <span class="token string">"prefetch"</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 property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/assets/**"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"urls"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"https://fonts.googleapis.com/**"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This makes sure that any font (using wildcard) requested from <u><strong>fonts.googleapis.com</strong></u> will get cached and served from there on future requests.</p> <p>In terms of APIs the <code class="language-text">dataGroup</code> comes to play. We will need to tell service worker which routes are to be used, the size of cached items, their life time in cache (expiry) and also time out if the network request fails.</p> <div class="gatsby-code-button-container" data-toaster-id="28118788069605237000" data-toaster-class="gatsby-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;dataGroups&quot;: [ { &quot;name&quot;: &quot;books-api&quot;, &quot;urls&quot;: [&quot;/books&quot;], &quot;cacheConfig&quot;: { &quot;strategy&quot;: &quot;freshness&quot;, &quot;maxSize&quot;: 20, &quot;maxAge&quot;: &quot;1h&quot;, &quot;timeout&quot;: &quot;5s&quot; } }, { &quot;name&quot;: &quot;book-api&quot;, &quot;urls&quot;: [&quot;/book/:id&quot;], &quot;cacheConfig&quot;: { &quot;strategy&quot;: &quot;performance&quot;, &quot;maxSize&quot;: 10, &quot;maxAge&quot;: &quot;1d&quot; } } ]`, `28118788069605237000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"dataGroups"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"books-api"</span><span class="token punctuation">,</span> <span class="token property">"urls"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/books"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"cacheConfig"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"strategy"</span><span class="token operator">:</span> <span class="token string">"freshness"</span><span class="token punctuation">,</span> <span class="token property">"maxSize"</span><span class="token operator">:</span> <span class="token number">20</span><span class="token punctuation">,</span> <span class="token property">"maxAge"</span><span class="token operator">:</span> <span class="token string">"1h"</span><span class="token punctuation">,</span> <span class="token property">"timeout"</span><span class="token operator">:</span> <span class="token string">"5s"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"book-api"</span><span class="token punctuation">,</span> <span class="token property">"urls"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/book/:id"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"cacheConfig"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"strategy"</span><span class="token operator">:</span> <span class="token string">"performance"</span><span class="token punctuation">,</span> <span class="token property">"maxSize"</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token property">"maxAge"</span><span class="token operator">:</span> <span class="token string">"1d"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The most important part of the above config is the strategy. There are currently two values available, <code class="language-text">freshness</code> and <code class="language-text">performance</code>. The first one is equal to <strong>network first</strong>, meaning the resource is requested from network first and if not available from cache.</p> <p>The second one is equal to <strong>cache first</strong> means it is returned from cache first and if it does not exist on cache it will be requested from network.</p> <p><strong>Max size</strong> determines for how many entries should be kept in cache, because we don’t want to take too much space in browser cache and cause problems. <strong>Max age</strong> is used to determine how long responses are allowed to remain in the cache before being considered invalid and evicted.</p> <p>You can have these suffixes:</p> <ul> <li><code class="language-text">d</code>: days</li> <li><code class="language-text">h</code>: hours</li> <li><code class="language-text">m</code>: minutes</li> <li><code class="language-text">s</code>: seconds</li> <li><code class="language-text">u</code>: milliseconds After configuring these options you can now try to set your app to offline in dev tools and see what happens. It does feel good to see the application working without a network connection, doesn’t it.</li> </ul> <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/1edcd115389080aac4faa53478eacd92/93df8/bookshelfpic.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 30%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAABCUlEQVR42k2QwUrEMBRF+6G6sqDouHBEEfEr3Lhw4a8MdqA7/QKhdgptpknTpEnT5E2r144OXsIjvHdPbpLo5CqJr5Oz2/XxYnV6sz6/Sx+f38qyYGwrRCNlI0TddZ21RmujtLHWOuf8rGhxn14+pPEyARkvX48uVk8v75/ZR1EUUkpgrneBKNBuFk3T9PWnqOFcSsNFZyz1bnTDVNcyz3POuTGGaAe3Ng4rhPAPnGFWbopNXm+ZlKJpuFISt8qyjDEG+Cds3BnTadW2Sg9h3GP7/Ehp3bZt3/ewzm+zSKiqSgihtQYL3zAMmGLkfRhnoUNEEXYYHypOQfIBxq/AhA5gVAq/Auy9/wYxVEgGeIPskgAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Bookshelf" title="" src="/static/1edcd115389080aac4faa53478eacd92/302a4/bookshelfpic.png" srcset="/static/1edcd115389080aac4faa53478eacd92/01bf6/bookshelfpic.png 270w, /static/1edcd115389080aac4faa53478eacd92/07484/bookshelfpic.png 540w, /static/1edcd115389080aac4faa53478eacd92/302a4/bookshelfpic.png 1080w, /static/1edcd115389080aac4faa53478eacd92/0d292/bookshelfpic.png 1620w, /static/1edcd115389080aac4faa53478eacd92/b3608/bookshelfpic.png 2160w, /static/1edcd115389080aac4faa53478eacd92/93df8/bookshelfpic.png 3292w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="a-idpushapush-notifications" style="position:relative;"><a href="#a-idpushapush-notifications" aria-label="a idpushapush notifications permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a id="push"></a>Push notification’s’</h2> <p>To me the most impressing feature coming with PWAs is the push notification. This somehow completes the native user experience alongside the <em>add to home screen</em> feature.</p> <p>The good news is that this is supported by default in Angular and you don’t need to put too much effort in getting it working. We will however need to follow some conventions to implement the functionality in our API (as its needed for this purpose).</p> <p>First thing we need to do is to subscribe to the notifications. We will need <code class="language-text">SwPush</code> from the Angular Service Worker to implement this:</p> <div class="gatsby-code-button-container" data-toaster-id="17713118091195267000" data-toaster-class="gatsby-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 { SwPush } from '@angular/service-worker'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; ... constructor(private swPush: SwPush, private http: HttpClient) {} VAPID_PUBLIC_KEY = 'your VAPID private key'; API_URL = 'the api endpoint which supports push notification'; subscribeToPush() { // Requesting messaging service to subscribe current client (browser) this.swPush.requestSubscription({ serverPublicKey: this.VAPID_PUBLIC_KEY }) .then(pushSubscription =&gt; { // Passing subscription object to our backend this.addSubscriber(pushSubscription) .subscribe( res =&gt; { console.log('[App] Add subscriber request answer', res); }, err =&gt; { console.log('[App] Add subscriber request failed', err); }) }) .catch(err =&gt; { ... }) } addSubscriber(subscription) { const url = \`\${this.API_URL}\`; console.log('[Push Service] Adding subscriber') let body = { action: 'subscribing to the push endpoint', subscription: subscription } return this.http .post(url, body) .catch(this.handleError); } private handleError(error: Response | any) { let errMsg: string; if (error instanceof Response) { errMsg = \`\${error.statusText || 'Network error'}\`; } else { errMsg = error.message ? error.message : error.toString(); } return Observable.throw(errMsg); }`, `17713118091195267000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> SwPush <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/service-worker'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> HttpClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/common/http'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Observable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs/Observable'</span><span class="token punctuation">;</span> <span class="token operator">...</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> swPush<span class="token operator">:</span> SwPush<span class="token punctuation">,</span> <span class="token keyword">private</span> http<span class="token operator">:</span> HttpClient<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token constant">VAPID_PUBLIC_KEY</span> <span class="token operator">=</span> <span class="token string">'your VAPID private key'</span><span class="token punctuation">;</span> <span class="token constant">API_URL</span> <span class="token operator">=</span> <span class="token string">'the api endpoint which supports push notification'</span><span class="token punctuation">;</span> <span class="token function">subscribeToPush</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Requesting messaging service to subscribe current client (browser)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>swPush<span class="token punctuation">.</span><span class="token function">requestSubscription</span><span class="token punctuation">(</span><span class="token punctuation">{</span> serverPublicKey<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token constant">VAPID_PUBLIC_KEY</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>pushSubscription <span class="token operator">=</span><span class="token operator">&amp;</span>gt<span class="token punctuation">;</span> <span class="token punctuation">{</span> <span class="token comment">// Passing subscription object to our backend</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addSubscriber</span><span class="token punctuation">(</span>pushSubscription<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span> res <span class="token operator">=</span><span class="token operator">&amp;</span>gt<span class="token punctuation">;</span> <span class="token punctuation">{</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'[App] Add subscriber request answer'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> err <span class="token operator">=</span><span class="token operator">&amp;</span>gt<span class="token punctuation">;</span> <span class="token punctuation">{</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'[App] Add subscriber request failed'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span>err <span class="token operator">=</span><span class="token operator">&amp;</span>gt<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 function">addSubscriber</span><span class="token punctuation">(</span>subscription<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token constant">API_URL</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 builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'[Push Service] Adding subscriber'</span><span class="token punctuation">)</span> <span class="token keyword">let</span> body <span class="token operator">=</span> <span class="token punctuation">{</span> action<span class="token operator">:</span> <span class="token string">'subscribing to the push endpoint'</span><span class="token punctuation">,</span> subscription<span class="token operator">:</span> subscription <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>http <span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> body<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>handleError<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token function">handleError</span><span class="token punctuation">(</span>error<span class="token operator">:</span> Response <span class="token operator">|</span> <span class="token builtin">any</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> errMsg<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>error <span class="token keyword">instanceof</span> <span class="token class-name">Response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> errMsg <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>error<span class="token punctuation">.</span>statusText <span class="token operator">||</span> <span class="token string">'Network error'</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 keyword">else</span> <span class="token punctuation">{</span> errMsg <span class="token operator">=</span> error<span class="token punctuation">.</span>message <span class="token operator">?</span> error<span class="token punctuation">.</span>message <span class="token operator">:</span> error<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 keyword">return</span> Observable<span class="token punctuation">.</span><span class="token function">throw</span><span class="token punctuation">(</span>errMsg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Let me break this down and explain it step by step.</p> <p>The first step is to subscribe to your web push endpoint (this is not your back-end server) which is responsible for sending push notifications. This is like establishing a connection with a server and keeping that open so they can send us the notifications later through that (of course this was just an example and not reality).</p> <p>To do this we need to have a valid <a href="https://tools.ietf.org/html/draft-thomson-webpush-vapid-02" target="_blank" rel="nofollow noopener noreferrer">Voluntary Application Server Identification</a> (VAPID) public key from our sever which <code class="language-text">ngsw</code> will use to subscribe to the push endpoint. If you are wondering about these concepts and don’t have enough background refer to <a href="https://tools.ietf.org/html/draft-ietf-webpush-protocol" target="_blank" rel="nofollow noopener noreferrer">Web Push Protocol</a> specifications.</p> <p>In short the whole process looks like this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 638px; " > <a class="gatsby-resp-image-link" href="/static/4474adbfe08bef3a017ae6d85efad1e6/8608d/webpush.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3QUD/8QAFRABAQAAAAAAAAAAAAAAAAAAARD/2gAIAQEAAQUCb//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABYQAQEBAAAAAAAAAAAAAAAAAAABIf/aAAgBAQABPyE2I//aAAwDAQACAAMAAAAQ8A//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAgMAAAAAAAAAAAAAAAABABEhMUH/2gAIAQEAAT8QDzFvJoAC3NE0n//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="WebPush" title="" src="/static/4474adbfe08bef3a017ae6d85efad1e6/8608d/webpush.jpg" srcset="/static/4474adbfe08bef3a017ae6d85efad1e6/6f81f/webpush.jpg 270w, /static/4474adbfe08bef3a017ae6d85efad1e6/09d21/webpush.jpg 540w, /static/4474adbfe08bef3a017ae6d85efad1e6/8608d/webpush.jpg 638w" sizes="(max-width: 638px) 100vw, 638px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>As soon as you subscribe, you will start getting notifications. At this point I haven’t implemented the push notification in the demo application, but I will add it in my next blog post.</p> <h4 id="considerations-with-push-notifications-using-ngsw" style="position:relative;"><a href="#considerations-with-push-notifications-using-ngsw" aria-label="considerations with push notifications using ngsw permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Considerations with push notifications using ngsw</h4> <ul> <li>You nee to send notification data straight away with the send notification request as payload (NGSW can’t request this payload later, which is possible in general).</li> <li>You have to send this data object in the <code class="language-text">notification</code> property of the payload.</li> </ul> <p>A normal payload structure will look like:</p> <div class="gatsby-code-button-container" data-toaster-id="8452600194299342000" data-toaster-class="gatsby-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;notification&quot;: { &quot;title&quot;: &quot;The push notification title&quot;, &quot;actions&quot;: [ { &quot;action&quot;: &quot;actionOne&quot;, &quot;title&quot;: &quot;Action One&quot; } ], &quot;body&quot;: &quot;The is the body which will be shown on notification&quot;, &quot;dir&quot;: &quot;auto&quot;, &quot;icon&quot;: &quot;path to icon&quot;, &quot;badge&quot;: &quot;path to badge&quot;, &quot;lang&quot;: &quot;en&quot;, &quot;renotify&quot;: true, &quot;requireInteraction&quot;: true, &quot;tag&quot;: 926796012340920300, &quot;vibrate&quot;: [300, 100, 400], &quot;data&quot;: { // this object can contain arbitrary info } } }`, `8452600194299342000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"notification"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"The push notification title"</span><span class="token punctuation">,</span> <span class="token property">"actions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"action"</span><span class="token operator">:</span> <span class="token string">"actionOne"</span><span class="token punctuation">,</span> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Action One"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"body"</span><span class="token operator">:</span> <span class="token string">"The is the body which will be shown on notification"</span><span class="token punctuation">,</span> <span class="token property">"dir"</span><span class="token operator">:</span> <span class="token string">"auto"</span><span class="token punctuation">,</span> <span class="token property">"icon"</span><span class="token operator">:</span> <span class="token string">"path to icon"</span><span class="token punctuation">,</span> <span class="token property">"badge"</span><span class="token operator">:</span> <span class="token string">"path to badge"</span><span class="token punctuation">,</span> <span class="token property">"lang"</span><span class="token operator">:</span> <span class="token string">"en"</span><span class="token punctuation">,</span> <span class="token property">"renotify"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token property">"requireInteraction"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token property">"tag"</span><span class="token operator">:</span> <span class="token number">926796012340920300</span><span class="token punctuation">,</span> <span class="token property">"vibrate"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">300</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">400</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// this object can contain arbitrary info</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Hope this article has helped you to get started with PWAs using Angular. Don’t forget to spread the love fellas.</p><![CDATA[Making multi language Angular applications using ngx-translate]]>https://yashints.dev/blog/2018/01/17/multi-language-angular-applicationshttps://yashints.dev/blog/2018/01/17/multi-language-angular-applicationsWed, 17 Jan 2018 00:00:00 GMT<p>Are you working on an international product where you need to support multiple languages? Is your application written in Angular? Then this article might help you to get it done easier than ever.</p> <!--more--> <p>We will use a small application since the purpose here is to show you how easy you can another language to your application. So let’s get started.</p> <p>Full source code of this example is available on <a href="https://github.com/yashints/ngx-translate" target="_blank" rel="nofollow noopener noreferrer">this GitHub repo</a>.</p> <h2 id="prerequisites" style="position:relative;"><a href="#prerequisites" aria-label="prerequisites permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prerequisites</h2> <p>You will need to have node, npm and <a href="https://github.com/angular/angular-cli" target="_blank" rel="nofollow noopener noreferrer">Angular CLI</a> installed before going further.</p> <h2 id="creating-the-application" style="position:relative;"><a href="#creating-the-application" aria-label="creating 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>Creating the application</h2> <p>Let’s start by creating a new application using <a href="https://github.com/angular/angular-cli" target="_blank" rel="nofollow noopener noreferrer">Angular CLI</a>:</p> <div class="gatsby-code-button-container" data-toaster-id="98166814886906720000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng new demo --skip-install`, `98166814886906720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng new demo --skip-install</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>We use <code class="language-text">--skip-install</code> flag to prevent installing the node modules as we intend to add <strong>ngx-translate</strong> to our <code class="language-text">package.json</code> shortly.</p> <p>Let’s do that next:</p> <div class="gatsby-code-button-container" data-toaster-id="1513601744785453300" data-toaster-class="gatsby-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 @ngx-translate/core @ngx-translate/http-loader --save`, `1513601744785453300`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @ngx-translate/core @ngx-translate/http-loader <span class="token parameter variable">--save</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>I added the <code class="language-text">http-loader</code> just because I’ve created some <code class="language-text">json</code> files containing the translations which I want to fetch. This simulates some real time translation such as using a <em>RESTful</em> translation service.</p> <p>You will get some warnings from <code class="language-text">npm</code> but don’t worry, go ahead and run <code class="language-text">npm install</code> to install all the required packages for the application.</p> <h2 id="importing-the-translation-module" style="position:relative;"><a href="#importing-the-translation-module" aria-label="importing the translation module permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Importing the translation module</h2> <p>Let’s open up our <code class="language-text">app.module.ts</code> and import the <code class="language-text">TranslateModule</code>.</p> <p>This module requires a loader which is the <code class="language-text">TranslationHttpLoader</code> we added earlier. But before doing so we need a way to create it since it has a dependency on <code class="language-text">HttpClient</code>.</p> <p>There are multiple ways to achieve this, but we use a factory method just because you will need and exported function for <a href="https://angular.io/docs/ts/latest/cookbook/aot-compiler.html" target="_blank" rel="nofollow noopener noreferrer">AoT compilation</a> or if you are using <a href="http://ionic.io/" target="_blank" rel="nofollow noopener noreferrer">Ionic</a>:</p> <div class="gatsby-code-button-container" data-toaster-id="21898588566983344000" data-toaster-class="gatsby-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 { HttpClientModule, HttpClient } from '@angular/common/http'; import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; export function translateHttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http); } @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: translateHttpLoaderFactory, deps: [HttpClient] } }) ], providers: [], bootstrap: [AppComponent] })`, `21898588566983344000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> HttpClientModule<span class="token punctuation">,</span> HttpClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/common/http'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> TranslateModule<span class="token punctuation">,</span> TranslateLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@ngx-translate/core'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> TranslateHttpLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@ngx-translate/http-loader'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">translateHttpLoaderFactory</span><span class="token punctuation">(</span>http<span class="token operator">:</span> HttpClient<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">TranslateHttpLoader</span><span class="token punctuation">(</span>http<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> declarations<span class="token operator">:</span> <span class="token punctuation">[</span> AppComponent <span class="token punctuation">]</span><span class="token punctuation">,</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span> BrowserModule<span class="token punctuation">,</span> HttpClientModule<span class="token punctuation">,</span> TranslateModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span><span class="token punctuation">{</span> loader<span class="token operator">:</span> <span class="token punctuation">{</span> provide<span class="token operator">:</span> TranslateLoader<span class="token punctuation">,</span> useFactory<span class="token operator">:</span> translateHttpLoaderFactory<span class="token punctuation">,</span> deps<span class="token operator">:</span> <span class="token punctuation">[</span>HttpClient<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> providers<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> bootstrap<span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The loader can load the translation files using <code class="language-text">http</code>.</p> <h2 id="adding-the-translation-service" style="position:relative;"><a href="#adding-the-translation-service" aria-label="adding the translation service permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Adding the translation service</h2> <p>OK, we need the <code class="language-text">TranslateService</code> to be able to make our template multi-lingual. Also we need to add our translation files for different languages we want to use.</p> <p>First let’s import the service. Open your <code class="language-text">app.component.ts</code> and insert this line on top:</p> <div class="gatsby-code-button-container" data-toaster-id="82690547796766750000" data-toaster-class="gatsby-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 { TranslateService } from '@ngx-translate/core'`, `82690547796766750000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> TranslateService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@ngx-translate/core'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now we need to define our default language, which we will do inside the constructor:</p> <div class="gatsby-code-button-container" data-toaster-id="18338534482839597000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`constructor(private translateService: TranslateService) { translateService.setDefaultLang('en'); }`, `18338534482839597000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> translateService<span class="token operator">:</span> TranslateService<span class="token punctuation">)</span> <span class="token punctuation">{</span> translateService<span class="token punctuation">.</span><span class="token function">setDefaultLang</span><span class="token punctuation">(</span><span class="token string">'en'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>I’ll use two languages here but the process is the same and adding a third one as simple as adding a file containing the translated text. These files would be put into <code class="language-text">assets/i18n</code> folder.</p> <p>First English file in <code class="language-text">src/assets/i18n/en.json</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="23815199812404896000" data-toaster-class="gatsby-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;Title&quot;: &quot;Translation demo&quot;, &quot;WelcomeMessage&quot;: &quot;Welcome to the international demo application&quot; }`, `23815199812404896000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"Title"</span><span class="token operator">:</span> <span class="token string">"Translation demo"</span><span class="token punctuation">,</span> <span class="token property">"WelcomeMessage"</span><span class="token operator">:</span> <span class="token string">"Welcome to the international demo application"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And Spanish in <code class="language-text">src/assets/i18n/es.json</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="80457793175634660000" data-toaster-class="gatsby-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;Title&quot;: &quot;Demo de traducción&quot;, &quot;WelcomeMessage&quot;: &quot;Bienvenido a la aplicación de demostración internacional&quot; }`, `80457793175634660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"Title"</span><span class="token operator">:</span> <span class="token string">"Demo de traducción"</span><span class="token punctuation">,</span> <span class="token property">"WelcomeMessage"</span><span class="token operator">:</span> <span class="token string">"Bienvenido a la aplicación de demostración internacional"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>These files will be loaded using our translation loader that we added to the translation module. Now we can go ahead and create our template. We use the translate directive to tell the translate service which part of the template should be replaced.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> If you use the translate pipe, it expects nothing but the variable name inside the tag, so if you add other text it won’t pick it up.</div></div> <div class="gatsby-code-button-container" data-toaster-id="27310391743422624000" data-toaster-class="gatsby-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 translate>Title</h1> <div translate>WelcomeMessage</div>`, `27310391743422624000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">translate</span><span class="token punctuation">></span></span>Title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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">translate</span><span class="token punctuation">></span></span>WelcomeMessage<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>There is nothing fancy in there, just using the variables in those <code class="language-text">json</code> files and adding the translate attribute so that Angular know how these should be fetched using translation loader.</p> <p>We need one more thing to setup and that is our language switcher. Let’s for now keep it simple and add two buttons there which will call a function to switch between these languages, your final template would be something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="71310451562148590000" data-toaster-class="gatsby-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 style=&quot;text-align:center&quot;> <h1 translate>Title</h1> <h6 translate>WelcomeMessage</h6> <button (click)=&quot;switchLanguage('en')&quot;>English</button> <button (click)=&quot;switchLanguage('es')&quot;>Spanish</button> </div>`, `71310451562148590000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">text-align</span><span class="token punctuation">:</span>center</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">translate</span><span class="token punctuation">></span></span>Title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h6</span> <span class="token attr-name">translate</span><span class="token punctuation">></span></span>WelcomeMessage<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h6</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">(click)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>switchLanguage('en')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>English<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>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>switchLanguage('es')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Spanish<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>and now defining the <code class="language-text">switchLanguage</code> method:</p> <div class="gatsby-code-button-container" data-toaster-id="21756002532195140000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`switchLanguage(language: string) { this.translateService.use(language); }`, `21756002532195140000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token function">switchLanguage</span><span class="token punctuation">(</span>language<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>translateService<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>language<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Remember that we injected our service into the constructor.</p> <h2 id="first-test" style="position:relative;"><a href="#first-test" aria-label="first test permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 test</h2> <p>Let’s run the app and see what happens, just type <code class="language-text">ng serve</code> and open up <code class="language-text">http://localhost:4200</code> in the browser. You will see the home page:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 865px; " > <a class="gatsby-resp-image-link" href="/static/f8826a1accec2cb4b025a3a9d055864b/79e48/en.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.074074074074076%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA+klEQVR42pVRy2qDQBT1/78lRRQUXGgKiuKIuHDlwncsCC50xgfGR3oa2yS0s+lZ3Pe5czkj3O5Y13VZlts/Iez7DhdFkWEYQRC4rhuGoa7rlmVpmub7fhzHKDqOg9i27bIsMX+wvsl1XaMHjiiK2KIoCgJZliVJAtM0TSxSVfV0esPqJ/lxw5Fz8dp6jZ/k6nLJsqwCPqqiyIuiRJrneZqlqKRpmiQJmuu2ccjTOHZdxyibprHvWd/3lNIvz9gwDE3TtG3LGOO/fGDbNnBo18HM8xXT9A58B0ftX/k8z8Tz3o0zIQRH2rYDhYlHcMhfXQSuNg/7M8zX8hMFV/l3zp9T9QAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="English" title="" src="/static/f8826a1accec2cb4b025a3a9d055864b/79e48/en.png" srcset="/static/f8826a1accec2cb4b025a3a9d055864b/01bf6/en.png 270w, /static/f8826a1accec2cb4b025a3a9d055864b/07484/en.png 540w, /static/f8826a1accec2cb4b025a3a9d055864b/79e48/en.png 865w" sizes="(max-width: 865px) 100vw, 865px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>If you click on Spanish button the page will change to this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 854px; " > <a class="gatsby-resp-image-link" href="/static/593826fc175055424fad4f88ae647220/c3fd4/es.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 42.22222222222223%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAA+0lEQVR42p2QO2+DMBSF8/9HVgYeEmJHYmJAajE/ACUsDIiYNyIYBxGQiOkpkC5Nl34S9sHX53IPp3Vdx3EkhFBKi6Ioy3IYhiiK8jyv6xqvbdsGQVBVVd/3SZKEYYjzZVlgPOFhjOm6bpqmoiiyLBPPMwzDtm3XdbGiJEkSSo7jWJalqqqmaWh0mP/NYWYbXddxfkfX9nbrGOu/2Ve+X+Ccd6xDrsMstg2RrhsIWeQ5sqVpCo3kV0ozkGeoZmmKUtM0sAgh3oz93BDi+RKH+nNs8QI6juNP8OFRml7OZ0J8n/gYZO/7c+39D5vn+b4xTdPjMSInNA5/f/kLKei7dh5z5rMAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Spanish" title="" src="/static/593826fc175055424fad4f88ae647220/c3fd4/es.png" srcset="/static/593826fc175055424fad4f88ae647220/01bf6/es.png 270w, /static/593826fc175055424fad4f88ae647220/07484/es.png 540w, /static/593826fc175055424fad4f88ae647220/c3fd4/es.png 854w" sizes="(max-width: 854px) 100vw, 854px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Let’s go ahead and change the button texts as well. This time we use inline template with the <code class="language-text">translate</code> pipe. First we add the two labels to the <code class="language-text">json</code> files.</p> <p>For English:</p> <div class="gatsby-code-button-container" data-toaster-id="22527607930526060000" data-toaster-class="gatsby-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;Title&quot;: &quot;Translation demo&quot;, &quot;WelcomeMessage&quot;: &quot;Welcome to the international demo application&quot;, &quot;English&quot;: &quot;English&quot;, &quot;Spanish&quot;: &quot;Spanish&quot; }`, `22527607930526060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"Title"</span><span class="token operator">:</span> <span class="token string">"Translation demo"</span><span class="token punctuation">,</span> <span class="token property">"WelcomeMessage"</span><span class="token operator">:</span> <span class="token string">"Welcome to the international demo application"</span><span class="token punctuation">,</span> <span class="token property">"English"</span><span class="token operator">:</span> <span class="token string">"English"</span><span class="token punctuation">,</span> <span class="token property">"Spanish"</span><span class="token operator">:</span> <span class="token string">"Spanish"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And for Spanish:</p> <div class="gatsby-code-button-container" data-toaster-id="15687693943735103000" data-toaster-class="gatsby-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;Title&quot;: &quot;Demo de traducción&quot;, &quot;WelcomeMessage&quot;: &quot;Bienvenido a la aplicación de demostración internacional&quot;, &quot;English&quot;: &quot;Inglés&quot;, &quot;Spanish&quot;: &quot;Español&quot; }`, `15687693943735103000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"Title"</span><span class="token operator">:</span> <span class="token string">"Demo de traducción"</span><span class="token punctuation">,</span> <span class="token property">"WelcomeMessage"</span><span class="token operator">:</span> <span class="token string">"Bienvenido a la aplicación de demostración internacional"</span><span class="token punctuation">,</span> <span class="token property">"English"</span><span class="token operator">:</span> <span class="token string">"Inglés"</span><span class="token punctuation">,</span> <span class="token property">"Spanish"</span><span class="token operator">:</span> <span class="token string">"Español"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Finally we change the buttons in the template to use these labels:</p> <div class="gatsby-code-button-container" data-toaster-id="61029273911579840000" data-toaster-class="gatsby-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 (click)=&quot;switchLanguage('en')&quot;>{{ 'English' | translate }}</button> <button (click)=&quot;switchLanguage('es')&quot;>{{ 'Spanish' | translate }}</button>`, `61029273911579840000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">(click)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>switchLanguage('en')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{ 'English' | translate }}<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>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>switchLanguage('es')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{ 'Spanish' | translate }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Now the application should have hot reloaded and you should see the first picture. But if you click on Spanish you should see the buttons change:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 726px; " > <a class="gatsby-resp-image-link" href="/static/da1cd5f5475e2aeb109f9c30e6cb1349/f8067/es-1.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsTAAALEwEAmpwYAAABSUlEQVR42qVRzWvCMBztny7zKIhXL54EYeLBk+BtdGwMdK60xWrtt0kTk1VnRSliutc5xmBslwXyeL+v93skmuu6QoiyLM/n8+VyATkcDlJKkNPpVBQFSJqmqCqlgChlWQaCvNZut5vN5mg0ArZaLdM0wes3ddu2B4PBcDjs9Xq1Wg3Yv+2Px+Nut9toNDqdDiS0MAyDIPB9D2OGYUB4vV7PZjPUQOI4Rt6yrMViMZ/PoyjyPA+h4zjH41Er/3E0KYTv+5RSOBBSUkKjMCTAKEoZSxKsry6hNEkSGCGEgHDOq+F8v8d7wC1j6W6345yhFTUk4XwDxhlQSMGvZ8MhmmWv1fAfrpQq1ZX8ZvujSX3hdps9T6e6ri9XgRfLO/3p/nGiP0zsFfsUVJXYtVn7tqeK8zzHz+OFCU3p5u3FXBqWazlBlG5/bn4HrNvpJNIVpasAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Spanish" title="" src="/static/da1cd5f5475e2aeb109f9c30e6cb1349/f8067/es-1.png" srcset="/static/da1cd5f5475e2aeb109f9c30e6cb1349/01bf6/es-1.png 270w, /static/da1cd5f5475e2aeb109f9c30e6cb1349/07484/es-1.png 540w, /static/da1cd5f5475e2aeb109f9c30e6cb1349/f8067/es-1.png 726w" sizes="(max-width: 726px) 100vw, 726px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="passing-variables-to-translate-service" style="position:relative;"><a href="#passing-variables-to-translate-service" aria-label="passing variables to translate service permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Passing variables to translate service</h2> <p>You can pass your component variables to the translate pipe to be able to format your strings in those <code class="language-text">json</code> files. The simplest form is to show the welcome message for the user by having his/her name in the message.</p> <p>We will first change our <code class="language-text">json</code> files to have the user name in the message:</p> <div class="gatsby-code-button-container" data-toaster-id="63115848113184330000" data-toaster-class="gatsby-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;Title&quot;: &quot;Translation demo&quot;, &quot;WelcomeMessage&quot;: &quot;Dear {{name}}, welcome to the international demo application&quot;, &quot;English&quot;: &quot;English&quot;, &quot;Spanish&quot;: &quot;Spanish&quot; }`, `63115848113184330000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"Title"</span><span class="token operator">:</span> <span class="token string">"Translation demo"</span><span class="token punctuation">,</span> <span class="token property">"WelcomeMessage"</span><span class="token operator">:</span> <span class="token string">"Dear {{name}}, welcome to the international demo application"</span><span class="token punctuation">,</span> <span class="token property">"English"</span><span class="token operator">:</span> <span class="token string">"English"</span><span class="token punctuation">,</span> <span class="token property">"Spanish"</span><span class="token operator">:</span> <span class="token string">"Spanish"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And for Spanish:</p> <div class="gatsby-code-button-container" data-toaster-id="36720805041654383000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// Line break for readability { &quot;Title&quot;: &quot;Demo de traducción&quot;, &quot;WelcomeMessage&quot;: &quot;Querido {{name}}, bienvenido a la aplicación de demostración internacional&quot;, &quot;English&quot;: &quot;Inglés&quot;, &quot;Spanish&quot;: &quot;Español&quot; }`, `36720805041654383000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token comment">// Line break for readability</span> <span class="token punctuation">{</span> <span class="token property">"Title"</span><span class="token operator">:</span> <span class="token string">"Demo de traducción"</span><span class="token punctuation">,</span> <span class="token property">"WelcomeMessage"</span><span class="token operator">:</span> "Querido <span class="token punctuation">{</span><span class="token punctuation">{</span>name<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">,</span> bienvenido a la aplicación de demostración internacional"<span class="token punctuation">,</span> <span class="token property">"English"</span><span class="token operator">:</span> <span class="token string">"Inglés"</span><span class="token punctuation">,</span> <span class="token property">"Spanish"</span><span class="token operator">:</span> <span class="token string">"Español"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now let’s define the user in our <code class="language-text">app.component.ts</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="59330468272751970000" data-toaster-class="gatsby-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 user: any = { name: Yaser, }`, `59330468272751970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">let</span> user<span class="token operator">:</span> <span class="token builtin">any</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> Yaser<span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Finally, we need to pass this to the pipe:</p> <div class="gatsby-code-button-container" data-toaster-id="64917104683262110000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<h6>{{ 'WelcomeMessage' | translate: user }}</h6>`, `64917104683262110000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h6</span><span class="token punctuation">></span></span>{{ 'WelcomeMessage' | translate: user }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h6</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now you should be able to see the my name in the welcome message.</p> <h2 id="custom-loaders" style="position:relative;"><a href="#custom-loaders" aria-label="custom loaders permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Custom loaders</h2> <p>You can even write your own loaders and use a third party service for translation. It is very easy to do that, in fact all you need to do is to create a class which extends the TranslateLoader and then add a method called <code class="language-text">getTranslation</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="43771699157675155000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class CustomLoader implements TranslateLoader { getTranslation(lang: string): Observable<any> { return Observable.of({ KEY: 'value' }) } }`, `43771699157675155000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">class</span> <span class="token class-name">CustomLoader</span> <span class="token keyword">implements</span> <span class="token class-name">TranslateLoader</span> <span class="token punctuation">{</span> <span class="token function">getTranslation</span><span class="token punctuation">(</span>lang<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Observable<span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token constant">KEY</span><span class="token operator">:</span> <span class="token string">'value'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now you can use this instead of that factory method we created earlier in your <code class="language-text">app.module.ts</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="24312673882340995000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@NgModule({ imports: [ BrowserModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: CustomLoader }, }), ], bootstrap: [AppComponent], }) export class AppModule {}`, `24312673882340995000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> imports<span class="token operator">:</span> <span class="token punctuation">[</span> BrowserModule<span class="token punctuation">,</span> TranslateModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span><span class="token punctuation">{</span> loader<span class="token operator">:</span> <span class="token punctuation">{</span> provide<span class="token operator">:</span> TranslateLoader<span class="token punctuation">,</span> useClass<span class="token operator">:</span> CustomLoader <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> bootstrap<span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<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">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Hope this article has helped you to get started with the <code class="language-text">ngx-traslate</code> package. For more information you can refer to <a href="https://github.com/ngx-translate/core" target="_blank" rel="nofollow noopener noreferrer">their official documentation</a>.</p> <h2 id="more-goodies" style="position:relative;"><a href="#more-goodies" aria-label="more goodies permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 goodies</h2> <p>Based on one of the comments I got from <strong><em>Andreas Löw</em></strong> from <strong><em>CodeAndWeb GmbH</em></strong>, just wanted to introduce some tools you can use alongside <code class="language-text">ngx-translate</code> which makes your day perfect.</p> <h3 id="a-pluralisation-plugin" style="position:relative;"><a href="#a-pluralisation-plugin" aria-label="a pluralisation plugin permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>A pluralisation plugin</h3> <p>First one is an npm package called <a href="https://www.npmjs.com/package/ngx-translate-messageformat-compiler" target="_blank" rel="nofollow noopener noreferrer">ngx-translate-messageformat-compiler</a> which allows you to compile translations using <em>ICU syntax</em> for handling pluralization and gender.</p> <p><a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" rel="nofollow noopener noreferrer">ICU Message Format</a> is a standardized syntax for dealing with the translation of user-visible strings into various languages that may have different requirements for the correct declension of words (e.g. according to number, gender, case) - or to simplify: pluralization.</p> <p>The complete guide can be found in their <a href="https://github.com/lephyrus/ngx-translate-messageformat-compiler" target="_blank" rel="nofollow noopener noreferrer">Github repository</a> but to quickly show you how it can help you (I will skip the setup part as you can find it in the <a href="https://github.com/yashints/ngx-translate-tools" target="_blank" rel="nofollow noopener noreferrer">code repository on my GitHub</a>).</p> <p>Imagine you want to show a list of different categories of cats with their count on your web site which presumably helps a pet shop to show case what their current inventory is. here is how HTML will look like:</p> <div class="gatsby-code-button-container" data-toaster-id="43504120475937210000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<ul> <li *ngFor=&quot;let cat of cats&quot;> <span translate [translateParams]=&quot;{ Count: cat.count, category: cat.category }&quot; >CATS</span >. </li> </ul>`, `43504120475937210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">*ngFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>let cat of cats<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">translate</span> <span class="token attr-name">[translateParams]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{ Count: cat.count, category: cat.category }<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span>CATS<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>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In your component you will have a list of cats categories and their count:</p> <div class="gatsby-code-button-container" data-toaster-id="35882843041206880000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`cats = [ { count: 1, category: 'Aegean', }, { count: 0, category: 'American', }, { count: 4, category: 'Lykoi', }, ]`, `35882843041206880000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript">cats <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> count<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> category<span class="token operator">:</span> <span class="token string">'Aegean'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> count<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> category<span class="token operator">:</span> <span class="token string">'American'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> count<span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span> category<span class="token operator">:</span> <span class="token string">'Lykoi'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And finally in your <code class="language-text">json</code> file:</p> <div class="gatsby-code-button-container" data-toaster-id="26691751966129738000" data-toaster-class="gatsby-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;CATS&quot;: &quot;There {Count, plural, =0{are no {category} cats} one{is one {category} cat} other{are # {category} cats}}&quot; }`, `26691751966129738000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"CATS"</span><span class="token operator">:</span> <span class="token string">"There {Count, plural, =0{are no {category} cats} one{is one {category} cat} other{are # {category} cats}}"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>No when you run your app you will see the list like this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 377px; " > <a class="gatsby-resp-image-link" href="/static/244fb886a3241eb8da285fece416b53a/6146e/cats.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 35.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA9UlEQVR42n2QW1PDIBCF8///lW1a02AmF9KSG5CEADWkU1/UsQOp2wedqhm/B2aHPXuWg/e43bRddzpNSkml1AHvx9FIKRlj5/ML52yQuuU0ihPQHLWmjOY5jsJQKu3563WIwq5rsywhpIxQRIqCHPZJmoIFQjuck12wWfm+EKIqS4SegmDrP6yKsvKuf7DWXj4uzs3OQWmddTdupZ3n+V7puS+gASdcmdHkWcZ51/eiqeu6quIkbWjDGH19ewfB98TCZimGOM4445RCcIoxhjhgwho6TdOPzdclRC9422utjDHgJQf4S3l8HqF1//KF4V/B/uETzTSFpw0pfpkAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Cats" title="" src="/static/244fb886a3241eb8da285fece416b53a/6146e/cats.png" srcset="/static/244fb886a3241eb8da285fece416b53a/01bf6/cats.png 270w, /static/244fb886a3241eb8da285fece416b53a/6146e/cats.png 377w" sizes="(max-width: 377px) 100vw, 377px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h3 id="extract-plugin" style="position:relative;"><a href="#extract-plugin" aria-label="extract plugin permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Extract plugin</h3> <p>This amasing plugin is <a href="https://github.com/biesbjerg/ngx-translate-extract" target="_blank" rel="nofollow noopener noreferrer">ngx-translate-extract</a> and it lets you extract your translatable text into the <code class="language-text">json</code> files. This is very handy if you already have a project and want to extract all of the text in one go instead of going through your HTML files one by one.</p> <p>First install it by running:</p> <div class="gatsby-code-button-container" data-toaster-id="8887100652069924000" data-toaster-class="gatsby-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 @biesbjerg/ngx-translate-extract --save-dev`, `8887100652069924000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @biesbjerg/ngx-translate-extract --save-dev</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>As you can see there is no need to save it as a dependency. You only need this when developing, and obviously you care about your package size.</p> <p>Now you can simply use it by running the below command:</p> <div class="gatsby-code-button-container" data-toaster-id="97260208912609100000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ngx-translate-extract -i ./src -o ./src/i18n/en.json`, `97260208912609100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ngx-translate-extract <span class="token parameter variable">-i</span> ./src <span class="token parameter variable">-o</span> ./src/i18n/en.json</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And that’s it, you can now go ahead and modify the variable names if you like. For more info please refer to <a href="https://github.com/biesbjerg/ngx-translate-extract" target="_blank" rel="nofollow noopener noreferrer">their GitHub page</a>.</p> <h2 id="bableedit" style="position:relative;"><a href="#bableedit" aria-label="bableedit permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>BableEdit</h2> <p>This is a <a href="https://www.codeandweb.com/babeledit" target="_blank" rel="nofollow noopener noreferrer">handy little tool </a> which you can use to edit your <code class="language-text">json</code> files all at once. It allows you see and edit all your translations in one place, compare translations for different languages, and find missing translations.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 952px; " > <a class="gatsby-resp-image-link" href="/static/212bdcb07d2996fe814b066921015807/7e4a6/babeledit2-win-952.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 69.62962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAAsTAAALEwEAmpwYAAACE0lEQVR42l1Sa3ObMBDU//9TjdN8Sdv4gY0BA+IloScG7NjGxHa74Dgz6Y64ESPt7eruSJ6Zw/HQtvuuO18ulw+sAWO8/14++vFnjMPm3PfX65ULRXgppNApLZqm5oXIEq6kyVNe2SqlTCtjTVXXtZRqt9tZY1lRSqnPXZfmjLz9fnUWDqVJWZZ5Xvi+7zjObD73PG+5XMUxNSNArqpKKVWO2FbWD2MimSc4u93+3iGljKMYl47H42HEffMVu66rrE0p9UNKjEysVn1/uY0JQHZdF/pBEIRRhCwQtN+htYZylGRE8U1l9ak738lCCN/3NptQSLkf8f4d0DfWZgkN4oyI3FVSgPZQFtDcgB1GcIEq/oemaaBsjV75EUnTcL1yhBju4SBNs2CwDH6ojdmNaNvdF+AF9WNF8Wu6IIfDXrBcawMm+qykxHshG8cxZO7OwWkeaNt2qL5W04VLTqcDy9OEpkab+5vXnodVsEIMTeH44L8d5EEcPECp5OzPfEn6vjdK84IZba/XG/oJy5BNkoQmSRTBAsUjH/5b1Awvr6x5W6zI8XiCAmOsyAu0EQeUUqhZW0EBfUK94bwdgVPcgXej9cxxCUYaFR0mYP+Owa2bWooS6Tjn+FCCbb1FCszGRz8AcciytRTj6fkB2oK49lDmaDqbP01+Yk2eX348PWMzmzvzBSZ45Sw/18JxPS+YvLz+A96s/H+25drWAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="BabelEdit" title="" src="/static/212bdcb07d2996fe814b066921015807/7e4a6/babeledit2-win-952.png" srcset="/static/212bdcb07d2996fe814b066921015807/01bf6/babeledit2-win-952.png 270w, /static/212bdcb07d2996fe814b066921015807/07484/babeledit2-win-952.png 540w, /static/212bdcb07d2996fe814b066921015807/7e4a6/babeledit2-win-952.png 952w" sizes="(max-width: 952px) 100vw, 952px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>It’s worth giving it a shot if you have a couple of languages to support.</p><![CDATA[Angular reactive forms and custom validations]]>https://yashints.dev/blog/2017/12/19/angular-reactive-forms-and-custom-validationshttps://yashints.dev/blog/2017/12/19/angular-reactive-forms-and-custom-validationsTue, 19 Dec 2017 00:00:00 GMT<p>When using <a href="https://v2.angular.io/docs/ts/latest/guide/reactive-forms.html" target="_blank" rel="nofollow noopener noreferrer">reactive forms</a> in <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular</a> we usually avoid template based validation like <code class="language-text">required</code>, <code class="language-text">maxlength</code> and so on.</p> <!--more--> <p>Instead we use the <code class="language-text">Validators</code> in the <code class="language-text">@angular/forms</code> like this:</p> <div class="gatsby-code-button-container" data-toaster-id="88361218641486820000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`this.heroForm = this.fb.group({ name: ['', Validators.required], })`, `88361218641486820000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>heroForm <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">,</span> Validators<span class="token punctuation">.</span>required<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"><strong>Note</strong>: in the above code, <code class="language-text">fb</code> is an instance of <code class="language-text">FormBuilder</code> which is injected into the constructor.</div></div> <p>However, sometimes we want to implement a custom logic for our validations. Scenarios like checking a property value based on another property or checking whether two entered email addresses are equal.</p> <h2 id="template" style="position:relative;"><a href="#template" aria-label="template permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Template</h2> <p>We will take the email address scenario here as our base example and implement a custom validator that checks whether or not they are the same.</p> <p>First let’s see how the template looks like:</p> <div class="gatsby-code-button-container" data-toaster-id="39435461923962010000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<form novalidate> <label> <span>Full name</span> <input type=&quot;text&quot; name=&quot;name&quot; placeholder=&quot;Your full name&quot; /> </label> <div> <label> <span>Email address</span> <input type=&quot;email&quot; name=&quot;email&quot; placeholder=&quot;Your email address&quot; /> </label> <label> <span>Confirm address</span> <input type=&quot;email&quot; name=&quot;confirm&quot; placeholder=&quot;Confirm your email address&quot; /> </label> </div> <button type=&quot;submit&quot;>Sign up</button> </form>`, `39435461923962010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">novalidate</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</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 punctuation">></span></span>Full name<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>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Your full name<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>label</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>label</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 punctuation">></span></span>Email address<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>input</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>email<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Your email address<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>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</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 punctuation">></span></span>Confirm address<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>input</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>email<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>confirm<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Confirm your email address<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>label</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>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>submit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Sign up<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>form</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see, it is a pretty simple form with three fields: name, email and its confirmation. Now let’s create the form for this template:</p> <div class="gatsby-code-button-container" data-toaster-id="36057005569107694000" data-toaster-class="gatsby-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 { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators, AbstractControl } from '@angular/forms'; @Component({...}) export class SignupComponent implements OnInit { user: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit() { this.user = this.fb.group({ name: ['', Validators.required], email: ['', Validators.required], confirm: ['', Validators.required] }, { validate: (formGroup: FormGroup) => { return this.validateEmailConfirmation(formGroup); } }); } }`, `36057005569107694000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> OnInit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> FormBuilder<span class="token punctuation">,</span> FormGroup<span class="token punctuation">,</span> Validators<span class="token punctuation">,</span> AbstractControl <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/forms'</span><span class="token punctuation">;</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Component</span></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 keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">SignupComponent</span> <span class="token keyword">implements</span> <span class="token class-name">OnInit</span> <span class="token punctuation">{</span> user<span class="token operator">:</span> FormGroup<span class="token punctuation">;</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> fb<span class="token operator">:</span> FormBuilder<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token function">ngOnInit</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>user <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">,</span> Validators<span class="token punctuation">.</span>required<span class="token punctuation">]</span><span class="token punctuation">,</span> email<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">,</span> Validators<span class="token punctuation">.</span>required<span class="token punctuation">]</span><span class="token punctuation">,</span> confirm<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">,</span> Validators<span class="token punctuation">.</span>required<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token function-variable function">validate</span><span class="token operator">:</span> <span class="token punctuation">(</span>formGroup<span class="token operator">:</span> FormGroup<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">validateEmailConfirmation</span><span class="token punctuation">(</span>formGroup<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>So in our model we have a name which is required, an email address and its confirmation which are required as well. However we cannot access confirm control value here so we will need another way for the confirmation validation.</p> <p>That’s when the second parameter to <code class="language-text">group</code> method on <code class="language-text">FormBuilder</code> comes to play. It takes a function which can be executed when the values are changed. In this case we are expecting a form group as input and we are calling a private method from our component and pass that form group as input to that method.</p> <p>Now let’s implement the <code class="language-text">validateEmailConfirmation</code> method:</p> <div class="gatsby-code-button-container" data-toaster-id="87884495791850910000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`private validateEmailConfirmation(formGroup: AbstractControl): {[key: string]: boolean} { const email = formGroup.get('email'); const confirm = formGroup.get('confirm'); if (!email || !confirm) { return null; } if (email.value !== confirm.value) { return { confirm: false }; } }`, `87884495791850910000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">private</span> <span class="token function">validateEmailConfirmation</span><span class="token punctuation">(</span>formGroup<span class="token operator">:</span> AbstractControl<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">[</span>key<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> email <span class="token operator">=</span> formGroup<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'email'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> confirm <span class="token operator">=</span> formGroup<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'confirm'</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>email <span class="token operator">||</span> <span class="token operator">!</span>confirm<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>email<span class="token punctuation">.</span>value <span class="token operator">!==</span> confirm<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 punctuation">{</span> confirm<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>First we get the email and confirm controls by calling the <code class="language-text">get</code> method on the form group. Then we check that both of them do exists by a <code class="language-text">truthy</code> check. If either of them do not exists we just return null.</p> <p>Returning null means that the result is valid (remember that we have required all of them so that wouldn’t be a problem).</p> <p>At last we compare the two values and if they are not equal we return an object which has a key and a <code class="language-text">boolean</code> value assigned to it.</p> <h2 id="binding-the-template-to-the-form" style="position:relative;"><a href="#binding-the-template-to-the-form" aria-label="binding the template to the form permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Binding the template to the form</h2> <p>We can now bind the form to the template and the validation messages to it:</p> <div class="gatsby-code-button-container" data-toaster-id="78981715684452000000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<form novalidate (ngSubmit)=&quot;onSubmit(user)&quot; [formGroup]=&quot;user&quot;> <div class=&quot;form-group&quot;> <label> <span>Full name</span> <input type=&quot;text&quot; placeholder=&quot;Your full name&quot; formControlName=&quot;name&quot; /> </label> <div class=&quot;error&quot; *ngIf=&quot;user.get('name').hasError('required')&quot;> Name is required </div> </div> <div class=&quot;form-group&quot;> <label> <span>Email address</span> <input type=&quot;email&quot; placeholder=&quot;Your email address&quot; formControlName=&quot;email&quot; /> </label> <div class=&quot;error&quot; *ngIf=&quot;user.get('email').hasError('required')&quot;> Email is required </div> </div> <div class=&quot;form-group&quot;> <label> <span>Confirm address</span> <input type=&quot;email&quot; placeholder=&quot;Confirm your email address&quot; formControlName=&quot;confirm&quot; /> </label> <div class=&quot;error&quot; *ngIf=&quot;user.get('confirm').hasError('required')&quot;> Confirming email is required </div> <div class=&quot;error&quot; *ngIf=&quot;user.hasError('confirm')&quot;> The email and its confirmation do not match. </div> </div> <button type=&quot;submit&quot; [disabled]=&quot;user.invalid&quot;>Sign up</button> </form>`, `78981715684452000000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">novalidate</span> <span class="token attr-name">(ngSubmit)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>onSubmit(user)<span class="token punctuation">"</span></span> <span class="token attr-name">[formGroup]</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>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>form-group<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>label</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 punctuation">></span></span>Full name<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>input</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>text<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Your full name<span class="token punctuation">"</span></span> <span class="token attr-name">formControlName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<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>label</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>error<span class="token punctuation">"</span></span> <span class="token attr-name">*ngIf</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user.get('name').hasError('required')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Name is required <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>form-group<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>label</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 punctuation">></span></span>Email address<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>input</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>email<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Your email address<span class="token punctuation">"</span></span> <span class="token attr-name">formControlName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<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>label</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>error<span class="token punctuation">"</span></span> <span class="token attr-name">*ngIf</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user.get('email').hasError('required')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Email is required <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>form-group<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>label</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 punctuation">></span></span>Confirm address<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>input</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>email<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Confirm your email address<span class="token punctuation">"</span></span> <span class="token attr-name">formControlName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>confirm<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>label</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>error<span class="token punctuation">"</span></span> <span class="token attr-name">*ngIf</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user.get('confirm').hasError('required')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Confirming email is required <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>error<span class="token punctuation">"</span></span> <span class="token attr-name">*ngIf</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user.hasError('confirm')<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> The email and its confirmation do not match. <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>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>submit<span class="token punctuation">"</span></span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user.invalid<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Sign up<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>form</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The first thing we have modified in the template is <code class="language-text">[formGroup]</code> to the form and assigned the form group we made to it. Then we added <code class="language-text">formControlName</code> to each one of the inputs.</p> <p>So far we are wired up. Then we disabled the submit button if the form is invalid. And when it comes to error messages we get the control from the form and check for error messages with normal validation e.g. <code class="language-text">required</code>.</p> <p>We need one more error message for when the two email address do not match and because we are using a custom validator we will need to check for errors on the form group rather than the controls.</p> <p>Note that we are just checking for <code class="language-text">user.hasError('confirm')</code> to see whether they are equal or not.</p> <p>And that’s it. We now have a working form with all the bindings and validations in place. Hope this helps to code better and do not forget to spread the love 😉</p><![CDATA[Setting up VSTS CI/CD for a SPA app using AngularCLI, ASPNetCore (Part 2)]]>https://yashints.dev/blog/2017/12/18/setting-up-vsts-ci-cd-for-a-spa-app-using-angularcli-aspnetcore-part-2https://yashints.dev/blog/2017/12/18/setting-up-vsts-ci-cd-for-a-spa-app-using-angularcli-aspnetcore-part-2Mon, 18 Dec 2017 00:00:00 GMT<p><a href="/2017-04-27-vsts-cicd-angularcli-aspnetcore/">In my previous post</a> I showed you how to setup a build pipeline for a SPA application written in <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular</a> using <a href="https://github.com/angular/angular-cli" target="_blank" rel="nofollow noopener noreferrer">Angular CLI</a> and <a href="https://docs.microsoft.com/en-us/aspnet/core/" target="_blank" rel="nofollow noopener noreferrer">ASP.Net Core</a> as back-end. I promised back then to continue with the release as well, but have been pretty busy lately.</p> <!--more--> <p>Now is the time to pay my debt and show you how you will get the release done to make it a proper continuous delivery right from when you commit the code to when it is deployed to production.</p> <p>We will be using <a href="https://azure.microsoft.com/en-au/services/app-service/web/" target="_blank" rel="nofollow noopener noreferrer">Azure Web Apps</a> for our deployment purposes but it really doesn’t matter where you deploy it since there are many third party tools covering different providers like <a href="https://aws.amazon.com/" target="_blank" rel="nofollow noopener noreferrer">AWS</a>.</p> <h1 id="create-the-release-definition" style="position:relative;"><a href="#create-the-release-definition" aria-label="create the release definition permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the release definition</h1> <p>You can create a release in VSTS in two easy ways, either click on the release tab and create a new release definition:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 697px; " > <a class="gatsby-resp-image-link" href="/static/e0966127d4b79a70a80508b7349181a6/7422e/release-from-release-page.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 33.33333333333333%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABaElEQVR42nWOPU/CUBiFO7q4GBV1NjgYf4Yx8Tc4uehqHGXAEBxMnPwJOpiQ6CBRYsRvMCZAQCxI+WwDlLZIe3tpb28/7rWB6GI8OTl5n+U9h5neOJ7aPlvajS3uxGa2Tic3T+bC78GjxnyUm41wC1EucFAP7udXQ8m1yMt6+H5lLx2IVidCn8uHLJNIFy7iqfPLVPK1eJ2t3eRq8UzjjhVvP8R4lk8U2lc5wcc3Ts43lExVfq4oT9zggRs8lnsMlkQxk1NLrCcKRJU80HexaSNom9A2ADaAgyAlDqUepe44yQgRMhhZ6JS7OvIodglyCJZl13V1CIGuKxr80vThcOh6hFD66xFREyGm3+JLZb5YbhXYJltpy7UGxpZhGLZty9CGyEWmYVkWIcT7kf/dR9M0GaDIfYFXBF5qNf3D1FTbcTDG9H+RUTPym3lBqNbrY3d7UrvTAQCoqqppGoTQT78B/ZG/BQDwDRqkaZzbFvGkAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Release from release page" title="" src="/static/e0966127d4b79a70a80508b7349181a6/7422e/release-from-release-page.png" srcset="/static/e0966127d4b79a70a80508b7349181a6/01bf6/release-from-release-page.png 270w, /static/e0966127d4b79a70a80508b7349181a6/07484/release-from-release-page.png 540w, /static/e0966127d4b79a70a80508b7349181a6/7422e/release-from-release-page.png 697w" sizes="(max-width: 697px) 100vw, 697px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>or if you have a successful build click on the release button next to it and it will then brings you to the same page but automatically links it to the build definition’s output artefact:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 697px; " > <a class="gatsby-resp-image-link" href="/static/2f8ccc44816c40f94cb01f101199f7a3/7422e/release-from-build-summary.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 22.962962962962965%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABDElEQVR42i2Iu07DMBRA83tIMNM8xHd0qrqXX6BTGxUCxOkKyoKAAZhoMlEioZZSJbZjx3aeTnAK9x4d3Xu0fVbHXFJepBjjFMdJzDlv21bKprfag9X8H61s6kpWZScbDWOSIIwgooTSlAoqRCaKvCxrmWeCU64o8gImkBEmWM4REetPuo6azUYb3Y/OHyZjfzx5nAzvhrqjm45pXVvW7ZnpGMZVj3oHi4F+qRuOaSwGxvRYvzg5nR5p/oc/e5vNn+buq2s/2/aL7YUeCABYue676wXeMlyCFVDlr7uqBx4IvZsQaG3RRrto+7WFOxh/x+gH0YSSmChnMGOIoV1fGGTpPs1J3lVdVxyoul+PQPRJdY2jzwAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Release from build summary" title="" src="/static/2f8ccc44816c40f94cb01f101199f7a3/7422e/release-from-build-summary.png" srcset="/static/2f8ccc44816c40f94cb01f101199f7a3/01bf6/release-from-build-summary.png 270w, /static/2f8ccc44816c40f94cb01f101199f7a3/07484/release-from-build-summary.png 540w, /static/2f8ccc44816c40f94cb01f101199f7a3/7422e/release-from-build-summary.png 697w" sizes="(max-width: 697px) 100vw, 697px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>The easiest way to create the release definition is based on a template. The best template for our purpose is <strong>Azure App Service Deployment</strong>, which is very straightforward to use. When you click on create new release definition you will see below pop up:</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/efac25cf62a8c937e82d0c9d7dfd66a7/90683/vststemplate.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 39.25925925925926%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd6AsD//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAYEAACAwAAAAAAAAAAAAAAAAAAARAhgf/aAAgBAQABPyHBu4//2gAMAwEAAgADAAAAEPPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGBABAQEBAQAAAAAAAAAAAAAAAQARIUH/2gAIAQEAAT8QT00yHNl//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="New release definition" title="" src="/static/efac25cf62a8c937e82d0c9d7dfd66a7/47311/vststemplate.jpg" srcset="/static/efac25cf62a8c937e82d0c9d7dfd66a7/6f81f/vststemplate.jpg 270w, /static/efac25cf62a8c937e82d0c9d7dfd66a7/09d21/vststemplate.jpg 540w, /static/efac25cf62a8c937e82d0c9d7dfd66a7/47311/vststemplate.jpg 1080w, /static/efac25cf62a8c937e82d0c9d7dfd66a7/0047d/vststemplate.jpg 1620w, /static/efac25cf62a8c937e82d0c9d7dfd66a7/274e1/vststemplate.jpg 2160w, /static/efac25cf62a8c937e82d0c9d7dfd66a7/90683/vststemplate.jpg 2842w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Select the first option and you will be asked to enter a name for the environment you are deploying to:</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/d9488ae3e64a38eaf4e8b24c26a9d3e2/d35b7/vstsenvironment.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 45.92592592592593%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMCBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe7qdAD/xAAWEAEBAQAAAAAAAAAAAAAAAAAQATH/2gAIAQEAAQUCZp//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAXEAADAQAAAAAAAAAAAAAAAAABECGx/9oACAEBAAE/IQa9H//aAAwDAQACAAMAAAAQsw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAACAgMAAAAAAAAAAAAAAAAAIQFREDFB/9oACAEBAAE/EJk2rFYsjsn/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="VSTS environment" title="" src="/static/d9488ae3e64a38eaf4e8b24c26a9d3e2/47311/vstsenvironment.jpg" srcset="/static/d9488ae3e64a38eaf4e8b24c26a9d3e2/6f81f/vstsenvironment.jpg 270w, /static/d9488ae3e64a38eaf4e8b24c26a9d3e2/09d21/vstsenvironment.jpg 540w, /static/d9488ae3e64a38eaf4e8b24c26a9d3e2/47311/vstsenvironment.jpg 1080w, /static/d9488ae3e64a38eaf4e8b24c26a9d3e2/d35b7/vstsenvironment.jpg 1374w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Enter the name and close the panel by clicking on the <code class="language-text">x</code> mark (there is no save button here).</p> <h2 id="linking-the-build-artefact" style="position:relative;"><a href="#linking-the-build-artefact" aria-label="linking the build artefact permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Linking the build artefact</h2> <p>Now it is time to add the build artefact to the release. Click on add artefact button and you will see below pop up:</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/85981ee3cf691972874e244c0d32e65b/77607/vstsartifact.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 56.666666666666664%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB3R60cgX/xAAYEAACAwAAAAAAAAAAAAAAAAAAAREgQf/aAAgBAQABBQKFTT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAABECAx/9oACAEBAAY/Asgr/8QAGRAAAQUAAAAAAAAAAAAAAAAAIQABESBh/9oACAEBAAE/IcCggNW//9oADAMBAAIAAwAAABDfD//EABURAQEAAAAAAAAAAAAAAAAAABAx/9oACAEDAQE/EIf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhMRBBkeH/2gAIAQEAAT8QPkEEM0OqhjbfFqStAVTAxt9n/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="VSTS artefact" title="" src="/static/85981ee3cf691972874e244c0d32e65b/47311/vstsartifact.jpg" srcset="/static/85981ee3cf691972874e244c0d32e65b/6f81f/vstsartifact.jpg 270w, /static/85981ee3cf691972874e244c0d32e65b/09d21/vstsartifact.jpg 540w, /static/85981ee3cf691972874e244c0d32e65b/47311/vstsartifact.jpg 1080w, /static/85981ee3cf691972874e244c0d32e65b/0047d/vstsartifact.jpg 1620w, /static/85981ee3cf691972874e244c0d32e65b/274e1/vstsartifact.jpg 2160w, /static/85981ee3cf691972874e244c0d32e65b/77607/vstsartifact.jpg 2885w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Select the project and the list of builds will be populated with all the available builds. Select the one you are after and select latest as the version. Then give it a source alias (this is an identifier - typically a short name - that uniquely identifies an artefact linked to a a release definition). Now select add and that’s it we have linked the build output to the release.</p> <h2 id="setting-the-deployment-condition" style="position:relative;"><a href="#setting-the-deployment-condition" aria-label="setting the deployment condition permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 the deployment condition</h2> <p>Now it is time to set the deployment condition, I will use automatic deployment which is turned off by default. Click on the little trigger button on top of the artefact:</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/0b7e2dacc12229adfc69851ecb1865b0/04254/cdtriggervsts.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 20.740740740740744%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAEABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB34FB/8QAFRABAQAAAAAAAAAAAAAAAAAAAEH/2gAIAQEAAQUCV//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEAAT8hX//aAAwDAQACAAMAAAAQA8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAXEAADAQAAAAAAAAAAAAAAAAAAEBGB/9oACAEBAAE/ECXC/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Trigger VSTS" title="" src="/static/0b7e2dacc12229adfc69851ecb1865b0/47311/cdtriggervsts.jpg" srcset="/static/0b7e2dacc12229adfc69851ecb1865b0/6f81f/cdtriggervsts.jpg 270w, /static/0b7e2dacc12229adfc69851ecb1865b0/09d21/cdtriggervsts.jpg 540w, /static/0b7e2dacc12229adfc69851ecb1865b0/47311/cdtriggervsts.jpg 1080w, /static/0b7e2dacc12229adfc69851ecb1865b0/0047d/cdtriggervsts.jpg 1620w, /static/0b7e2dacc12229adfc69851ecb1865b0/274e1/cdtriggervsts.jpg 2160w, /static/0b7e2dacc12229adfc69851ecb1865b0/04254/cdtriggervsts.jpg 2756w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Click on enable to for continuous deployment. Add the source branch (master, prod, etc.) which means it will only trigger the release if the source branch is the one you select here. Close the panel and we’re done in this section.</p> <h2 id="release-tasks" style="position:relative;"><a href="#release-tasks" aria-label="release tasks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Release tasks</h2> <p>Before we continue with the release tasks you will need to have the following:</p> <ol> <li>An instance of Azure Web Apps (refer <a href="http://www.c-sharpcorner.com/blogs/stepbystep-guide-to-creating-a-web-app-on-azure-portal" target="_blank" rel="nofollow noopener noreferrer">here to learn how to create one using portal</a> or <a href="https://azure.microsoft.com/en-us/get-started/web-app/" target="_blank" rel="nofollow noopener noreferrer">here to learn how to create and deploy using Visual Studio</a>)</li> <li>A service endpoint defined and liked to your Azure Subscription. Refer <a href="https://docs.microsoft.com/en-us/vsts/build-release/concepts/library/service-endpoints" target="_blank" rel="nofollow noopener noreferrer">here for a comprehensive list of endpoints</a> and how to create them.</li> </ol> <p>Now click on the tasks tab and in the environment panel select the service endpoint mentioned above in the Azure Subscription box:</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/5f403af4fb854e5dc1d9e67c18eab896/df937/releaseenv.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 45.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe23Qg//xAAWEAEBAQAAAAAAAAAAAAAAAAAiACD/2gAIAQEAAQUCUs//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAWEAEBAQAAAAAAAAAAAAAAAABBACD/2gAIAQEABj8CIz//xAAaEAACAgMAAAAAAAAAAAAAAAAAARAhMVGR/9oACAEBAAE/IcqC3XbhQz//2gAMAwEAAgADAAAAEPAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBAAAwABBQAAAAAAAAAAAAAAAAExERBBccHR/9oACAEBAAE/EKTzu3kbqfAb4KelH//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Release environment" title="" src="/static/5f403af4fb854e5dc1d9e67c18eab896/47311/releaseenv.jpg" srcset="/static/5f403af4fb854e5dc1d9e67c18eab896/6f81f/releaseenv.jpg 270w, /static/5f403af4fb854e5dc1d9e67c18eab896/09d21/releaseenv.jpg 540w, /static/5f403af4fb854e5dc1d9e67c18eab896/47311/releaseenv.jpg 1080w, /static/5f403af4fb854e5dc1d9e67c18eab896/0047d/releaseenv.jpg 1620w, /static/5f403af4fb854e5dc1d9e67c18eab896/df937/releaseenv.jpg 1705w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Then select Web App from the app type drop down and select the web app you created from step one above.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> Run on agent in this page uses <code class="language-text">VS2017</code> hosted agent, if you want to use a Linux host you will need to change the settings yourself.</div></div> <p>Now click on the <code class="language-text">Deploy Azure App Service</code> task to see the details on the right hand side panel. We will leave the version on this page to remain on <code class="language-text">3.*</code> which now supports <code class="language-text">Supports File Transformations (XDT)</code> and <code class="language-text">Supports Variable Substitutions(XML, JSON)</code> but if you want to use an older version you can do that.</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/beb00992201773483211c32951572198/d9c39/releasetask.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 50.37037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe21SoP/xAAXEAADAQAAAAAAAAAAAAAAAAAAAREg/9oACAEBAAEFAqK5/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAAAEgMUH/2gAIAQEABj8Cpmx//8QAGxAAAQQDAAAAAAAAAAAAAAAAAQAQESFBgaH/2gAIAQEAAT8hJXyRysbwwy//2gAMAwEAAgADAAAAEAAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBABAAIBBQAAAAAAAAAAAAAAAQARMUFxgZHR/9oACAEBAAE/EKQHyXT2GowdSK6ZxM90uDP/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="VSTS release task" title="" src="/static/beb00992201773483211c32951572198/47311/releasetask.jpg" srcset="/static/beb00992201773483211c32951572198/6f81f/releasetask.jpg 270w, /static/beb00992201773483211c32951572198/09d21/releasetask.jpg 540w, /static/beb00992201773483211c32951572198/47311/releasetask.jpg 1080w, /static/beb00992201773483211c32951572198/0047d/releasetask.jpg 1620w, /static/beb00992201773483211c32951572198/d9c39/releasetask.jpg 1800w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Based on what you’ve selected in the environment section from previous steps, the next three fields will be pre-filled for you.</p> <p>The next important thing to consider is when you have set up an staging slot for your web app and want to deploy to it first and do some verification before deploying to production which is a logical precaution. If so tick the deploy to staging box.</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/a3fe4b4216f4c58067809bba760b7e8c/0993a/taskcontinue.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 49.62962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3amgD//EABUQAQEAAAAAAAAAAAAAAAAAABAB/9oACAEBAAEFAmP/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAVEAEBAAAAAAAAAAAAAAAAAAABIP/aAAgBAQABPyEaf//aAAwDAQACAAMAAAAQUM//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAACAgMAAAAAAAAAAAAAAAAAARARITGB/9oACAEBAAE/EHJ0qMnTef/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="VSTS release task" title="" src="/static/a3fe4b4216f4c58067809bba760b7e8c/47311/taskcontinue.jpg" srcset="/static/a3fe4b4216f4c58067809bba760b7e8c/6f81f/taskcontinue.jpg 270w, /static/a3fe4b4216f4c58067809bba760b7e8c/09d21/taskcontinue.jpg 540w, /static/a3fe4b4216f4c58067809bba760b7e8c/47311/taskcontinue.jpg 1080w, /static/a3fe4b4216f4c58067809bba760b7e8c/0047d/taskcontinue.jpg 1620w, /static/a3fe4b4216f4c58067809bba760b7e8c/0993a/taskcontinue.jpg 1783w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>You can leave the package folder intact if the build output is created on the default working folder.</p> <p>Select the take app offline if you haven’t selected the deploy to slot option (since users might experience some unexpected behaviour if they are using the application).</p> <p>And at last if you want to use web deploy for reasons like having a dependency on it, you will need to tick publish using web deploy and that’s it.</p> <p>Click save and queue release if you already have a successful build and there you go, end to end from commit to deployment to the target environment.</p> <p>Hope this helps you to have a seamless experience using <a href="https://www.visualstudio.com/team-services/" target="_blank" rel="nofollow noopener noreferrer">Visual Studio Team Services</a> features for CI/CD.</p><![CDATA[How to use nested form groups using ReactiveForms in Angular]]>https://yashints.dev/blog/2017/12/15/nested-formgroups-reactiveforms-angularhttps://yashints.dev/blog/2017/12/15/nested-formgroups-reactiveforms-angularFri, 15 Dec 2017 00:00:00 GMT<p>It’s been a while since I decided to write about reactive forms, as I believe they are an essential part of every developer’s life.</p> <!--more--> <p>Before I start, let’s see what does reactive mean.</p> <p>When talking about <a href="https://angular.io/guide/reactive-forms" target="_blank" rel="nofollow noopener noreferrer">reactive forms</a>, it means that we are avoiding to use <code class="language-text">ngModel</code>, <code class="language-text">required</code> and so on. This means that instead of showing that Angular is taking care of the form for us, we can use the underlying APIs to do so.</p> <p><a href="https://github.com/yashints/NestedFormGroupsAngular" target="_blank" rel="nofollow noopener noreferrer">Full source code here</a>.</p> <p>In a simpler term, instead of using template driven model binding, we can construct our own form and the way they should be bound, validated and so on. For more information please refer to <a href="https://angular.io/guide/reactive-forms" target="_blank" rel="nofollow noopener noreferrer">Angular documentation here</a>.</p> <p>Now if you are creating a form in <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular </a> using Reactive Forms and you have a complex object to bind to i.e. your form has multiple sections and each of them should be bound to a child object, then you can simply use <a href="https://angular.io/api/forms/FormControl#formcontrol" target="_blank" rel="nofollow noopener noreferrer">FormControl</a> on an input like this:</p> <div class="gatsby-code-button-container" data-toaster-id="63378319619622280000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<input formControlName=&quot;”parent.child.property”&quot; />`, `63378319619622280000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">formControlName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>”parent.child.property”<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Instead you can use nested form groups that make it easy to understand and prevent you from having a large flat object to use in your bindings. So let’s see how we should do it properly.</p> <p>Let’s assume we have a form to let user select some services they want to purchase as part of a package. Each service is presented in UI as a checkbox which user can check or uncheck.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> Assumptions I’ve made: You are familiar with Angular and also had some basic exposure to Reactive Forms.</div></div> <p>Our model would look something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="75476945715516210000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export class Package { name: string serviceInfo: ServiceInfo } export class ServiceInfo { deliveryDate: Date services: Array<string> }`, `75476945715516210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Package</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> string <span class="token literal-property property">serviceInfo</span><span class="token operator">:</span> ServiceInfo <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ServiceInfo</span> <span class="token punctuation">{</span> <span class="token literal-property property">deliveryDate</span><span class="token operator">:</span> Date <span class="token literal-property property">services</span><span class="token operator">:</span> Array<span class="token operator">&lt;</span>string<span class="token operator">></span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And we can then create the form group using the <code class="language-text">FormBuilder</code> which we can inject into our constructor:</p> <div class="gatsby-code-button-container" data-toaster-id="62840554297157470000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export class MyForm { packageForm: FormGroup; constructor(private fb: FormBuilder) { } ngOnInit(): void { this.packageForm = this.fb.group({ name: ['', Validators.required], serviceInfo: this.fb.group({ deliveryDate: '', services: this.fb.FormArray() }) }); } }`, `62840554297157470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">MyForm</span> <span class="token punctuation">{</span> <span class="token literal-property property">packageForm</span><span class="token operator">:</span> FormGroup<span class="token punctuation">;</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter"><span class="token keyword">private</span> <span class="token literal-property property">fb</span><span class="token operator">:</span> FormBuilder</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token function">ngOnInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>packageForm <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">,</span> Validators<span class="token punctuation">.</span>required<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">serviceInfo</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">deliveryDate</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">services</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">FormArray</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>For now I just used an array but we will change this shortly after we created our service catalogue object:</p> <div class="gatsby-code-button-container" data-toaster-id="30307771844864240000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`serviceList: Array<any> = [ { name: 'ADSL', code: 'ADSL', selected: false }, { name: 'Cable Broad Band', code: 'CBL', selected: false }, { name: 'Foxtel TV', code: 'FOXTEL', selected: true }, { name: 'Home Wireless', code: 'HWL', selected: true }, { name: '4G Network', code: '4G', selected: false } ];`, `30307771844864240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token literal-property property">serviceList</span><span class="token operator">:</span> Array<span class="token operator">&lt;</span>any<span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ADSL'</span><span class="token punctuation">,</span> <span class="token literal-property property">code</span><span class="token operator">:</span> <span class="token string">'ADSL'</span><span class="token punctuation">,</span> <span class="token literal-property property">selected</span><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 literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Cable Broad Band'</span><span class="token punctuation">,</span> <span class="token literal-property property">code</span><span class="token operator">:</span> <span class="token string">'CBL'</span><span class="token punctuation">,</span> <span class="token literal-property property">selected</span><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 literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Foxtel TV'</span><span class="token punctuation">,</span> <span class="token literal-property property">code</span><span class="token operator">:</span> <span class="token string">'FOXTEL'</span><span class="token punctuation">,</span> <span class="token literal-property property">selected</span><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 literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Home Wireless'</span><span class="token punctuation">,</span> <span class="token literal-property property">code</span><span class="token operator">:</span> <span class="token string">'HWL'</span><span class="token punctuation">,</span> <span class="token literal-property property">selected</span><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 literal-property property">name</span><span class="token operator">:</span> <span class="token string">'4G Network'</span><span class="token punctuation">,</span> <span class="token literal-property property">code</span><span class="token operator">:</span> <span class="token string">'4G'</span><span class="token punctuation">,</span> <span class="token literal-property property">selected</span><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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now we can create a method which will generate the desired <code class="language-text">FormArray</code> for us (just to keep the form group creation clean) using the above catalogue:</p> <div class="gatsby-code-button-container" data-toaster-id="8440494203084792000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`buildServiceList() { const arr = this.serviceList.map(service => { return this.fb.control(service.selected); }); return this.fb.array(arr); }`, `8440494203084792000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">buildServiceList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>serviceList<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">service</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">control</span><span class="token punctuation">(</span>service<span class="token punctuation">.</span>selected<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">array</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This method will simply create a <code class="language-text">FormArray</code> and adds <code class="language-text">Boolean</code> controls to it where the service’s selected property is <code class="language-text">true</code>. We can now use this method to generate our <code class="language-text">FormGroup</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="94460888666208810000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ngOnInit(): void { this.packageForm = this.fb.group({ name: ['', Validators.required], serviceInfo: this.fb.group({ deliveryDate: '', services: this.buildServiceList() }) }); }`, `94460888666208810000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">ngOnInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>packageForm <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">,</span> Validators<span class="token punctuation">.</span>required<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">serviceInfo</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fb<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">deliveryDate</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">services</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">buildServiceList</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>So far we have defined our <code class="language-text">FormGroup</code> and we can now use it in our HTML template.</p> <div class="gatsby-code-button-container" data-toaster-id="81335988102777040000" data-toaster-class="gatsby-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;container&quot;> <h1>Select your services</h1> <form [formGroup]=&quot;packageForm&quot; (submit)=&quot;onSubmit()&quot;> <div class=&quot;form-group&quot;> <label for=&quot;name&quot;>Your name:</label> <input name=&quot;name&quot; formControlName=&quot;name&quot; /> </div> <div formGroupName=&quot;serviceInfo&quot;> <div class=&quot;form-group&quot;> <label>Delivery Date:</label> <input formControlName=&quot;deliveryDate&quot; type=&quot;date&quot; /> </div> <div class=&quot;form-group&quot;> <label>Services:</label> <div *ngFor=&quot;let service of services.controls; let i = index&quot;> <label> <input type=&quot;checkbox&quot; [formControl]=&quot;service&quot; value=&quot;&quot; /> </label> </div> </div> </div> <div><button class=&quot;btn btn-primary&quot;>Save</button></div> </form> </div>`, `81335988102777040000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>container<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>h1</span><span class="token punctuation">></span></span>Select your services<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">[formGroup]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>packageForm<span class="token punctuation">"</span></span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>onSubmit()<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>form-group<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>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Your name:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span> <span class="token attr-name">formControlName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<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">formGroupName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>serviceInfo<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>form-group<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>label</span><span class="token punctuation">></span></span>Delivery Date:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">formControlName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>deliveryDate<span class="token punctuation">"</span></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>date<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>form-group<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>label</span><span class="token punctuation">></span></span>Services:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</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">*ngFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>let service of services.controls; let i = index<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>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</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>checkbox<span class="token punctuation">"</span></span> <span class="token attr-name">[formControl]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>service<span class="token punctuation">"</span></span> <span class="token attr-name">value</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>label</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>button</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>btn btn-primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Save<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>form</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In this template, I’ve used a form which has <code class="language-text">[formGroup]</code> to use our <code class="language-text">packageForm</code>. Then I’ve defined a form control for the name property.</p> <p>Once that is done it is now time to go ahead and create the template for the child <code class="language-text">FormGroup</code>.  As you can see we need a container element (I’ve used <code class="language-text">div</code> in this case but you can use <code class="language-text">ng-container</code> if you don’t want any element on DOM for that). We tell Angular that this part should be assigned to a <code class="language-text">FormGroup</code> named “serviceInfo”.</p> <p>Now we define our delivery date as normal formControl and when it comes to services we can then loop through the services array and generate them. There are two ways to access the array. As you can see in the above template I’ve stored the array in a class property and then used it to keep my template more readable.</p> <p>However you can access it like this using the packageForm:</p> <div class="gatsby-code-button-container" data-toaster-id="12153771471038155000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!--Line break for readability--> <div *ngFor=&quot;let service of packageForm.controls.serviceInfo.controls.services.controls; let i = index&quot; ></div>`, `12153771471038155000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token comment">&lt;!--Line break for readability--></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">*ngFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>let service of packageForm.controls.serviceInfo.controls.services.controls; let i = index<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can see why I’ve stored it in a local variable now. Now when you make changes to the form, you can see it below when I am just outputting the value of the form.</p> <p>Alright we just need to extract the selected services when the form is submitted. I’ve created another method to do so:</p> <div class="gatsby-code-button-container" data-toaster-id="16082881672120863000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`getSelectedServices() { return this.packageForm.value .services.filter(x => x) .map((selected, i) => this.serviceList.map( service => service.code )); }`, `16082881672120863000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">getSelectedServices</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>packageForm<span class="token punctuation">.</span>value <span class="token punctuation">.</span>services<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> x<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">selected<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span>serviceList<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span> <span class="token parameter">service</span> <span class="token operator">=></span> service<span class="token punctuation">.</span>code <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can then call this on submit to extract the services and save it as an <code class="language-text">Array&lt;string></code>:</p> <div class="gatsby-code-button-container" data-toaster-id="84944521601606100000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`onSubmit() { const formValue = Object.assign({}, this.packageForm.value, { selectedServices: this.getSelectedServices() }); console.log(formValue); }`, `84944521601606100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">onSubmit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> formValue <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</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">this</span><span class="token punctuation">.</span>packageForm<span class="token punctuation">.</span>value<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">selectedServices</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getSelectedServices</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>formValue<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And that’s it. Hope this helps people like me who are looking to use complex objects in their UI forms and want to use <code class="language-text">Reactive Forms</code> as their desired method.</p> <p>And as always don’t forget to spread the love by sharing this if it was useful, and also feedback always is welcomed.</p><![CDATA[Using ASP.NET Core DI to inject objects into ActionFilterAttribute]]>https://yashints.dev/blog/2017/10/04/aspnetcore-di-actionfilterattributehttps://yashints.dev/blog/2017/10/04/aspnetcore-di-actionfilterattributeWed, 04 Oct 2017 00:00:00 GMT<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>Let’s assume you want to validate something before a request hits your <a href="https://docs.microsoft.com/en-us/aspnet/core/" target="_blank" rel="nofollow noopener noreferrer">ASP.NET Core</a> controller’s action method. One of the possible solutions is to create an <code class="language-text">ActionFilterAttribute</code> and use its <code class="language-text">OnActionExecutionAsync</code> (in case you like to do it asynchronously) to do the checking. Now if you are depending on something like configuration or even another instance of a class it is going to be tricky.</p> <!--more--> <div class="custom-block info"><div class="custom-block-body"><strong>Note</strong>: The purpose of this post is not to introduce the <code class="language-text">ActionFilterAttributes</code>. <a href="https://msdn.microsoft.com/en-us/library/system.web.mvc.actionfilterattribute(v=vs.118).aspx" target="_blank" rel="nofollow noopener noreferrer">For that you can have a look at here</a>.</div></div> <p>The way you use your filter attribute is to put it above your action like this:</p> <div class="gatsby-code-button-container" data-toaster-id="34181939329473954000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public class ValidateSomethingAttribute : ActionFilterAttribute { public override async Task OnActionExecutionAsync( ActionExecutingContext context, ActionExecutionDelegate next) { await DoSomething(context); await base.OnActionExecutionAsync(context, next); } } public class MyController: Controller { [ValidateSomethingAttribute] public ActionResult Get() { } }`, `34181939329473954000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ValidateSomethingAttribute</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ActionFilterAttribute</span></span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token keyword">async</span> <span class="token return-type class-name">Task</span> <span class="token function">OnActionExecutionAsync</span><span class="token punctuation">(</span> <span class="token class-name">ActionExecutingContext</span> context<span class="token punctuation">,</span> <span class="token class-name">ActionExecutionDelegate</span> next<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">DoSomething</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnActionExecutionAsync</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> next<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyController</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Controller</span></span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">ValidateSomethingAttribute</span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token return-type class-name">ActionResult</span> <span class="token function">Get</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="why-use-dependency-injection-di" style="position:relative;"><a href="#why-use-dependency-injection-di" aria-label="why use dependency injection di permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 use dependency injection (DI)?</h2> <p>Obviously there are two ways you can pass an input to an action filter. You can pass an input or you can use dependency injector (and I am not talking about scalar values here). The benefit of having dependency injector inject that dependency is that you won’t need to define a public property in your filter and pass it from controller.</p> <p>Instead you can define a private property and set it from the filter’s constructor:</p> <div class="gatsby-code-button-container" data-toaster-id="90901845208899720000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public class ValidateSomethingAttribute : ActionFilterAttribute { private readonly IConfiguration _configuration; public ValidateSomethingAttribute(IConfiguration configuration) { _configuration = configuration; } public override async Task OnActionExecutionAsync( ActionExecutingContext context, ActionExecutionDelegate next) { await DoSomething(context); await base.OnActionExecutionAsync(context, next); } }`, `90901845208899720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ValidateSomethingAttribute</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ActionFilterAttribute</span></span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">readonly</span> <span class="token class-name">IConfiguration</span> _configuration<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token function">ValidateSomethingAttribute</span><span class="token punctuation">(</span><span class="token class-name">IConfiguration</span> configuration<span class="token punctuation">)</span> <span class="token punctuation">{</span> _configuration <span class="token operator">=</span> configuration<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token keyword">async</span> <span class="token return-type class-name">Task</span> <span class="token function">OnActionExecutionAsync</span><span class="token punctuation">(</span> <span class="token class-name">ActionExecutingContext</span> context<span class="token punctuation">,</span> <span class="token class-name">ActionExecutionDelegate</span> next<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">DoSomething</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnActionExecutionAsync</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> next<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="how-to-get-it-injected" style="position:relative;"><a href="#how-to-get-it-injected" aria-label="how to get it injected permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 to get it injected</h2> <p>Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection" target="_blank" rel="nofollow noopener noreferrer">dependency injection (DI)</a>. This is because attributes must have their constructor parameters supplied where they are applied. This is a limitation of how attributes work.</p> <p>Now the question is how to have DI to inject that dependency into our filter for us. The answer is by using another filter called <code class="language-text">ServiceFilter</code>.</p> <h2 id="servicefilterattribute" style="position:relative;"><a href="#servicefilterattribute" aria-label="servicefilterattribute permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>ServiceFilterAttribute</h2> <p>From <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters" target="_blank" rel="nofollow noopener noreferrer">Microsoft Docs</a>:</p> <p>A <code class="language-text">ServiceFilter</code> retrieves an instance of the filter from DI. You add the filter to the container in <code class="language-text">ConfigureServices</code>, and reference it in a <code class="language-text">ServiceFilter</code> attribute.</p> <p>All we need to do is to let DI know it should resolve our filter attribute and inject it using a service filter:</p> <div class="gatsby-code-button-container" data-toaster-id="1343270962408360400" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public void ConfigureServices(IServiceCollection services) { ... services.AddScoped&lt;ValidateSomethingAttribute&gt;(); }`, `1343270962408360400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ConfigureServices</span><span class="token punctuation">(</span><span class="token class-name">IServiceCollection</span> services<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token range operator">..</span><span class="token punctuation">.</span> services<span class="token punctuation">.</span>AddScoped<span class="token operator">&amp;</span>lt<span class="token punctuation">;</span>ValidateSomethingAttribute<span class="token operator">&amp;</span>gt<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>and in the controller:</p> <div class="gatsby-code-button-container" data-toaster-id="90011788051089360000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[ServiceFilter(typeof(ValidateSomethingAttribute))] public IActionResult Index() { return View(); }`, `90011788051089360000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">ServiceFilter</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token type-expression class-name">ValidateSomethingAttribute</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token return-type class-name">IActionResult</span> <span class="token function">Index</span><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">View</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And done, you now can depend on ASP.NET Core DI to handle everything for you and not worry about initialising objects with their dependencies.</p> <p>To me this way is very neat and better than trying to pass the dependencies as parameters, especially if the number of dependencies are high.</p><![CDATA[CORS issues when using Azure AD in ASP.Net Core and Angular]]>https://yashints.dev/blog/2017/10/01/cors-issues-azure-ad-aspnetcorehttps://yashints.dev/blog/2017/10/01/cors-issues-azure-ad-aspnetcoreSun, 01 Oct 2017 23:32:00 GMT<p>Recently, I wrote a <a href="/2017-09-28-integrating-spa-azure-ad/">post</a> about using <a href="https://azure.microsoft.com/en-au/services/active-directory/" target="_blank" rel="nofollow noopener noreferrer">Azure Active Directory</a> (AD) as authentication mechanism for a single page application written in Angular.</p> <!--more--> <p>It also consumed <a href="https://github.com/aspnet/Home" target="_blank" rel="nofollow noopener noreferrer">ASP.NET Core 2.0</a> as API layer an we saw how to wire up the whole thing end to end.</p> <p>In my approach I redirected user to Azure from client side, however, there are other ways you can follow in which the user is redirected from server to Azure login page. In such cases you might struggle with <a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank" rel="nofollow noopener noreferrer">cross origin resource sharing</a> aka CORS issues as it will be required for the application to behave properly.</p> <h2 id="why" style="position:relative;"><a href="#why" aria-label="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>Why?</h2> <p>The reason for that is because another domain is trying to call your API for token generation purposes. So if you don’t enable the CORS the authentication will not be successfully done.</p> <p>To allow <code class="language-text">CORS</code> we need to add the header <code class="language-text">Access-Control-Allow-Origin</code> to the requests. There are two ways we can enable it, globally or on certain requests.</p> <h3 id="configure-the-cors-policy" style="position:relative;"><a href="#configure-the-cors-policy" aria-label="configure the cors policy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Configure the CORS policy</h3> <p>Before going deeper into those, you will need to configure the CORS in your <code class="language-text">ConfigureServices</code> method on your <code class="language-text">Startup.cs</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="91217209385571760000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public void ConfigureServices(IServiceCollection services) { // Add service and create Policy with options services.AddCors(options => { options.AddPolicy(&quot;CorsPolicy&quot;, builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() ); }); services.AddMvc(); }`, `91217209385571760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ConfigureServices</span><span class="token punctuation">(</span><span class="token class-name">IServiceCollection</span> services<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Add service and create Policy with options</span> services<span class="token punctuation">.</span><span class="token function">AddCors</span><span class="token punctuation">(</span>options <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span><span class="token function">AddPolicy</span><span class="token punctuation">(</span><span class="token string">"CorsPolicy"</span><span class="token punctuation">,</span> builder <span class="token operator">=></span> builder<span class="token punctuation">.</span><span class="token function">AllowAnyOrigin</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AllowAnyMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AllowAnyHeader</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AllowCredentials</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> services<span class="token punctuation">.</span><span class="token function">AddMvc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I prefer the policy over just enabling CORS because it gives us more control to be able to explicitly specify when do we want to enable it.</p> <p>Now that you’ve done configuring let’s see both ways, I mentioned earlier. For enabling the CORS globally, you can use the middle-ware available in <code class="language-text">Microsoft.AspNetCore.Cors</code> NuGet package:</p> <div class="gatsby-code-button-container" data-toaster-id="17332243255850277000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public void Configure(IApplicationBuilder app) { // ... // global policy - assign here or on each controller app.UseCors(&quot;CorsPolicy&quot;); // ... app.UseMvcWithDefultRoutes(); }`, `17332243255850277000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Configure</span><span class="token punctuation">(</span><span class="token class-name">IApplicationBuilder</span> app<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token comment">// global policy - assign here or on each controller</span> app<span class="token punctuation">.</span><span class="token function">UseCors</span><span class="token punctuation">(</span><span class="token string">"CorsPolicy"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ...</span> app<span class="token punctuation">.</span><span class="token function">UseMvcWithDefultRoutes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It is very important to call the middle-ware before adding MVC as otherwise it will not work, since the request gets terminated by MVC pipeline.</p> <p>The second way (also my preferred option) is to add it the controller we need (e.g. login controller):</p> <div class="gatsby-code-button-container" data-toaster-id="10109506372095111000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[EnableCors(&quot;CorsPolicy&quot;)] [Authorize] public class LoginController : Controller { ... }`, `10109506372095111000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">EnableCors</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"CorsPolicy"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Authorize</span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LoginController</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Controller</span></span> <span class="token punctuation">{</span> <span class="token range operator">..</span><span class="token punctuation">.</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It’s all done. Your application now supports CORS and the authentication will be successful.</p> <h2 id="refine-the-policy" style="position:relative;"><a href="#refine-the-policy" aria-label="refine the policy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Refine the policy</h2> <p>If you paid attention to the policy you will find out that we are enabling the <code class="language-text">CORS</code> for all domains, all headers and all methods. This is can lead to security issues later on, so let’s refine this to just allow that from Azure AD and not other domains.</p> <p>In the policy you just need to set the domain instead of using <code class="language-text">AllowAnyOrigin</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="6795598792459700000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`services.AddCors(options => { options.AddPolicy(&quot;CorsPolicy&quot;, builder => builder.WithOrigins(&quot;https://login.microsoftonline.com&quot;) .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); });`, `6795598792459700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp">services<span class="token punctuation">.</span><span class="token function">AddCors</span><span class="token punctuation">(</span>options <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span><span class="token function">AddPolicy</span><span class="token punctuation">(</span><span class="token string">"CorsPolicy"</span><span class="token punctuation">,</span> builder <span class="token operator">=></span> builder<span class="token punctuation">.</span><span class="token function">WithOrigins</span><span class="token punctuation">(</span><span class="token string">"https://login.microsoftonline.com"</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AllowAnyMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AllowAnyHeader</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AllowCredentials</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This makes sure that our APIs are only available to the specified domain rather than any domain which is much more secure.</p> <p>Hope this helps resolving the issue you’re facing.</p> <h2 id="references" style="position:relative;"><a href="#references" aria-label="references permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>References</h2> <ul> <li><a href="https://docs.microsoft.com/en-us/aspnet/core/security/cors" target="_blank" rel="nofollow noopener noreferrer">ASP.NET Core docs</a></li> <li><a href="https://github.com/Azure-Samples/active-directory-angularjs-singlepageapp-dotnet-webapi" target="_blank" rel="nofollow noopener noreferrer">Azure Samples</a></li> </ul><![CDATA[Integrating your SPA with Azure AD]]>https://yashints.dev/blog/2017/09/28/integrating-spa-azure-adhttps://yashints.dev/blog/2017/09/28/integrating-spa-azure-adThu, 28 Sep 2017 15:10:00 GMT<blockquote> <p>As a user I want to be able to login to system using my work account</p> </blockquote> <p>This is one of the most famous lines in a user story in almost every project’s backlog.</p> <!--more--> <p>However, sometimes it might be the case that you are responsible to decide which authentication mechanism to be used.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> The source code for this post can be found on my <a href="https://github.com/yashints/Angular4AzureAD" target="_blank" rel="nofollow noopener noreferrer">GitHub repository</a>.</div></div> <p>You might decide to use <a href="https://azure.microsoft.com/en-au/services/active-directory/" target="_blank" rel="nofollow noopener noreferrer">Azure Active Directory</a> (AAD) and if that’s the case this post will help you to get up to speed with that process. The assumption is that you have a <a href="https://en.wikipedia.org/wiki/Single-page_application" target="_blank" rel="nofollow noopener noreferrer">single page application</a> (SPA) and are using <a href="https://docs.microsoft.com/en-us/aspnet/core/" target="_blank" rel="nofollow noopener noreferrer">ASP.Net Core</a> Web API as your supporting back-end.</p> <p>Also I will assume that you already have an Azure AD setup and have created an application with return URL <code class="language-text">localhost:4200</code>. If you do not know how to do that please read <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications" target="_blank" rel="nofollow noopener noreferrer">this article</a>.</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> the project structure I use here is not best practice and is only used to show you how you can utilise Azure AD as your authentication mechanism. However, I’ve used it in a large project and it has served me well in the development productivity.</div></div> <h2 id="setting-up-the-projects" style="position:relative;"><a href="#setting-up-the-projects" aria-label="setting up the projects permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 projects</h2> <p>We will need two projects, one for the APIs and one for the client side. I will use <a href="https://cli.angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular CLI</a> for the client side. So let’s create them. I’m also using <a href="https://www.visualstudio.com/vs/whatsnew/" target="_blank" rel="nofollow noopener noreferrer">Visual Studio 2017</a> but feel free to use <a href="https://code.visualstudio.com/" target="_blank" rel="nofollow noopener noreferrer">Visual Studio Code</a> or even command line.</p> <p>After creating your solution, you will need to create a web API project targeting .NET CORE 2.0. Do not select an authentication scheme at this time since we will configure it shortly.</p> <p>Then create an empty web project and use whatever name you like. For now I’ve used API and Web as my preferred names. Your project structure should look something like this by now:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 902px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 43.333333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQBAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB1LMyiI0V/8QAGBABAQADAAAAAAAAAAAAAAAAAQAQERL/2gAIAQEAAQUC5bTI5b//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAAAIVH/2gAIAQIBAT8BUFD/xAAZEAACAwEAAAAAAAAAAAAAAAAAMgEgoZH/2gAIAQEABj8CXRNEjtP/xAAeEAAABAcAAAAAAAAAAAAAAAAAARHwEDFhcZGh0f/aAAgBAQABPyElTQrWFNhwL2NRnH//2gAMAwEAAgADAAAAEKsP/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERUf/aAAgBAwEBPxCPSPT/xAAVEQEBAAAAAAAAAAAAAAAAAAAAcf/aAAgBAgEBPxCCD//EABwQAAEEAwEAAAAAAAAAAAAAAAABESExEEFRcf/aAAgBAQABPxBQwpaUBtLSacjjKvw//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Project Structure" title="" src="/static/9c375beb27b5876574d19300575a8e3f/fc6fd/proj_structure.jpg" srcset="/static/9c375beb27b5876574d19300575a8e3f/6f81f/proj_structure.jpg 270w, /static/9c375beb27b5876574d19300575a8e3f/09d21/proj_structure.jpg 540w, /static/9c375beb27b5876574d19300575a8e3f/fc6fd/proj_structure.jpg 902w" sizes="(max-width: 902px) 100vw, 902px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </span></p> <h2 id="configuring-the-required-services" style="position:relative;"><a href="#configuring-the-required-services" aria-label="configuring the required services permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Configuring the required services</h2> <p>Once done open your <code class="language-text">Startup.cs</code> file and navigate to <code class="language-text">ConfigureServices</code> method. If you are wondering why please read my <a href="/2017-09-23-authentication-asp-net-core-2-0/">previous post</a> on the changes in ASP.NET Core 2.0.</p> <p>Before we can setup our authentication we need to setup our configuration with the values you gathered when setting up the active directory and the web API application (refer to my previous post). Open your <code class="language-text">appsettings.json</code> and add these lines:</p> <div class="gatsby-code-button-container" data-toaster-id="25865513617153303000" data-toaster-class="gatsby-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;AzureAd&quot;: { &quot;AADInstance&quot;: &quot;https://login.microsoftonline.com/&quot;, &quot;ClientId&quot;: &quot;ca81dd3d-4cd9-4b50-b451-74df7f8838d5&quot;, &quot;TenantId&quot;: &quot;db9af0e4-03ec-439b-a75b-01c54a5c9a04&quot; }`, `25865513617153303000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"AzureAd"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"AADInstance"</span><span class="token operator">:</span> <span class="token string">"https://login.microsoftonline.com/"</span><span class="token punctuation">,</span> <span class="token property">"ClientId"</span><span class="token operator">:</span> <span class="token string">"ca81dd3d-4cd9-4b50-b451-74df7f8838d5"</span><span class="token punctuation">,</span> <span class="token property">"TenantId"</span><span class="token operator">:</span> <span class="token string">"db9af0e4-03ec-439b-a75b-01c54a5c9a04"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>{: .box-note} <strong>Note:</strong> remember to replace the application and tenant Id with yours.</p> <p>Now navigate to <code class="language-text">ConfigureServices</code> method and add the authentication and authorisation services options as below:</p> <div class="gatsby-code-button-container" data-toaster-id="27797952286328620000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// Add Authentication services. //Configure Auth var clientId = Configuration[&quot;AzureAd:ClientId&quot;]; var tenantId = Configuration[&quot;AzureAd:TenantId&quot;]; var issuer = \$&quot;https://sts.windows.net/{tenantId}/&quot;; var serviceProvider = services.BuildServiceProvider(); var loggerFactory = serviceProvider.GetService<ILoggerFactory>(); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = &quot;https://login.microsoftonline.com/common/&quot;; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = issuer, ValidateAudience = true, ValidAudiences = new string[] { clientId }, ValidateLifetime = true }; options.Events = new MyJwtBearerEvents(loggerFactory.CreateLogger<MyJwtBearerEvents>()); options.SaveToken = true; }); services.AddAuthorization();`, `27797952286328620000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="cs"><pre style="counter-reset: linenumber NaN" class="language-cs line-numbers"><code class="language-cs"><span class="token comment">// Add Authentication services.</span> <span class="token comment">//Configure Auth</span> <span class="token class-name"><span class="token keyword">var</span></span> clientId <span class="token operator">=</span> Configuration<span class="token punctuation">[</span><span class="token string">"AzureAd:ClientId"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> tenantId <span class="token operator">=</span> Configuration<span class="token punctuation">[</span><span class="token string">"AzureAd:TenantId"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> issuer <span class="token operator">=</span> <span class="token interpolation-string"><span class="token string">$"https://sts.windows.net/</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">tenantId</span><span class="token punctuation">}</span></span><span class="token string">/"</span></span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> serviceProvider <span class="token operator">=</span> services<span class="token punctuation">.</span><span class="token function">BuildServiceProvider</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> loggerFactory <span class="token operator">=</span> serviceProvider<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetService</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ILoggerFactory<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> services<span class="token punctuation">.</span><span class="token function">AddAuthentication</span><span class="token punctuation">(</span>JwtBearerDefaults<span class="token punctuation">.</span>AuthenticationScheme<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AddJwtBearer</span><span class="token punctuation">(</span>options <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span>Authority <span class="token operator">=</span> <span class="token string">"https://login.microsoftonline.com/common/"</span><span class="token punctuation">;</span> options<span class="token punctuation">.</span>TokenValidationParameters <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">TokenValidationParameters</span> <span class="token punctuation">{</span> ValidateIssuer <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> ValidIssuer <span class="token operator">=</span> issuer<span class="token punctuation">,</span> ValidateAudience <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> ValidAudiences <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> clientId <span class="token punctuation">}</span><span class="token punctuation">,</span> ValidateLifetime <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> options<span class="token punctuation">.</span>Events <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">MyJwtBearerEvents</span><span class="token punctuation">(</span>loggerFactory<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">CreateLogger</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>MyJwtBearerEvents<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> options<span class="token punctuation">.</span>SaveToken <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> services<span class="token punctuation">.</span><span class="token function">AddAuthorization</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>To give you a bit of an intro to the code, we first retrieve the Azure AD configuration. Afterwards, we get an instance of <code class="language-text">ILogger</code> for logging purposes (you can skip this part if you like but you have to remove it from event handler as well).</p> <p>That done, we add the authentication to services instance and set a default scheme (in this case I am using <code class="language-text">JwtBearer</code>). Then have to configure our preferred option. This part is very straight forward so I am not going through the whole code.</p> <p>You can find the code for <code class="language-text">MyJwtBearerEvents</code> <a href="https://github.com/yashints/Angular4AzureAD/blob/master/API/MyJwtBearerEvents.cs" target="_blank" rel="nofollow noopener noreferrer">here</a>.</p> <p>It’s time to let ASP.NET Core know it should use authentication. This is an important step since without it the whole setup won’t work. Head to <code class="language-text">Configure</code> method and add the middleware:</p> <div class="gatsby-code-button-container" data-toaster-id="38074045088186790000" data-toaster-class="gatsby-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.UseAuthentication();`, `38074045088186790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp">app<span class="token punctuation">.</span><span class="token function">UseAuthentication</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>We’re done with configuration at this point, time to secure our API. I’ve got a <code class="language-text">ValuesController</code> which I will add the <code class="language-text">Auhorize</code> attribute to it:</p> <div class="gatsby-code-button-container" data-toaster-id="47370772021057815000" data-toaster-class="gatsby-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.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; namespace API.Controllers { [Route(&quot;api/[controller]&quot;)] [Authorize] public class ValuesController : Controller { // GET api/values [HttpGet] public IEnumerable&lt;string&gt; Get() { return new string[] { &quot;value1&quot;, &quot;value2&quot; }; } //... other methods } }`, `47370772021057815000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Collections<span class="token punctuation">.</span>Generic</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>AspNetCore<span class="token punctuation">.</span>Mvc</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>AspNetCore<span class="token punctuation">.</span>Authorization</span><span class="token punctuation">;</span> <span class="token keyword">namespace</span> <span class="token namespace">API<span class="token punctuation">.</span>Controllers</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Route</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"api/[controller]"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Authorize</span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ValuesController</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Controller</span></span> <span class="token punctuation">{</span> <span class="token comment">// GET api/values</span> <span class="token punctuation">[</span>HttpGet<span class="token punctuation">]</span> <span class="token keyword">public</span> IEnumerable<span class="token operator">&amp;</span>lt<span class="token punctuation">;</span><span class="token keyword">string</span><span class="token operator">&amp;</span>gt<span class="token punctuation">;</span> <span class="token function">Get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token string">"value1"</span><span class="token punctuation">,</span> <span class="token string">"value2"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//... other methods</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="creating-the-client-side" style="position:relative;"><a href="#creating-the-client-side" aria-label="creating the client side permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 client side</h2> <p>Alright, now that the server side is secured, let set up our client side to use Azure AD authentication.</p> <p>We will start by initialising our project. Head to Web folder and open a console (you will need to have <code class="language-text">nodejs</code>, <code class="language-text">npm</code> and <code class="language-text">AngularCLI</code> installed globally). Run this command to create an application (I am using skip install flag because I need to add some packages before installing the default ones):</p> <div class="gatsby-code-button-container" data-toaster-id="43797402462906106000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng new spa --skip-install`, `43797402462906106000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng new spa --skip-install</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now go to spa folder and cut and paste everything to root of the Web folder (this is for simplicity and ease of use). Lets add all the required packages by adding them to <code class="language-text">package.json</code> file. Open it up and add these lines to dependencies section:</p> <div class="gatsby-code-button-container" data-toaster-id="33851699528702550000" data-toaster-class="gatsby-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;adal-angular4&quot;: &quot;^1.1.10&quot;, &quot;bootstrap&quot;: &quot;^3.3.7&quot;,`, `33851699528702550000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"adal-angular4"</span><span class="token operator">:</span> <span class="token string">"^1.1.10"</span><span class="token punctuation">,</span> <span class="token property">"bootstrap"</span><span class="token operator">:</span> <span class="token string">"^3.3.7"</span><span class="token punctuation">,</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>The <a href="https://github.com/benbaran/adal-angular4" target="_blank" rel="nofollow noopener noreferrer">first package</a> is a wrapper around <a href="https://github.com/AzureAD/azure-activedirectory-library-for-js" target="_blank" rel="nofollow noopener noreferrer">adal</a> which is used to authenticate to Azure Active Directory. I will show you how we use it later.</p> <p>Now run:</p> <div class="gatsby-code-button-container" data-toaster-id="24728144425143530000" data-toaster-class="gatsby-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`, `24728144425143530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Once finished, we need to define some routes for the application so we can secure a particular one. Protecting routes is a very common task when building applications, as we want to prevent our users from accessing areas that they’re not allowed to access, or, we might want to ask them for confirmation when leaving a certain area. Angular router provides a feature called <strong>Route Guards</strong> that try to solve exactly that problem.</p> <p>Here is how our guard looks like:</p> <div class="gatsby-code-button-container" data-toaster-id="74035463686425260000" data-toaster-class="gatsby-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 { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Router, CanActivate, CanActivateChild, ActivatedRouteSnapshot, RouterStateSnapshot, NavigationExtras } from '@angular/router'; import { Adal4Service } from 'adal-angular4'; @Injectable() export class AuthGuard implements CanActivate, CanActivateChild { constructor( private router: Router, private adalSvc: Adal4Service ) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { if (this.adalSvc.userInfo.authenticated) { return true; } else { this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); return false; } } canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { return this.canActivate(childRoute, state); } }`, `74035463686425260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Observable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs/Observable'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Router<span class="token punctuation">,</span> CanActivate<span class="token punctuation">,</span> CanActivateChild<span class="token punctuation">,</span> ActivatedRouteSnapshot<span class="token punctuation">,</span> RouterStateSnapshot<span class="token punctuation">,</span> NavigationExtras <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Adal4Service <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'adal-angular4'</span><span class="token punctuation">;</span> @<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AuthGuard</span> <span class="token keyword">implements</span> <span class="token class-name">CanActivate</span><span class="token punctuation">,</span> CanActivateChild <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span> <span class="token parameter"><span class="token keyword">private</span> <span class="token literal-property property">router</span><span class="token operator">:</span> Router<span class="token punctuation">,</span> <span class="token keyword">private</span> <span class="token literal-property property">adalSvc</span><span class="token operator">:</span> Adal4Service</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token function">canActivate</span><span class="token punctuation">(</span>route<span class="token operator">:</span> ActivatedRouteSnapshot<span class="token punctuation">,</span> <span class="token literal-property property">state</span><span class="token operator">:</span> RouterStateSnapshot<span class="token punctuation">)</span><span class="token operator">:</span> boolean <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>adalSvc<span class="token punctuation">.</span>userInfo<span class="token punctuation">.</span>authenticated<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">else</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>router<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'/login'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">queryParams</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">returnUrl</span><span class="token operator">:</span> state<span class="token punctuation">.</span>url <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> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">canActivateChild</span><span class="token punctuation">(</span>childRoute<span class="token operator">:</span> ActivatedRouteSnapshot<span class="token punctuation">,</span> <span class="token literal-property property">state</span><span class="token operator">:</span> RouterStateSnapshot<span class="token punctuation">)</span><span class="token operator">:</span> boolean <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">canActivate</span><span class="token punctuation">(</span>childRoute<span class="token punctuation">,</span> state<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see I am using one of the packages we added earlier which helps configure our application to authenticate to Azure AD.</p> <p>Now that we have our guard, let create our routing (I’ve already added three components to the application called home, login and values):</p> <div class="gatsby-code-button-container" data-toaster-id="71997311459994240000" data-toaster-class="gatsby-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 { Routes, RouterModule } from '@angular/router' import { HomeComponent } from './components/home/home.component' import { LoginComponent } from './components/login/login.component' import { AuthGuard } from './services/authguard.service' import { ValuesComponent } from './components/values/values.component' const appRoutes: Routes = [ { path: '', component: HomeComponent }, { path: 'login', component: LoginComponent }, { path: 'values', component: ValuesComponent, canActivate: [AuthGuard] }, // otherwise redirect to home { path: '**', redirectTo: '' }, ] export const routing = RouterModule.forRoot(appRoutes)`, `71997311459994240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Routes<span class="token punctuation">,</span> RouterModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> HomeComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./components/home/home.component'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> LoginComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./components/login/login.component'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> AuthGuard <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./services/authguard.service'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ValuesComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./components/values/values.component'</span> <span class="token keyword">const</span> <span class="token literal-property property">appRoutes</span><span class="token operator">:</span> Routes <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> HomeComponent <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'login'</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> LoginComponent <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'values'</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> ValuesComponent<span class="token punctuation">,</span> <span class="token literal-property property">canActivate</span><span class="token operator">:</span> <span class="token punctuation">[</span>AuthGuard<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// otherwise redirect to home</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'**'</span><span class="token punctuation">,</span> <span class="token literal-property property">redirectTo</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 keyword">export</span> <span class="token keyword">const</span> routing <span class="token operator">=</span> RouterModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span>appRoutes<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now we can add our routing module to our application. Open the <code class="language-text">app.module.ts</code> file and import and add router to it:</p> <div class="gatsby-code-button-container" data-toaster-id="68930586689670600000" data-toaster-class="gatsby-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 { routing } from './app-routing'; ... imports: [ routing ]`, `68930586689670600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> routing <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./app-routing'</span><span class="token punctuation">;</span> <span class="token operator">...</span> <span class="token literal-property property">imports</span><span class="token operator">:</span> <span class="token punctuation">[</span> routing <span class="token punctuation">]</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We will need a login component which will handle the unauthorised requests:</p> <div class="gatsby-code-button-container" data-toaster-id="31113019934912000000" data-toaster-class="gatsby-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 { Component } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Adal4Service } from 'adal-angular4'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent { constructor( private route: ActivatedRoute, private router: Router, private adalSvc: Adal4Service ) { } login(): void { const returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/'; if (this.adalSvc.userInfo.authenticated) { this.router.navigate([returnUrl]); } else { this.adalSvc.login(); } } }`, `31113019934912000000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ActivatedRoute<span class="token punctuation">,</span> Router <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Adal4Service <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'adal-angular4'</span><span class="token punctuation">;</span> @<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">selector</span><span class="token operator">:</span> <span class="token string">'app-login'</span><span class="token punctuation">,</span> <span class="token literal-property property">templateUrl</span><span class="token operator">:</span> <span class="token string">'./login.component.html'</span><span class="token punctuation">,</span> <span class="token literal-property property">styleUrls</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'./login.component.css'</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">class</span> <span class="token class-name">LoginComponent</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span> <span class="token parameter"><span class="token keyword">private</span> <span class="token literal-property property">route</span><span class="token operator">:</span> ActivatedRoute<span class="token punctuation">,</span> <span class="token keyword">private</span> <span class="token literal-property property">router</span><span class="token operator">:</span> Router<span class="token punctuation">,</span> <span class="token keyword">private</span> <span class="token literal-property property">adalSvc</span><span class="token operator">:</span> Adal4Service</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> returnUrl <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>route<span class="token punctuation">.</span>snapshot<span class="token punctuation">.</span>queryParams<span class="token punctuation">[</span><span class="token string">'returnUrl'</span><span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token string">'/'</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>adalSvc<span class="token punctuation">.</span>userInfo<span class="token punctuation">.</span>authenticated<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>router<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token punctuation">[</span>returnUrl<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">this</span><span class="token punctuation">.</span>adalSvc<span class="token punctuation">.</span><span class="token function">login</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Very straightforward, we just call login method on clicking a button. Of course you can do it on load without need to have a button, this will just makes debugging a bit easier.</p> <p>At this point let’s add the Azure configuration to our app. First we need to define the same Azure configuration that we used for our ASP.NET Core application. So head to your environments.ts and add them:</p> <div class="gatsby-code-button-container" data-toaster-id="26167687642257940000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export const environment = { production: false, azureConfig: { tenant: 'tenantname.onmicrosoft.com', clientId: 'ca81dd3d-4cd9-4b50-b451-74df7f8838d5', postLogoutRedirectUri: 'http://localhost:4200/', }, }`, `26167687642257940000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> environment <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">production</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">azureConfig</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tenant</span><span class="token operator">:</span> <span class="token string">'tenantname.onmicrosoft.com'</span><span class="token punctuation">,</span> <span class="token literal-property property">clientId</span><span class="token operator">:</span> <span class="token string">'ca81dd3d-4cd9-4b50-b451-74df7f8838d5'</span><span class="token punctuation">,</span> <span class="token literal-property property">postLogoutRedirectUri</span><span class="token operator">:</span> <span class="token string">'http://localhost:4200/'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The <code class="language-text">adal-angular4</code> requires the tenant Id and client id (which is the same as application id) and a post back URL. Remember that we’ve set the same when creating the application on Azure AD.</p> <p>Alright, time to initialise this service. Open up your <code class="language-text">app.component.ts</code> file and import the <code class="language-text">Adal4Service</code> from this package, then call init method and pass the above config to it:</p> <div class="gatsby-code-button-container" data-toaster-id="81442771719077410000" data-toaster-class="gatsby-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 { Adal4Service } from 'adal-angular4'; import { Router } from '@angular/router'; import { environment } from '../environments/environment'; export class AppComponent implements OnInit { isLoggedIn: boolean = false; constructor(private adalSvc: Adal4Service, private router: Router) { this.adalSvc.init(environment.azureConfig); } ngOnInit(): void { this.adalSvc.handleWindowCallback(); this.isLoggedIn = this.adalSvc.userInfo.authenticated; } logout(): void { this.adalSvc.logOut(); } }`, `81442771719077410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Adal4Service <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'adal-angular4'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Router <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> environment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../environments/environment'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppComponent</span> <span class="token keyword">implements</span> <span class="token class-name">OnInit</span> <span class="token punctuation">{</span> <span class="token literal-property property">isLoggedIn</span><span class="token operator">:</span> boolean <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter"><span class="token keyword">private</span> <span class="token literal-property property">adalSvc</span><span class="token operator">:</span> Adal4Service<span class="token punctuation">,</span> <span class="token keyword">private</span> <span class="token literal-property property">router</span><span class="token operator">:</span> Router</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>adalSvc<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>environment<span class="token punctuation">.</span>azureConfig<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">ngOnInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>adalSvc<span class="token punctuation">.</span><span class="token function">handleWindowCallback</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>isLoggedIn <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>adalSvc<span class="token punctuation">.</span>userInfo<span class="token punctuation">.</span>authenticated<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">logout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>adalSvc<span class="token punctuation">.</span><span class="token function">logOut</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Because of that post back URL we’ve defined, we also need to handle the login callback coming from Azure AD. We do this by calling <code class="language-text">handleWindowCallback</code> from the aforementioned service on init.</p> <p>Let’s define the HTML for the app component as well:</p> <div class="gatsby-code-button-container" data-toaster-id="42266941010770354000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<nav class=&quot;navbar navbar-inverse&quot;> <div class=&quot;container-fluid&quot;> <div class=&quot;navbar-header&quot;> <a class=&quot;navbar-brand&quot; href=&quot;#&quot;>SPA App with Azure AD login</a> </div> <ul class=&quot;nav navbar-nav&quot;> <li><a [routerLink]=&quot;['/']&quot;>Home</a></li> <li><a [routerLink]=&quot;['/values']&quot;>Values</a></li> </ul> <ul class=&quot;nav navbar-nav navbar-right&quot;> <li *ngIf=&quot;!isLoggedIn&quot;> <a [routerLink]=&quot;['/login']&quot; ><span class=&quot;glyphicon glyphicon-log-in&quot;></span> Login</a > </li> <li *ngIf=&quot;isLoggedIn&quot;> <a (click)=&quot;logout()&quot; ><span class=&quot;glyphicon glyphicon-log-out&quot;></span> Logout</a > </li> </ul> </div> </nav> <div class=&quot;container-fluid&quot;> <div style=&quot;padding-top: 61px;&quot;></div> <router-outlet></router-outlet> </div>`, `42266941010770354000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><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>navbar navbar-inverse<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>container-fluid<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>navbar-header<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">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>navbar-brand<span class="token punctuation">"</span></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 punctuation">></span></span>SPA App with Azure AD login<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>ul</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>nav navbar-nav<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>li</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">[routerLink]</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>Home<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>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</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">[routerLink]</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>['/values']<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Values<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>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</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>nav navbar-nav navbar-right<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>li</span> <span class="token attr-name">*ngIf</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!isLoggedIn<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">[routerLink]</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><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>glyphicon glyphicon-log-in<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 punctuation">></span></span> Login<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>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">*ngIf</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>isLoggedIn<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">(click)</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logout()<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>glyphicon glyphicon-log-out<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 punctuation">></span></span> Logout<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>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</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 attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container-fluid<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 special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">padding-top</span><span class="token punctuation">:</span> 61px<span class="token punctuation">;</span></span><span class="token punctuation">"</span></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>router-outlet</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-outlet</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It is very simple. We have a menu which is pointing to our routes, a login/logout button which is shown based on user current status, and the router outlet which will load the correspondent component.</p> <p>Let’s create our services which are required to finish our application. First we will need a base service which can extract the token from user object and add it to request header as bearer token:</p> <div class="gatsby-code-button-container" data-toaster-id="2781876704310826000" data-toaster-class="gatsby-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 { Http, Response, Headers } from '@angular/http'; import { Inject, Injectable } from '@angular/core'; import 'rxjs/Rx'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/throw'; import { Observer } from 'rxjs/Observer'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; import { Adal4Service } from 'adal-angular4'; import { APP_CONFIG, AppConfig } from '../app.constants'; @Injectable() export class SecureHttpService<T> { headers: Headers; constructor(private http: Http, private apiEndPointUrl: string, private adalService: Adal4Service) { this.headers = new Headers({ 'Content-Type': 'application/json' }); let jwt = this.adalService.userInfo.token; this.headers.append('Authorization', 'Bearer ' + jwt); } getAll(): Observable<any> { return this.http.get(this.apiEndPointUrl, { headers: this.headers }).map( (res: Response) => { return res.json() as any[]; }).catch(this.handleError); } get(id: number): Observable<any> { return this.http.get(this.apiEndPointUrl + '/' + id).map((value, i) => { return <T>value.json() }) .catch(this.handleError); } private handleError(error: any) { console.error('server error:', error); if (error instanceof Response) { let errMessage = ''; try { errMessage = error.json().error; } catch (err) { errMessage = error.statusText; } return Observable.throw(errMessage); } return Observable.throw(error || 'server error'); } }`, `2781876704310826000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Http<span class="token punctuation">,</span> Response<span class="token punctuation">,</span> Headers <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/http'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Inject<span class="token punctuation">,</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'rxjs/Rx'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Observable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs/Observable'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'rxjs/add/observable/throw'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Observer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs/Observer'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'rxjs/add/operator/map'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'rxjs/add/operator/catch'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Adal4Service <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'adal-angular4'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">APP_CONFIG</span><span class="token punctuation">,</span> AppConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../app.constants'</span><span class="token punctuation">;</span> @<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">SecureHttpService</span><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> Headers<span class="token punctuation">;</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter"><span class="token keyword">private</span> <span class="token literal-property property">http</span><span class="token operator">:</span> Http<span class="token punctuation">,</span> <span class="token keyword">private</span> <span class="token literal-property property">apiEndPointUrl</span><span class="token operator">:</span> string<span class="token punctuation">,</span> <span class="token keyword">private</span> <span class="token literal-property property">adalService</span><span class="token operator">:</span> Adal4Service</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>headers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Headers</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token string-property property">'Content-Type'</span><span class="token operator">:</span> <span class="token string">'application/json'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> jwt <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>adalService<span class="token punctuation">.</span>userInfo<span class="token punctuation">.</span>token<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>headers<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'Authorization'</span><span class="token punctuation">,</span> <span class="token string">'Bearer '</span> <span class="token operator">+</span> jwt<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span>any<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>http<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>apiEndPointUrl<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>headers <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">res</span><span class="token operator">:</span> Response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> any<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>handleError<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">get</span><span class="token punctuation">(</span>id<span class="token operator">:</span> number<span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span>any<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>http<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>apiEndPointUrl <span class="token operator">+</span> <span class="token string">'/'</span> <span class="token operator">+</span> id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">value<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">></span>value<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> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>handleError<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token function">handleError</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">error</span><span class="token operator">:</span> any</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'server error:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>error <span class="token keyword">instanceof</span> <span class="token class-name">Response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> errMessage <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> errMessage <span class="token operator">=</span> error<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>error<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> errMessage <span class="token operator">=</span> error<span class="token punctuation">.</span>statusText<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> Observable<span class="token punctuation">.</span><span class="token function">throw</span><span class="token punctuation">(</span>errMessage<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> Observable<span class="token punctuation">.</span><span class="token function">throw</span><span class="token punctuation">(</span>error <span class="token operator">||</span> <span class="token string">'server error'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I am using a generic class which can be used later using <a href="https://www.typescriptlang.org/" target="_blank" rel="nofollow noopener noreferrer">TypeScript</a> features (which I love). In the constructor we need an instance of <code class="language-text">HTTP</code> service, the base URL and the <code class="language-text">Adal4Service</code> to extract the token from.</p> <p>Now let’s add our values service:</p> <div class="gatsby-code-button-container" data-toaster-id="63263795286107820000" data-toaster-class="gatsby-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 { Injectable, Inject } from '@angular/core' import { Http } from '@angular/http' import { APP_CONFIG, AppConfig } from '../app.constants' import { Adal4Service } from 'adal-angular4' import { SecureHttpService } from './secure-http.service' @Injectable() export class ValuesService extends SecureHttpService<string> { constructor( http: Http, @Inject(APP_CONFIG) appConfig: AppConfig, adalService: Adal4Service ) { super(http, appConfig.baseUrl + 'values', adalService) } }`, `63263795286107820000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable<span class="token punctuation">,</span> Inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Http <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/http'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">APP_CONFIG</span><span class="token punctuation">,</span> AppConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../app.constants'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Adal4Service <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'adal-angular4'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> SecureHttpService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./secure-http.service'</span> @<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ValuesService</span> <span class="token keyword">extends</span> <span class="token class-name">SecureHttpService</span><span class="token operator">&lt;</span>string<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span> <span class="token parameter"><span class="token literal-property property">http</span><span class="token operator">:</span> Http<span class="token punctuation">,</span> @<span class="token function">Inject</span><span class="token punctuation">(</span><span class="token constant">APP_CONFIG</span><span class="token punctuation">)</span> appConfig<span class="token operator">:</span> AppConfig<span class="token punctuation">,</span> <span class="token literal-property property">adalService</span><span class="token operator">:</span> Adal4Service</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span>http<span class="token punctuation">,</span> appConfig<span class="token punctuation">.</span>baseUrl <span class="token operator">+</span> <span class="token string">'values'</span><span class="token punctuation">,</span> adalService<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now you know what was the benefit of having that generic class, it’s superb isn’t it?</p> <div class="custom-block info"><div class="custom-block-body"><strong>Note:</strong> I am using an config object which can be injected anywhere.</div></div> <p>The source code for that is very simple:</p> <div class="gatsby-code-button-container" data-toaster-id="56617274419715930000" data-toaster-class="gatsby-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 { InjectionToken, NgModule } from '@angular/core' export class AppConfig { baseUrl: string } export const APP_CONSTANTS: AppConfig = { baseUrl: 'http://localhost:4200/api/', } export let APP_CONFIG = new InjectionToken() < AppConfig > 'app.config' @NgModule({ providers: [ { provide: APP_CONFIG, useValue: APP_CONSTANTS, }, ], }) export class AppConfigModule {}`, `56617274419715930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> InjectionToken<span class="token punctuation">,</span> NgModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppConfig</span> <span class="token punctuation">{</span> <span class="token literal-property property">baseUrl</span><span class="token operator">:</span> string <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token constant">APP_CONSTANTS</span><span class="token operator">:</span> AppConfig <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">baseUrl</span><span class="token operator">:</span> <span class="token string">'http://localhost:4200/api/'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">let</span> <span class="token constant">APP_CONFIG</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InjectionToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> AppConfig <span class="token operator">></span> <span class="token string">'app.config'</span> @<span class="token function">NgModule</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">providers</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">provide</span><span class="token operator">:</span> <span class="token constant">APP_CONFIG</span><span class="token punctuation">,</span> <span class="token literal-property property">useValue</span><span class="token operator">:</span> <span class="token constant">APP_CONSTANTS</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">export</span> <span class="token keyword">class</span> <span class="token class-name">AppConfigModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Alright, time to consume the values service in the values component:</p> <div class="gatsby-code-button-container" data-toaster-id="87784955731805040000" data-toaster-class="gatsby-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 { Component } from '@angular/core'; import { ValuesService } from '../../services/values.service'; @Component({ selector: 'app-values', templateUrl: './values.component.html', styleUrls: ['./values.component.css'] }) export class ValuesComponent { values: Array<string>; constructor(private service: ValuesService) { this.service.getAll().subscribe(x => this.values = x); } }`, `87784955731805040000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ValuesService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../../services/values.service'</span><span class="token punctuation">;</span> @<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">selector</span><span class="token operator">:</span> <span class="token string">'app-values'</span><span class="token punctuation">,</span> <span class="token literal-property property">templateUrl</span><span class="token operator">:</span> <span class="token string">'./values.component.html'</span><span class="token punctuation">,</span> <span class="token literal-property property">styleUrls</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'./values.component.css'</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">class</span> <span class="token class-name">ValuesComponent</span> <span class="token punctuation">{</span> <span class="token literal-property property">values</span><span class="token operator">:</span> Array<span class="token operator">&lt;</span>string<span class="token operator">></span><span class="token punctuation">;</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter"><span class="token keyword">private</span> <span class="token literal-property property">service</span><span class="token operator">:</span> ValuesService</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>service<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span>values <span class="token operator">=</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And the HTML:</p> <div class="gatsby-code-button-container" data-toaster-id="73246023607628000000" data-toaster-class="gatsby-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;col-xs-12&quot;> <h1>You're in, well done...</h1> <div class=&quot;well&quot;> <ul> <li *ngFor=&quot;let value of values&quot;>{{value}}</li> </ul> </div> </div>`, `73246023607628000000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>col-xs-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>h1</span><span class="token punctuation">></span></span>You're in, well done...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</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>well<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>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">*ngFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>let value of values<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{value}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <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 is not time to glue everything together. Open your app.module.ts and add all the services you need (components will get added when you add them using <code class="language-text">ng g component</code> command):</p> <div class="gatsby-code-button-container" data-toaster-id="23971633911080858000" data-toaster-class="gatsby-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 { BrowserModule } from '@angular/platform-browser' import { NgModule } from '@angular/core' import { Adal4Service, Adal4HTTPService } from 'adal-angular4' import { HttpModule, Http } from '@angular/http' import { AppComponent } from './app.component' import { HomeComponent } from './components/home/home.component' import { LoginComponent } from './components/login/login.component' import { ValuesComponent } from './components/values/values.component' import { AppConfigModule } from './app.constants' import { AuthGuard } from './services/authguard.service' import { routing } from './app-routing' import { ValuesService } from './services/values.service' import { SecureHttpService } from './services/secure-http.service' @NgModule({ declarations: [AppComponent, HomeComponent, LoginComponent, ValuesComponent], imports: [BrowserModule, AppConfigModule, HttpModule, routing], providers: [ AuthGuard, SecureHttpService, ValuesService, Adal4Service, { provide: Adal4HTTPService, useFactory: Adal4HTTPService.factory, deps: [Http, Adal4Service], }, ], bootstrap: [AppComponent], }) export class AppModule {}`, `23971633911080858000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> BrowserModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/platform-browser'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> NgModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Adal4Service<span class="token punctuation">,</span> Adal4HTTPService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'adal-angular4'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> HttpModule<span class="token punctuation">,</span> Http <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/http'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> AppComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./app.component'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> HomeComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./components/home/home.component'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> LoginComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./components/login/login.component'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ValuesComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./components/values/values.component'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> AppConfigModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./app.constants'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> AuthGuard <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./services/authguard.service'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> routing <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./app-routing'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ValuesService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./services/values.service'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> SecureHttpService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./services/secure-http.service'</span> @<span class="token function">NgModule</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">declarations</span><span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<span class="token punctuation">,</span> HomeComponent<span class="token punctuation">,</span> LoginComponent<span class="token punctuation">,</span> ValuesComponent<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">imports</span><span class="token operator">:</span> <span class="token punctuation">[</span>BrowserModule<span class="token punctuation">,</span> AppConfigModule<span class="token punctuation">,</span> HttpModule<span class="token punctuation">,</span> routing<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">providers</span><span class="token operator">:</span> <span class="token punctuation">[</span> AuthGuard<span class="token punctuation">,</span> SecureHttpService<span class="token punctuation">,</span> ValuesService<span class="token punctuation">,</span> Adal4Service<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">provide</span><span class="token operator">:</span> Adal4HTTPService<span class="token punctuation">,</span> <span class="token literal-property property">useFactory</span><span class="token operator">:</span> Adal4HTTPService<span class="token punctuation">.</span>factory<span class="token punctuation">,</span> <span class="token literal-property property">deps</span><span class="token operator">:</span> <span class="token punctuation">[</span>Http<span class="token punctuation">,</span> Adal4Service<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 literal-property property">bootstrap</span><span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<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">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see we’ve provided all the required service we added. Also configured the <code class="language-text">Adal4HTTPService</code> which then will get used by <code class="language-text">Adal4Service</code> and specified its dependencies.</p> <h2 id="proxy" style="position:relative;"><a href="#proxy" aria-label="proxy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Proxy</h2> <p>Since we are using two different project we will need to let Angular CLI know when to delegate the requests to our ASP.NET Core APIs. For that you can simply create a proxy and use it when using <code class="language-text">ng serve</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="61395503391557345000" data-toaster-class="gatsby-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;/api&quot;: { &quot;target&quot;: &quot;http://localhost:51009/&quot;, &quot;secure&quot;: false } }`, `61395503391557345000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"/api"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"target"</span><span class="token operator">:</span> <span class="token string">"http://localhost:51009/"</span><span class="token punctuation">,</span> <span class="token property">"secure"</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The port defined above need to be the port that is used to lunch you API application. Also you will need to let ng know it should use a proxy. Open your <code class="language-text">package.json</code> and replace <code class="language-text">ng serve</code> with:</p> <div class="gatsby-code-button-container" data-toaster-id="34988319589232520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`ng serve --proxy-config proxy.conf.json`, `34988319589232520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash">ng serve --proxy-config proxy.conf.json</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now run <code class="language-text">dotnet run</code> in root of APIs and run <code class="language-text">npm start</code> from the root of the Web folder. And it is all done. When you click on values menu you will be redirected to your Azure AD where you can login and then you will be redirected back to your application and the values will be loaded.</p> <p>Hope you will benefit from this post and remember to spread it (<a href="https://goo.gl/LnbzSB" target="_blank" rel="nofollow noopener noreferrer">short link</a>) where you see fit.</p> <p>Again the complete source code can be found on my <a href="https://github.com/yashints/Angular4AzureAD" target="_blank" rel="nofollow noopener noreferrer">GitHub repository</a>.</p> <p>Hope you’ve enjoyed this article.</p><![CDATA[Authentication in ASP.NET Core 2.0]]>https://yashints.dev/blog/2017/09/23/authentication-asp-net-core-2-0https://yashints.dev/blog/2017/09/23/authentication-asp-net-core-2-0Sat, 23 Sep 2017 00:00:00 GMT<p>As you might know the <a href="https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-net-core-2-0/" target="_blank" rel="nofollow noopener noreferrer">.NET Core 2.0</a> was release recently and with it come many improvements and changes. In this post I will point out a couple of changes from a security and authentication perspective.</p> <!--more--> <h2 id="authentication" style="position:relative;"><a href="#authentication" aria-label="authentication permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Authentication</h2> <p>If you have previously used any form of authentication in ASP.NET Core 1.0, you would know that in order to configure your preferred mechanism you have to call one of the middle-wares available. For example if you wanted to use cookie authentication (local) this is how it would look like:</p> <div class="gatsby-code-button-container" data-toaster-id="43556994694428930000" data-toaster-class="gatsby-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.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = &quot;Cookie&quot;, LoginPath = new PathString(&quot;/Account/Login/&quot;), AccessDeniedPath = new PathString(&quot;/Account/Forbidden/&quot;), AutomaticAuthenticate = true, AutomaticChallenge = true });`, `43556994694428930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="cs"><pre style="counter-reset: linenumber NaN" class="language-cs line-numbers"><code class="language-cs">app<span class="token punctuation">.</span><span class="token function">UseCookieAuthentication</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">CookieAuthenticationOptions</span> <span class="token punctuation">{</span> AuthenticationScheme <span class="token operator">=</span> <span class="token string">"Cookie"</span><span class="token punctuation">,</span> LoginPath <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PathString</span><span class="token punctuation">(</span><span class="token string">"/Account/Login/"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> AccessDeniedPath <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PathString</span><span class="token punctuation">(</span><span class="token string">"/Account/Forbidden/"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> AutomaticAuthenticate <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> AutomaticChallenge <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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>This basically means that you are letting ASP.Net know that you want to use cookie authentication with a specific login/access denied path. Also you want to enable automatic authenticate which means the <code class="language-text">middleware</code> will run on every inbound request, look for a cookie and if one is present it will validate it, and if valid create an identity from it and add it to the current user.</p> <p>I will not go through more details as it is not the purpose of this post but you can find all the details on <a href="https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?tabs=visual-studio%2Caspnetcore2x" target="_blank" rel="nofollow noopener noreferrer">Microsoft Official Documentation</a>. Same thing is true if you wanted to use <a href="https://blogs.msdn.microsoft.com/webdev/2017/04/06/jwt-validation-and-authorization-in-asp-net-core/" target="_blank" rel="nofollow noopener noreferrer">JWT bearer</a> or any other form of authentication.</p> <div class="gatsby-code-button-container" data-toaster-id="32691608107258440000" data-toaster-class="gatsby-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.UseJwtBearerAuthentication(new JwtBearerOptions() { Audience = &quot;http://localhost:5001/&quot;, Authority = &quot;http://localhost:5000/&quot;, AutomaticAuthenticate = true });`, `32691608107258440000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="cs"><pre style="counter-reset: linenumber NaN" class="language-cs line-numbers"><code class="language-cs">app<span class="token punctuation">.</span><span class="token function">UseJwtBearerAuthentication</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">JwtBearerOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Audience <span class="token operator">=</span> <span class="token string">"http://localhost:5001/"</span><span class="token punctuation">,</span> Authority <span class="token operator">=</span> <span class="token string">"http://localhost:5000/"</span><span class="token punctuation">,</span> AutomaticAuthenticate <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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Remember that you can use multiple middle wares in conjunction to support more complex scenarios.</p> <p>However, this has changed quite a bit in version 2.0 in a sense that all of these has been combined into a single service which you will need to configure. Also they have moved from <code class="language-text">Microsoft.AspNetCore.Http.Authentication</code> namespace to <code class="language-text">Microsoft.AspNetCore.Authentication</code>.</p> <p>Also instead of calling <code class="language-text">context.Authentication.Authenticate|Challenge|SignInAsync</code> you will call them on context directly like <code class="language-text">context.Authenticate|Challenge|SignInAsync</code>.</p> <p>That said if you just change your framework you will get a compile error which is awesome:</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/18a85a5f54cdedd2805e560b026f82d2/37c35/obsoleteauth.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 20.37037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAACE3AAAhNwEzWJ96AAAApUlEQVR42oWL2QqDMBRE/f+fk1i7ucSbZtFu8UZvkpaKXSn0rYfhMDBM4pzTRkrFpapBFLwRRlnFGwU7s9MS5NPDGHDwiMM7oxuox/F6vSXeewAwpt0fHIeWZas0W7J0scjWLN+yfMOWRV6KWpiyasoKqlqA0E+Tj68zfwMguq7Xh3h0MXh/cS4iRmsj0TRN9x/mef6UhIhOpzMiWmtppBDu3+k/D9P33tGHEAz5AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Obsolete Authentication Option" title="" src="/static/18a85a5f54cdedd2805e560b026f82d2/302a4/obsoleteauth.png" srcset="/static/18a85a5f54cdedd2805e560b026f82d2/01bf6/obsoleteauth.png 270w, /static/18a85a5f54cdedd2805e560b026f82d2/07484/obsoleteauth.png 540w, /static/18a85a5f54cdedd2805e560b026f82d2/302a4/obsoleteauth.png 1080w, /static/18a85a5f54cdedd2805e560b026f82d2/0d292/obsoleteauth.png 1620w, /static/18a85a5f54cdedd2805e560b026f82d2/37c35/obsoleteauth.png 1810w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>To achieve the above scenario you will need to first configure the service:</p> <div class="gatsby-code-button-container" data-toaster-id="76125407163785970000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.LoginPath = new PathString(&quot;/Account/Login/&quot;); options.AccessDeniedPath = new PathString(&quot;/Account/Forbidden/&quot;); });`, `76125407163785970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp">services<span class="token punctuation">.</span><span class="token function">AddAuthentication</span><span class="token punctuation">(</span>CookieAuthenticationDefaults<span class="token punctuation">.</span>AuthenticationScheme<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AddCookie</span><span class="token punctuation">(</span>CookieAuthenticationDefaults<span class="token punctuation">.</span>AuthenticationScheme<span class="token punctuation">,</span> options <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span>LoginPath <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PathString</span><span class="token punctuation">(</span><span class="token string">"/Account/Login/"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> options<span class="token punctuation">.</span>AccessDeniedPath <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PathString</span><span class="token punctuation">(</span><span class="token string">"/Account/Forbidden/"</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>It is very similar to how you used to configure your cookie authentication middle ware, except that you now have to define a default scheme in the constructor of the service. In above we’ve configured the default to be <code class="language-text">CookieAuthenticationDefaults.AuthenticationScheme</code>.</p> <p>There is a <strong>catch</strong> here, and that is just be defining the service configuration your application will not use authentication, you will need add <code class="language-text">app.UseAuthentication();</code> at the top of the <code class="language-text">Configure()</code> method.</p> <div class="gatsby-code-button-container" data-toaster-id="88217466349161230000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// This method gets called by the runtime. Use this method to // configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseAuthentication(); }`, `88217466349161230000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token comment">// This method gets called by the runtime. Use this method to</span> <span class="token comment">// configure the HTTP request pipeline.</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Configure</span><span class="token punctuation">(</span><span class="token class-name">IApplicationBuilder</span> app<span class="token punctuation">,</span> <span class="token class-name">IHostingEnvironment</span> env<span class="token punctuation">,</span> <span class="token class-name">ILoggerFactory</span> loggerFactory<span class="token punctuation">)</span> <span class="token punctuation">{</span> app<span class="token punctuation">.</span><span class="token function">UseAuthentication</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="authorization" style="position:relative;"><a href="#authorization" aria-label="authorization permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Authorization</h2> <p>You still can use your older code for authorisation though:</p> <div class="gatsby-code-button-container" data-toaster-id="1280058940994144300" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`services.AddAuthorization(options => { options.AddPolicy(&quot;RequireAdminRole&quot;, policy => policy.RequireRole(&quot;Admin&quot;)); });`, `1280058940994144300`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp">services<span class="token punctuation">.</span><span class="token function">AddAuthorization</span><span class="token punctuation">(</span>options <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span><span class="token function">AddPolicy</span><span class="token punctuation">(</span><span class="token string">"RequireAdminRole"</span><span class="token punctuation">,</span> policy <span class="token operator">=></span> policy<span class="token punctuation">.</span><span class="token function">RequireRole</span><span class="token punctuation">(</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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And in your controller:</p> <div class="gatsby-code-button-container" data-toaster-id="21968804052059697000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[Authorize(Policy = &quot;RequireAdminRole&quot;)] public class AdminController : Controller { public IActionResult Index() { return View(); } }`, `21968804052059697000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Authorize</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Policy <span class="token operator">=</span> <span class="token string">"RequireAdminRole"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AdminController</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Controller</span></span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token return-type class-name">IActionResult</span> <span class="token function">Index</span><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">View</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="active-vs-passive" style="position:relative;"><a href="#active-vs-passive" aria-label="active vs passive permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Active vs Passive</h2> <p>With the new version there is only one active authentication scheme at a time, because of the fact that it is not a single service. But first let me give a bit of history on what is active vs passive.</p> <p>Well authentication middleware has the concept of passive vs active. Active middleware always intercepts every incoming request and attempts to authenticate the call.</p> <p>If successful they create a principal that represents the current user and assign that principal to the hosting environment. Passive middleware, on the other hand, only inspects the request when asked to.</p> <p>Are you wondering what is the benefit of this? Well you won’t get complex scenarios where one of the middleware is failed but you cannot prevent others to get invoked.</p> <h2 id="two-factor-authentication-2fa-is-now-added" style="position:relative;"><a href="#two-factor-authentication-2fa-is-now-added" aria-label="two factor authentication 2fa is now added permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Two Factor Authentication (2FA) is now added</h2> <p>ASP.NET Identity has now support for two factor authentication using Time-based One-time Password Algorithm (TOTP), and in fact that is now its default option. That means you can use the authenticator app using a <a href="https://wikipedia.org/wiki/QR_code" target="_blank" rel="nofollow noopener noreferrer">QR Code</a> which is preferred over SMS 2FA which was available in version 1.0.</p> <p>Also the ASP.NET Core web app templates support authenticators, but do not provide support for QRCode generation. QRCode generators ease the setup of 2FA.</p><![CDATA[Using Azure B2C as your identity manager (Part 2)]]>https://yashints.dev/blog/2017/08/21/using-azure-b2c-identity-manager-part-2https://yashints.dev/blog/2017/08/21/using-azure-b2c-identity-manager-part-2Mon, 21 Aug 2017 00:00:00 GMT<p>Flexibility is a key part of Azure Active Directory B2C. Use built-in policies to create a login experience in minutes. For more complex scenarios, use our identity experience framework to build custom policies.</p> <!--more--> <p>This article is one of the two part series I wrote on how to use Azure B2C as your identity manager.</p> <p>You can find <a href="/blog/2017/08/16/using-azure-b2c-identity-manager-part-1/">part 1 here.</a></p> <p><a href="https://github.com/yashints/Angular4AzureB2C" target="_blank" rel="nofollow noopener noreferrer">Full source code on Github.</a></p> <h2 id="recap" style="position:relative;"><a href="#recap" aria-label="recap permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Recap</h2> <p>In my previous post I talked about how to setup the Azure B2C and get ready to integrate that into your application. There are a two ways to do this, mentioned below, however, I will show you how to implement the second one here from scratch.</p> <h2 id="options-available" style="position:relative;"><a href="#options-available" aria-label="options available permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 available:</h2> <ol> <li>Only server side integration</li> <li>Server and client side integration</li> </ol> <h2 id="what-do-you-need" style="position:relative;"><a href="#what-do-you-need" aria-label="what do you need permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 do you need?</h2> <p>If you’ve read and followed the previous post you should now have an <code class="language-text">application id</code> and a <code class="language-text">secret key</code> (you won’t need the secret key for this approach), plus your tenant login endpoint information. To cut it short, you will need the below configuration:</p> <div class="gatsby-code-button-container" data-toaster-id="86816532104166360000" data-toaster-class="gatsby-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;AzureAd&quot;: { &quot;Tenant&quot;: &quot;your-tenant-name.onmicrosoft.com&quot;, &quot;ClientId&quot;: &quot;7e232743-66f4-429e-9855-5b42f4dd08c6&quot;, &quot;Policy&quot;: &quot;B2C_1_policyname&quot;, &quot;ScopeRead&quot;: &quot;read&quot;, &quot;ScopeWrite&quot;: &quot;write&quot; }`, `86816532104166360000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"AzureAd"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"Tenant"</span><span class="token operator">:</span> <span class="token string">"your-tenant-name.onmicrosoft.com"</span><span class="token punctuation">,</span> <span class="token property">"ClientId"</span><span class="token operator">:</span> <span class="token string">"7e232743-66f4-429e-9855-5b42f4dd08c6"</span><span class="token punctuation">,</span> <span class="token property">"Policy"</span><span class="token operator">:</span> <span class="token string">"B2C_1_policyname"</span><span class="token punctuation">,</span> <span class="token property">"ScopeRead"</span><span class="token operator">:</span> <span class="token string">"read"</span><span class="token punctuation">,</span> <span class="token property">"ScopeWrite"</span><span class="token operator">:</span> <span class="token string">"write"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I put the information needed in above format to make it easy to be placed inside an <a href="https://docs.microsoft.com/en-us/aspnet/core/" target="_blank" rel="nofollow noopener noreferrer">Asp.Net Core</a> application config (<code class="language-text">appsettings.json</code> or <code class="language-text">web.config</code>).</p> <p>As you can see you will need the tenant name, application id which you’ve created (I’ve called it client id), the policy name you want to use for authentication purpose, and the scopes you will need such as read and write.</p> <h2 id="setup-the-authentication" style="position:relative;"><a href="#setup-the-authentication" aria-label="setup the authentication permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup the authentication</h2> <p>Now is the time to use this information. Create a class file and name it <code class="language-text">ConfigueAzureAuth</code> (or pick any name you like). Inside this file create a partial class and name it <code class="language-text">Startup</code>. Now in this class use the code below:</p> <div class="gatsby-code-button-container" data-toaster-id="64278157689431240000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public partial class Startup { public static string ScopeRead; public static string ScopeWrite; private void ConfigureAzureAdAuth(IApplicationBuilder app) { var tenant = Configuration[&quot;Authentication:AzureAd:Tenant&quot;]; var clientId = Configuration[&quot;Authentication:AzureAd:ClientId&quot;]; var policy = Configuration[&quot;Authentication:AzureAd:Policy&quot;]; var jwtBearerOptions = new JwtBearerOptions { MetadataAddress = \$&quot;https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration?p={policy}&quot;, Audience = clientId, Events = new JwtBearerEvents { OnAuthenticationFailed = (ctx) => { //Do whatever you would do for failed authentication //Normally log the exception and return 403 to client for this approach return Task.CompletedTask; } } }; app.UseJwtBearerAuthentication(jwtBearerOptions); ScopeRead = Configuration[&quot;Authentication:AzureAd:ScopeRead&quot;]; ScopeWrite = Configuration[&quot;Authentication:AzureAd:ScopeWrite&quot;]; } }`, `64278157689431240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">Startup</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name"><span class="token keyword">string</span></span> ScopeRead<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name"><span class="token keyword">string</span></span> ScopeWrite<span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ConfigureAzureAdAuth</span><span class="token punctuation">(</span><span class="token class-name">IApplicationBuilder</span> app<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword">var</span></span> tenant <span class="token operator">=</span> Configuration<span class="token punctuation">[</span><span class="token string">"Authentication:AzureAd:Tenant"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> clientId <span class="token operator">=</span> Configuration<span class="token punctuation">[</span><span class="token string">"Authentication:AzureAd:ClientId"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> policy <span class="token operator">=</span> Configuration<span class="token punctuation">[</span><span class="token string">"Authentication:AzureAd:Policy"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> jwtBearerOptions <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">JwtBearerOptions</span> <span class="token punctuation">{</span> MetadataAddress <span class="token operator">=</span> <span class="token interpolation-string"><span class="token string">$"https://login.microsoftonline.com/</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">tenant</span><span class="token punctuation">}</span></span><span class="token string">/v2.0/.well-known/openid-configuration?p=</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">policy</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> Audience <span class="token operator">=</span> clientId<span class="token punctuation">,</span> Events <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">JwtBearerEvents</span> <span class="token punctuation">{</span> OnAuthenticationFailed <span class="token operator">=</span> <span class="token punctuation">(</span>ctx<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//Do whatever you would do for failed authentication</span> <span class="token comment">//Normally log the exception and return 403 to client for this approach</span> <span class="token keyword">return</span> Task<span class="token punctuation">.</span>CompletedTask<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> app<span class="token punctuation">.</span><span class="token function">UseJwtBearerAuthentication</span><span class="token punctuation">(</span>jwtBearerOptions<span class="token punctuation">)</span><span class="token punctuation">;</span> ScopeRead <span class="token operator">=</span> Configuration<span class="token punctuation">[</span><span class="token string">"Authentication:AzureAd:ScopeRead"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> ScopeWrite <span class="token operator">=</span> Configuration<span class="token punctuation">[</span><span class="token string">"Authentication:AzureAd:ScopeWrite"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see there is not much to write in this class, it is a very basic configuration to use <a href="https://jwt.io/" target="_blank" rel="nofollow noopener noreferrer">JSON web token</a> (JWT) bearer authentication.</p> <p>Now open up the <code class="language-text">Startup.cs</code> and put this line inside <code class="language-text">Configure</code> method:</p> <div class="gatsby-code-button-container" data-toaster-id="60076449952395300000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`public void Configure(IApplicationBuilder app, IHostingEnvironment env){ //Rest of the code ConfigureAzureAdAuth(app); //code might continue }`, `60076449952395300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Configure</span><span class="token punctuation">(</span><span class="token class-name">IApplicationBuilder</span> app<span class="token punctuation">,</span> <span class="token class-name">IHostingEnvironment</span> env<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">//Rest of the code</span> <span class="token function">ConfigureAzureAdAuth</span><span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//code might continue</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Alright, so far you’ve told Asp.Net Core to use JWT bearer token with the Azure B2C endpoint, however, this is just to handle the server side check of the token which comes back from login process and and extract the claims to <code class="language-text">User</code> object.</p> <p>Now that we’ve configured everything, it is time to use <code class="language-text">Authorize</code> filter on one of the controllers. I’ve just used the default SampleDataController for this purpose.</p> <div class="gatsby-code-button-container" data-toaster-id="22883558637477150000" data-toaster-class="gatsby-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.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Web.Controllers { [Route(&quot;api/[controller]&quot;)] [Authorize] public class SampleDataController : Controller { private static string[] Summaries = new[] { &quot;Freezing&quot;, &quot;Bracing&quot;, &quot;Chilly&quot;, &quot;Cool&quot;, &quot;Mild&quot;, &quot;Warm&quot;, &quot;Balmy&quot;, &quot;Hot&quot;, &quot;Sweltering&quot;, &quot;Scorching&quot; }; [HttpGet(&quot;[action]&quot;)] public IEnumerable<WeatherForecast> WeatherForecasts() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { DateFormatted = DateTime.Now.AddDays(index).ToString(&quot;d&quot;), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }); } public class WeatherForecast { public string DateFormatted { get; set; } public int TemperatureC { get; set; } public string Summary { get; set; } public int TemperatureF { get { return 32 + (int)(TemperatureC / 0.5556); } } } } }`, `22883558637477150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><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>Collections<span class="token punctuation">.</span>Generic</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Linq</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>AspNetCore<span class="token punctuation">.</span>Authorization</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>AspNetCore<span class="token punctuation">.</span>Mvc</span><span class="token punctuation">;</span> <span class="token keyword">namespace</span> <span class="token namespace">Web<span class="token punctuation">.</span>Controllers</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Route</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"api/[controller]"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Authorize</span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SampleDataController</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Controller</span></span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> Summaries <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token string">"Freezing"</span><span class="token punctuation">,</span> <span class="token string">"Bracing"</span><span class="token punctuation">,</span> <span class="token string">"Chilly"</span><span class="token punctuation">,</span> <span class="token string">"Cool"</span><span class="token punctuation">,</span> <span class="token string">"Mild"</span><span class="token punctuation">,</span> <span class="token string">"Warm"</span><span class="token punctuation">,</span> <span class="token string">"Balmy"</span><span class="token punctuation">,</span> <span class="token string">"Hot"</span><span class="token punctuation">,</span> <span class="token string">"Sweltering"</span><span class="token punctuation">,</span> <span class="token string">"Scorching"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HttpGet</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"[action]"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token return-type class-name">IEnumerable<span class="token punctuation">&lt;</span>WeatherForecast<span class="token punctuation">></span></span> <span class="token function">WeatherForecasts</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword">var</span></span> rng <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> Enumerable<span class="token punctuation">.</span><span class="token function">Range</span><span class="token punctuation">(</span><span class="token number">1</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 function">Select</span><span class="token punctuation">(</span>index <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">WeatherForecast</span> <span class="token punctuation">{</span> DateFormatted <span class="token operator">=</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">.</span><span class="token function">AddDays</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token string">"d"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> TemperatureC <span class="token operator">=</span> rng<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">20</span><span class="token punctuation">,</span> <span class="token number">55</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Summary <span class="token operator">=</span> Summaries<span class="token punctuation">[</span>rng<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span>Summaries<span class="token punctuation">.</span>Length<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">public</span> <span class="token keyword">class</span> <span class="token class-name">WeatherForecast</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> DateFormatted <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> TemperatureC <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> Summary <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> TemperatureF <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token number">32</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span>TemperatureC <span class="token operator">/</span> <span class="token number">0.5556</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="configuring-the-client-side" style="position:relative;"><a href="#configuring-the-client-side" aria-label="configuring the client side permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Configuring the client side</h2> <p>In this approach we will need to interact with Azure B2C from our SPA application. For this we need some metadata about the endpoint and application id we have. Since I am using a client library called <a href="https://github.com/IdentityModel/oidc-client-js" target="_blank" rel="nofollow noopener noreferrer">oidc-client</a>, we will need a setting similar to this:</p> <div class="gatsby-code-button-container" data-toaster-id="42184934421911160000" data-toaster-class="gatsby-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;AzureClientConfig&quot;: { &quot;Authority&quot;: &quot;https://login.microsoftonline.com/your-tenant-domain/oauth2/v2.0/authorize&quot;, &quot;Client_id&quot;: &quot;your-application-id&quot;, &quot;Redirect_uri&quot;: &quot;https://localhost/loginCallback&quot;, &quot;Post_logout_redirect_uri&quot;: &quot;https://localhost&quot;, &quot;Response_type&quot;: &quot;id_token token&quot;, &quot;Scope&quot;: &quot;openid https://your-tenant-domain/app-name/read https://your-tenant-domain/app-name/user_impersonation&quot;, &quot;Silent_redirect_uri&quot;: &quot;https://localhost&quot;, &quot;AutomaticSilentRenew&quot;: true, &quot;FilterProtocolClaims&quot;: false, &quot;LoadUserInfo&quot;: false, &quot;MetadataUrl&quot;: &quot;https://login.microsoftonline.com/your-tenant-domain/v2.0/.well-known/openid-configuration?p=B2C_1_susitest&quot;, &quot;ResetPassUrl&quot;: &quot;https://login.microsoftonline.com/your-tenant-domain/oauth2/v2.0/authorize?p=B2C_1_passwordReset&quot; }`, `42184934421911160000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"AzureClientConfig"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"Authority"</span><span class="token operator">:</span> <span class="token string">"https://login.microsoftonline.com/your-tenant-domain/oauth2/v2.0/authorize"</span><span class="token punctuation">,</span> <span class="token property">"Client_id"</span><span class="token operator">:</span> <span class="token string">"your-application-id"</span><span class="token punctuation">,</span> <span class="token property">"Redirect_uri"</span><span class="token operator">:</span> <span class="token string">"https://localhost/loginCallback"</span><span class="token punctuation">,</span> <span class="token property">"Post_logout_redirect_uri"</span><span class="token operator">:</span> <span class="token string">"https://localhost"</span><span class="token punctuation">,</span> <span class="token property">"Response_type"</span><span class="token operator">:</span> <span class="token string">"id_token token"</span><span class="token punctuation">,</span> <span class="token property">"Scope"</span><span class="token operator">:</span> <span class="token string">"openid https://your-tenant-domain/app-name/read https://your-tenant-domain/app-name/user_impersonation"</span><span class="token punctuation">,</span> <span class="token property">"Silent_redirect_uri"</span><span class="token operator">:</span> <span class="token string">"https://localhost"</span><span class="token punctuation">,</span> <span class="token property">"AutomaticSilentRenew"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token property">"FilterProtocolClaims"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"LoadUserInfo"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"MetadataUrl"</span><span class="token operator">:</span> <span class="token string">"https://login.microsoftonline.com/your-tenant-domain/v2.0/.well-known/openid-configuration?p=B2C_1_susitest"</span><span class="token punctuation">,</span> <span class="token property">"ResetPassUrl"</span><span class="token operator">:</span> <span class="token string">"https://login.microsoftonline.com/your-tenant-domain/oauth2/v2.0/authorize?p=B2C_1_passwordReset"</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I just point out some important notes in the setting you will need to change:</p> <ul> <li>Replace the <code class="language-text">your-tenant-domain</code> with your tenant domain name you will find on your B2C blade. This will tell the login endpoint which B2C instance to use.</li> <li><code class="language-text">Client-id</code> is your application id you created earlier. This is exactly what you used to setup the server side settings.</li> <li><code class="language-text">Redirect-uri</code> is where the login response is sent to. You will need a handler at this URL which we will setup later on. Same goes for logout URL which is usually your login page.</li> <li>In the scope section you see I put <code class="language-text">app-name</code> in between the scope name and the tenant domain. This is the name of the application that you created. You can find the name of the application in the Applications menu of the B2C blade information page.</li> <li>If you intend to use silence renewal for user sessions then you should set the right URL and create the handler for it which I am not going to do here. I will cover that in a separate post later however.</li> <li>At the end of the <code class="language-text">MetadataUrl</code> and <code class="language-text">ResetPassUrl</code> you should put your policy names that you created for that purpose.</li> </ul> <p>Now it’s time to consume this information.</p> <h2 id="creating-the-application" style="position:relative;"><a href="#creating-the-application" aria-label="creating 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>Creating the application</h2> <p>I am going to use the default angular template of <a href="https://www.visualstudio.com/vs/whatsnew/" target="_blank" rel="nofollow noopener noreferrer">Visual Studio 2017</a> for this example which will setup a project for me with <a href="https://blogs.msdn.microsoft.com/webdev/2017/08/14/announcing-asp-net-core-2-0/" target="_blank" rel="nofollow noopener noreferrer">Asp.Net Core 2.0</a> and <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular 4</a>.</p> <p>Open up your Visual Studio and create a new web project (Select angular template). You should have a structure like below.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 588px; " > <a class="gatsby-resp-image-link" href="/static/9684ec4a02fd99a9d3d1d8470985acb3/ea91e/b2cvsprojstructure.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 118.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAYABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAIDBAX/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAfVq9LnF0DKiasH/xAAbEAACAgMBAAAAAAAAAAAAAAAAAQIDEBETMf/aAAgBAQABBQJ1w2qoHGskLwkLH//EABgRAAIDAAAAAAAAAAAAAAAAAAABEBES/9oACAEDAQE/AaRlT//EABgRAAIDAAAAAAAAAAAAAAAAAAABEBES/9oACAECAQE/AbZpz//EABgQAAIDAAAAAAAAAAAAAAAAAAAyASAx/9oACAEBAAY/AsFgW/8A/8QAGhAAAgMBAQAAAAAAAAAAAAAAAAEQETFBYf/aAAgBAQABPyFbqNaV3JodYcJ4Zqqj/9oADAMBAAIAAwAAABAkPwD/xAAXEQADAQAAAAAAAAAAAAAAAAAAAWEQ/9oACAEDAQE/EJEVv//EABYRAQEBAAAAAAAAAAAAAAAAAGEAEP/aAAgBAgEBPxBpd//EAB0QAQEAAQQDAAAAAAAAAAAAAAERABAhMVFhodH/2gAIAQEAAT8QrZU3HjrC6Mer9xdX35A7iAUhoisT5mObxHZp/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Project Structure" title="" src="/static/9684ec4a02fd99a9d3d1d8470985acb3/ea91e/b2cvsprojstructure.jpg" srcset="/static/9684ec4a02fd99a9d3d1d8470985acb3/6f81f/b2cvsprojstructure.jpg 270w, /static/9684ec4a02fd99a9d3d1d8470985acb3/09d21/b2cvsprojstructure.jpg 540w, /static/9684ec4a02fd99a9d3d1d8470985acb3/ea91e/b2cvsprojstructure.jpg 588w" sizes="(max-width: 588px) 100vw, 588px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>I am going to create a config module which can be configured to be injected to our service later using DI in Angular. Below is the file I’ve created in the <code class="language-text">ClientApp/app</code> folder:</p> <div class="gatsby-code-button-container" data-toaster-id="5002669880205368000" data-toaster-class="gatsby-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 { NgModule, InjectionToken } from '@angular/core' export let B2C_CONFIG = new InjectionToken() < B2CConfig > 'b2cconfig' export class B2CConfig { authority: string client_id: string redirect_uri: string post_logout_redirect_uri: string response_type: string scope: string silent_redirect_uri: string automaticSilentRenew: boolean filterProtocolClaims: boolean loadUserInfo: boolean metadataUrl: string resetPassUrl: string } export const APP_B2C_CONFIG: B2CConfig = { authority: 'https://login.microsoftonline.com/angular4b2c.onmicrosoft.com/oauth2/v2.0/authorize', client_id: '11246517-8ca1-41e9-8054-55acd1dfa250', redirect_uri: 'http://localhost:51126', post_logout_redirect_uri: 'http://localhost:51126', response_type: 'id_token token', scope: 'openid https://angular4b2c.onmicrosoft.com/spaapp/read https://angular4b2c.onmicrosoft.com/spaapp/user_impersonation', silent_redirect_uri: 'http://localhost:51126', automaticSilentRenew: false, filterProtocolClaims: false, loadUserInfo: false, metadataUrl: 'https://login.microsoftonline.com/angular4b2c.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_dev', resetPassUrl: 'https://login.microsoftonline.com/angular4b2c.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_reset', } @NgModule({ providers: [ { provide: B2C_CONFIG, useValue: APP_B2C_CONFIG, }, ], }) export class B2CConfigModule {}`, `5002669880205368000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> NgModule<span class="token punctuation">,</span> InjectionToken <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">export</span> <span class="token keyword">let</span> <span class="token constant">B2C_CONFIG</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InjectionToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> B2CConfig <span class="token operator">></span> <span class="token string">'b2cconfig'</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">B2CConfig</span> <span class="token punctuation">{</span> authority<span class="token operator">:</span> <span class="token builtin">string</span> client_id<span class="token operator">:</span> <span class="token builtin">string</span> redirect_uri<span class="token operator">:</span> <span class="token builtin">string</span> post_logout_redirect_uri<span class="token operator">:</span> <span class="token builtin">string</span> response_type<span class="token operator">:</span> <span class="token builtin">string</span> scope<span class="token operator">:</span> <span class="token builtin">string</span> silent_redirect_uri<span class="token operator">:</span> <span class="token builtin">string</span> automaticSilentRenew<span class="token operator">:</span> <span class="token builtin">boolean</span> filterProtocolClaims<span class="token operator">:</span> <span class="token builtin">boolean</span> loadUserInfo<span class="token operator">:</span> <span class="token builtin">boolean</span> metadataUrl<span class="token operator">:</span> <span class="token builtin">string</span> resetPassUrl<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token constant">APP_B2C_CONFIG</span><span class="token operator">:</span> B2CConfig <span class="token operator">=</span> <span class="token punctuation">{</span> authority<span class="token operator">:</span> <span class="token string">'https://login.microsoftonline.com/angular4b2c.onmicrosoft.com/oauth2/v2.0/authorize'</span><span class="token punctuation">,</span> client_id<span class="token operator">:</span> <span class="token string">'11246517-8ca1-41e9-8054-55acd1dfa250'</span><span class="token punctuation">,</span> redirect_uri<span class="token operator">:</span> <span class="token string">'http://localhost:51126'</span><span class="token punctuation">,</span> post_logout_redirect_uri<span class="token operator">:</span> <span class="token string">'http://localhost:51126'</span><span class="token punctuation">,</span> response_type<span class="token operator">:</span> <span class="token string">'id_token token'</span><span class="token punctuation">,</span> scope<span class="token operator">:</span> <span class="token string">'openid https://angular4b2c.onmicrosoft.com/spaapp/read https://angular4b2c.onmicrosoft.com/spaapp/user_impersonation'</span><span class="token punctuation">,</span> silent_redirect_uri<span class="token operator">:</span> <span class="token string">'http://localhost:51126'</span><span class="token punctuation">,</span> automaticSilentRenew<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> filterProtocolClaims<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> loadUserInfo<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> metadataUrl<span class="token operator">:</span> <span class="token string">'https://login.microsoftonline.com/angular4b2c.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_dev'</span><span class="token punctuation">,</span> resetPassUrl<span class="token operator">:</span> <span class="token string">'https://login.microsoftonline.com/angular4b2c.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_reset'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> providers<span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> provide<span class="token operator">:</span> <span class="token constant">B2C_CONFIG</span><span class="token punctuation">,</span> useValue<span class="token operator">:</span> <span class="token constant">APP_B2C_CONFIG</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">export</span> <span class="token keyword">class</span> <span class="token class-name">B2CConfigModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now let’s create the services we need. We will need to services, one which plays the route guard role and the other for authentication. Since I will be using <a href="https://github.com/IdentityModel/oidc-client-js" target="_blank" rel="nofollow noopener noreferrer">oidc-client</a>, I will use their Authentication service code. So here is our Authentication service which I’ve created inside services folder.</p> <p>Since the code is a bit long I won’t show the code here but don’t worry, a fully working version is to be found on my GitHub <a href="https://github.com/yashints/Angular4AzureB2C" target="_blank" rel="nofollow noopener noreferrer">repository</a>.</p> <p>However to demonstrate how you should use the above config, I’ll go through the necessary bits:</p> <div class="gatsby-code-button-container" data-toaster-id="89069873243758260000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`mgr: UserManager; constructor( @Inject(B2C_CONFIG) private config: B2CConfig, private http: Http, private router: Router) { this.mgr = new UserManager(this.config); }`, `89069873243758260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript">mgr<span class="token operator">:</span> UserManager<span class="token punctuation">;</span> <span class="token function">constructor</span><span class="token punctuation">(</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Inject</span></span><span class="token punctuation">(</span><span class="token constant">B2C_CONFIG</span><span class="token punctuation">)</span> <span class="token keyword">private</span> config<span class="token operator">:</span> B2CConfig<span class="token punctuation">,</span> <span class="token keyword">private</span> http<span class="token operator">:</span> Http<span class="token punctuation">,</span> <span class="token keyword">private</span> router<span class="token operator">:</span> Router<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mgr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserManager</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Once you got the config in the constructor you can go ahead and initialise the user manager from the <code class="language-text">oidc-client</code> library. Once initialised, you can then use its startSignIn method to initiate the login process which you will do behind your login button.</p> <div class="gatsby-code-button-container" data-toaster-id="43886907053016560000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`startSigninMainWindow() { this.mgr.signinRedirect({ data: 'some data' }).then(() => { console.log('signinRedirect done'); }).catch( (err) => { console.log(err); }); }`, `43886907053016560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token function">startSigninMainWindow</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>mgr<span class="token punctuation">.</span><span class="token function">signinRedirect</span><span class="token punctuation">(</span><span class="token punctuation">{</span> data<span class="token operator">:</span> <span class="token string">'some data'</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 punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'signinRedirect done'</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">catch</span><span class="token punctuation">(</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In my login component I just have a login button which calls the above method from authentication service.</p> <div class="gatsby-code-button-container" data-toaster-id="6041712833821001000" data-toaster-class="gatsby-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 { Component } from '@angular/core' import { Auth } from '../../services/auth.service' @Component({ selector: 'login', styleUrls: ['./login.css'], templateUrl: './login-component.html', }) export class LoginComponent { constructor(private service: Auth) {} login() { this.service.startSigninMainWindow() } }`, `6041712833821001000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Auth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../../services/auth.service'</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Component</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> selector<span class="token operator">:</span> <span class="token string">'login'</span><span class="token punctuation">,</span> styleUrls<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'./login.css'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> templateUrl<span class="token operator">:</span> <span class="token string">'./login-component.html'</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">class</span> <span class="token class-name">LoginComponent</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> service<span class="token operator">:</span> Auth<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token function">login</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>service<span class="token punctuation">.</span><span class="token function">startSigninMainWindow</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>OK, it’s time to create our route guard service. In this service we just tell Angular which route should be protected.</p> <div class="gatsby-code-button-container" data-toaster-id="80548854968679200000" data-toaster-class="gatsby-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 { Injectable } from '@angular/core' import { CanActivate, Router, CanActivateChild, ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router' import { Auth } from './auth.service' import { Observable } from 'rxjs/Rx' @Injectable() export class AuthGuard implements CanActivate, CanActivateChild { constructor(private auth: Auth, private router: Router) {} checkLogin(): Observable<boolean> | boolean { let isLoggedIn = this.auth.isLoggedInObs() isLoggedIn.subscribe(loggedin => { if (!loggedin) { this.router.navigate(['login']) } }) return isLoggedIn } canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | Promise<boolean> | boolean { return this.checkLogin() } canActivateChild( childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | Promise<boolean> | boolean { return this.canActivate(childRoute, state) } }`, `80548854968679200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> CanActivate<span class="token punctuation">,</span> Router<span class="token punctuation">,</span> CanActivateChild<span class="token punctuation">,</span> ActivatedRouteSnapshot<span class="token punctuation">,</span> RouterStateSnapshot<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/router'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Auth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./auth.service'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Observable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rxjs/Rx'</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Injectable</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AuthGuard</span> <span class="token keyword">implements</span> <span class="token class-name">CanActivate</span><span class="token punctuation">,</span> CanActivateChild <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> auth<span class="token operator">:</span> Auth<span class="token punctuation">,</span> <span class="token keyword">private</span> router<span class="token operator">:</span> Router<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token function">checkLogin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">></span> <span class="token operator">|</span> <span class="token builtin">boolean</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> isLoggedIn <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>auth<span class="token punctuation">.</span><span class="token function">isLoggedInObs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> isLoggedIn<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>loggedin <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>loggedin<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>router<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'login'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> isLoggedIn <span class="token punctuation">}</span> <span class="token function">canActivate</span><span class="token punctuation">(</span> route<span class="token operator">:</span> ActivatedRouteSnapshot<span class="token punctuation">,</span> state<span class="token operator">:</span> RouterStateSnapshot <span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">></span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">></span> <span class="token operator">|</span> <span class="token builtin">boolean</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">checkLogin</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">canActivateChild</span><span class="token punctuation">(</span> childRoute<span class="token operator">:</span> ActivatedRouteSnapshot<span class="token punctuation">,</span> state<span class="token operator">:</span> RouterStateSnapshot <span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">></span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">></span> <span class="token operator">|</span> <span class="token builtin">boolean</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">canActivate</span><span class="token punctuation">(</span>childRoute<span class="token punctuation">,</span> state<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You can see from above code that on route activation we will check whether the user is logged in or not. If the user is logged in, the redirection continues, otherwise it will be rejected.</p> <p>Now you can use this service on any route using <code class="language-text">canActivate</code> property of the route.</p> <div class="gatsby-code-button-container" data-toaster-id="49576577528547520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`RouterModule.forRoot([ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', component: HomeComponent }, { path: 'login', component: LoginComponent }, { path: 'counter', component: CounterComponent }, { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthGuard], }, { path: '**', redirectTo: 'home' }, ])`, `49576577528547520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript">RouterModule<span class="token punctuation">.</span><span class="token function">forRoot</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">''</span><span class="token punctuation">,</span> redirectTo<span class="token operator">:</span> <span class="token string">'home'</span><span class="token punctuation">,</span> pathMatch<span class="token operator">:</span> <span class="token string">'full'</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">'home'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> HomeComponent <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">'login'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> LoginComponent <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">'counter'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> CounterComponent <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">'fetch-data'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> FetchDataComponent<span class="token punctuation">,</span> canActivate<span class="token operator">:</span> <span class="token punctuation">[</span>AuthGuard<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">'**'</span><span class="token punctuation">,</span> redirectTo<span class="token operator">:</span> <span class="token string">'home'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Once done, if you run the app and click on the forecast menu, it will redirect you to login page. The only thing left to do is to handle the login callback from Azure B2C login endpoint.</p> <p>This is as easy as calling a method from oidc-client called <code class="language-text">signinRedirectCallback</code> method. For that I’ve already create a method in authentication service.</p> <div class="gatsby-code-button-container" data-toaster-id="51738419601664980000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`redirectCallback() { this.mgr.signinRedirectCallback() .then(user => { this.currentUser = user; this.router.navigateByUrl('/'); }) .catch(err => { if (err && err.error_description && err.error_description.indexOf('AADB2C90118') > -1) { let url = \`\${this.config.resetPassUrl}&client_id=\${this.config.client_id}&redirect_uri=\${this.config.redirect_uri}&response_type=\${this.config.response_type}&scope=\${this.config.scope}&nonce=\${this.randomString(32)}\`; window.location.href = url; } else { this.router.navigateByUrl('/login'); } console.log(err); }); }`, `51738419601664980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">redirectCallback</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>mgr<span class="token punctuation">.</span><span class="token function">signinRedirectCallback</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">user</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>currentUser <span class="token operator">=</span> user<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>router<span class="token punctuation">.</span><span class="token function">navigateByUrl</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 punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</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 operator">&amp;&amp;</span> err<span class="token punctuation">.</span>error_description <span class="token operator">&amp;&amp;</span> err<span class="token punctuation">.</span>error_description<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'AADB2C90118'</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>resetPassUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;client_id=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>client_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;redirect_uri=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>redirect_uri<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;response_type=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>response_type<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;scope=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>scope<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;nonce=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomString</span><span class="token punctuation">(</span><span class="token number">32</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> window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>href <span class="token operator">=</span> url<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">this</span><span class="token punctuation">.</span>router<span class="token punctuation">.</span><span class="token function">navigateByUrl</span><span class="token punctuation">(</span><span class="token string">'/login'</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>err<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The only ugly piece of code in this function is that I have to handle the reset password redirection manually. That catch block is for doing this bit.</p> <p>You’re all set now, not quite though. You will need to modify your fetch data component to send the API request using <code class="language-text">Authorization</code> code you’ve got from login callback.</p> <p>Fortunately the code we got from the <code class="language-text">oidc-client</code> repository does have the code we need, so all we have to do in replace the <code class="language-text">http</code> with our authentication service and use that to send the get request.</p> <div class="gatsby-code-button-container" data-toaster-id="77723005245429990000" data-toaster-class="gatsby-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 { Component, Inject } from '@angular/core' import { Http } from '@angular/http' import { Auth } from '../../services/auth.service' @Component({ selector: 'fetchdata', templateUrl: './fetchdata.component.html', }) export class FetchDataComponent { public forecasts: WeatherForecast[] constructor(http: Auth, @Inject('BASE_URL') baseUrl: string) { http.AuthGet(baseUrl + 'api/SampleData/WeatherForecasts').subscribe( result => { this.forecasts = result.json() as WeatherForecast[] }, error => console.error(error) ) } } interface WeatherForecast { dateFormatted: string temperatureC: number temperatureF: number summary: string }`, `77723005245429990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="typescript"><pre style="counter-reset: linenumber NaN" class="language-typescript line-numbers"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> Inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Http <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/http'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Auth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../../services/auth.service'</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Component</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> selector<span class="token operator">:</span> <span class="token string">'fetchdata'</span><span class="token punctuation">,</span> templateUrl<span class="token operator">:</span> <span class="token string">'./fetchdata.component.html'</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">class</span> <span class="token class-name">FetchDataComponent</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> forecasts<span class="token operator">:</span> WeatherForecast<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">constructor</span><span class="token punctuation">(</span>http<span class="token operator">:</span> Auth<span class="token punctuation">,</span> <span class="token decorator"><span class="token at operator">@</span><span class="token function">Inject</span></span><span class="token punctuation">(</span><span class="token string">'BASE_URL'</span><span class="token punctuation">)</span> baseUrl<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> http<span class="token punctuation">.</span><span class="token function">AuthGet</span><span class="token punctuation">(</span>baseUrl <span class="token operator">+</span> <span class="token string">'api/SampleData/WeatherForecasts'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span> result <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>forecasts <span class="token operator">=</span> result<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> WeatherForecast<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> error <span class="token operator">=></span> <span class="token builtin">console</span><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> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">WeatherForecast</span> <span class="token punctuation">{</span> dateFormatted<span class="token operator">:</span> <span class="token builtin">string</span> temperatureC<span class="token operator">:</span> <span class="token builtin">number</span> temperatureF<span class="token operator">:</span> <span class="token builtin">number</span> summary<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>As you can see, I’ve replaced the <code class="language-text">http</code> instance with auth service and <code class="language-text">http.get</code> with <code class="language-text">http.AuthGet</code>which will add the <code class="language-text">Authorization</code> header to request.</p> <h2 id="testing-the-whole-code" style="position:relative;"><a href="#testing-the-whole-code" aria-label="testing the whole 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>Testing the whole code</h2> <p>Just run the project and navigate to fetch data menu. It will redirect to login page, which after clicking on login, you will be redirected to the login page on Azure. After the login, it then redirects you back to your home component which will then handle the response and you’re good to go.</p> <p>Hope this post has helped you to get a high level overview of how to integrate your SPA application with B2C.</p><![CDATA[Using Azure B2C as your identity manager (Part 1)]]>https://yashints.dev/blog/2017/08/16/using-azure-b2c-identity-manager-part-1https://yashints.dev/blog/2017/08/16/using-azure-b2c-identity-manager-part-1Wed, 16 Aug 2017 00:00:00 GMT<p>Flexibility is a key part of Azure Active Directory B2C. Use built-in policies to create a login experience in minutes. For more complex scenarios, use our identity experience framework to build custom policies.</p> <!--more--> <p>This article is one of the two part series I wrote on how to use Azure B2C as your identity manager.</p> <p>You can find <a href="/blog/2017/08/21/using-azure-b2c-identity-manager-part-2/">part 2 here.</a></p> <p><a href="https://github.com/yashints/Angular4AzureB2C" target="_blank" rel="nofollow noopener noreferrer">Full source code on Github.</a></p> <p>A while ago I was engaged in a front end project using Asp.Net Core and Angular 2. At some point we decided to integrate our application with Azure B2C as our identity management aka IDM.</p> <p>In a nutshell, Azure B2C allows us to let users sign in with their own email address as their username compared to Azure Active Directory (AD) in which you have to have an email with the domain associated with your tenant.</p> <p>It also supports social login and multi factor authentication (MFA), learn more about it with <a href="https://docs.microsoft.com/en-us/azure/multi-factor-authentication/multi-factor-authentication" target="_blank" rel="nofollow noopener noreferrer">this short video</a>.</p> <p>I am not going to go through all of its features, however you can find enough information <a href="https://azure.microsoft.com/en-au/services/active-directory-b2c/" target="_blank" rel="nofollow noopener noreferrer">here</a>.</p> <p>In these blog series I will talk about how you can integrate your application into Azure B2C and use some of its features via <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api" target="_blank" rel="nofollow noopener noreferrer">GraphAPI</a>.</p> <h2 id="setup-your-b2c-tenant" style="position:relative;"><a href="#setup-your-b2c-tenant" aria-label="setup your b2c tenant permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup your B2C tenant</h2> <p>First of all you need to setup a B2C tenant (or more if you have a multi tenant application). There are many good articles on how to set it up, but I used <a href="https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-get-started" target="_blank" rel="nofollow noopener noreferrer">this</a> from <a href="https://www.microsoft.com/en-au" target="_blank" rel="nofollow noopener noreferrer">Microsoft</a> official documentation.</p> <h2 id="register-your-application" style="position:relative;"><a href="#register-your-application" aria-label="register your 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>Register your application</h2> <p>You will need an application in order to talk to the login endpoint provided by Azure B2C. This is very important because this application contains the information about your application such as reply URL. Simply follow <a href="https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-app-registration#navigate-to-b2c-settings" target="_blank" rel="nofollow noopener noreferrer">this</a> link to set it up. Don’t forget to setup the <strong>scopes</strong> as you might spend hours trying to figure out why you are getting unauthorised error from Azure login endpoint.</p> <p>The below picture demonstrates the screen you will need to fill in.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 576px; " > <a class="gatsby-resp-image-link" href="/static/b28abea37128d544a09907dc81561ab2/533c1/b2c-new-app-settings.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 112.59259259259258%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAAACXBIWXMAABnWAAAZ1gEY0crtAAACT0lEQVR42qWUy27aQBiF51nonk2KFJE+Syqk3LrOK7SvkqpSpOYF2kptpapZtOolEIiCbXzBHt9B4LHH9uk/hEZZRCSEX/o04IHj+c/MGdZqtbDTbqNNvGjv4PnWFhrPGmg01mN7exvNZhNsb38fewcHODg8wuHRK6jvuy9312af/tfpdMCE58K6+INQ11D4HmSSopYg6rWQQqIqK7DcGiG+vEByPUDc70HaNqoCkFm5BhXETKDIcrB0miKMfQQBR+B5cEgwThKoqut6LVQx60cf5yefoP++hEui3PfhE1VV4SnFBu++42z3LcZfexBVvvBhk2KTNEIQeQgDH5xzzOfzzQTd3iXOP3+DNxggSRNIKTcTzPIcspCoybOyLBfeqfE+1NwqFoJ/NRPdoQ5n7EA3TZi0y8ZoBF3XMaJRYRgGTMtEQrufpum9qLmiKMBm0wlS7iImQeQCdTZHvVxNveT/58d5+LOPbreHq6traEMDmqaD2w58spIXNfwl/AFcUSKjo8iSoYUxibjUmq1pcKm9iA54lEtEong03nSGnLpgZUlLuaVcjJVUubyDfJiC7KJsgUVxBJdW5HKK3XgM27GRk7nq+CiTpRJUPlK0VnEbvQltShhFiON4ETk/CCjL8Q30XM0XyxesQv1GvZhNJuniMkhIYD6bYdNiYRjAsiyYjgPDGSMIow2TkgmktMJBOMVHncOfiZur66mCd6+p6k78noLaGGZbHL+6JkFtG3x5sW7Q8tn7Lzh+fYrjN6c4OflAj0rMswxCiLXJ8xz/AHxqp4VTvEgMAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="New B2C App" title="" src="/static/b28abea37128d544a09907dc81561ab2/533c1/b2c-new-app-settings.png" srcset="/static/b28abea37128d544a09907dc81561ab2/01bf6/b2c-new-app-settings.png 270w, /static/b28abea37128d544a09907dc81561ab2/07484/b2c-new-app-settings.png 540w, /static/b28abea37128d544a09907dc81561ab2/533c1/b2c-new-app-settings.png 576w" sizes="(max-width: 576px) 100vw, 576px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>The most important things you will need at the end of these steps are the <strong>application Id</strong> and <strong>secret key</strong> which you will generate on the keys menu. Also make sure the reply URL is pointing to where you handle the login callback (either on client or server side).</p> <h2 id="setup-mfa" style="position:relative;"><a href="#setup-mfa" aria-label="setup mfa permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup MFA</h2> <p>The only thing that you cannot do through the new Azure portal is to create the MFA, which you can do via the <a href="https://manage.windowsazure.com/" target="_blank" rel="nofollow noopener noreferrer">classic portal</a>. The instructions to setup the MFA can be found here.</p> <p>Unfortunately the soft tokens are not available with the default MFA settings (you will need a <a href="https://docs.microsoft.com/en-us/azure/multi-factor-authentication/multi-factor-authentication-get-started" target="_blank" rel="nofollow noopener noreferrer">MFA server</a>), but you can use SMS or email verification.</p> <h2 id="create-your-policies" style="position:relative;"><a href="#create-your-policies" aria-label="create your policies permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 policies</h2> <p>The authentication flows are handled by <a href="https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-policies" target="_blank" rel="nofollow noopener noreferrer">policies</a> on Azure B2C. There are some default policies you can setup and use or you can opt in to use custom policies which give you more options but are harder to manage.</p> <p>You can simply get started by using one of sign-in or sign-up policies. This <a href="https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-policies" target="_blank" rel="nofollow noopener noreferrer">article</a> shows you how to set one up. Next you can setup a <a href="https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-policies#create-a-password-reset-policy" target="_blank" rel="nofollow noopener noreferrer">password reset policy</a> if you want to allow users to reset their passwords.</p> <p>After you setup the policies you can check the metadata endpoint by hitting metadata URL (replace the tenant and policy with yours):</p> <div class="custom-block info"><div class="custom-block-body"> <a href="https://login.microsoftonline.com/your-tenant-domain-qualifier/v2.0/.well-known/openid-configuration?p=your-policy-name" target="_blank" rel="nofollow noopener noreferrer">https://login.microsoftonline.com/your-tenant-domain-qualifier/v2.0/.well-known/openid-configuration?p=your-policy-name</a></div></div> <p>You can find the same link at the bottom of the policy details page where you can test the policy alone.</p> <h2 id="configurations-and-customisations" style="position:relative;"><a href="#configurations-and-customisations" aria-label="configurations and customisations permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Configurations and customisations</h2> <p>There are some default settings for token, session and single sign-on configuration, which you can use. However, if you have some requirement which force you to customise these settings, <a href="https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-token-session-sso" target="_blank" rel="nofollow noopener noreferrer">this link</a> contains the required information.</p> <h2 id="authorisation-flow" style="position:relative;"><a href="#authorisation-flow" aria-label="authorisation flow permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Authorisation flow</h2> <p>So far we saw how to setup the B2C to get it to a point where you can use it in your application. At this point you will need to follow three simple steps to successfully authenticate someone.</p> <ol> <li>Get an authorization code</li> <li>Get a token</li> <li>Use the token</li> </ol> <p>You can also refresh the token if you want, and before you think of these terms I have to say yes these are all part of OAuth 2.0 authorisation code flow.</p> <p>In the next blog post I will show you some code and samples which will help you integrate your application and also use some of the features that are available only via GraphAPI.</p><![CDATA[Generate a self sign cert with PowerShell]]>https://yashints.dev/blog/2017/06/22/generate-a-self-sign-cert-with-powershellhttps://yashints.dev/blog/2017/06/22/generate-a-self-sign-cert-with-powershellThu, 22 Jun 2017 09:23:00 GMT<p>Have ever been stumbled upon needing a certificate very fast and looking for tools for hours? Well I found a series of <code class="language-text">PowerShell</code> commands which makes your life super easy.</p> <!--more--> <p>I am sure there are many people who’ve tried <code class="language-text">OpenSSL</code>, <code class="language-text">MakeCert.exe</code>, <code class="language-text">IIS</code> or may other tools and spend hours searching to generate a <code class="language-text">self-sign</code> certificate for testing or other purposes.</p> <p>Well with <code class="language-text">PowerShell</code> it can be this easy. The commands you need are <code class="language-text">New-SelfSignedCertificate</code> and <code class="language-text">Export-PfxCertificate</code>. The way you use them is as follows.</p> <div class="gatsby-code-button-container" data-toaster-id="3353405649458874000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname yourdomainname`, `3353405649458874000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell"><span class="token function">New-SelfSignedCertificate</span> <span class="token operator">-</span>certstorelocation cert:\localmachine\my <span class="token operator">-</span>dnsname yourdomainname</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can put whatever you like as your domain name, which will be put in the subject.</p> <p>Running this command will generate a certificate and prints out the thumbprint for you which you will need if you want to export your certificate.</p> <p>You will need a password to export your certificate which you can define it as a variable:</p> <div class="gatsby-code-button-container" data-toaster-id="44303343407719530000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\$pwd = ConvertTo-SecureString -String &quot;P@\$sw0rd&quot; -Force -AsPlainText`, `44303343407719530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell"><span class="token variable">$pwd</span> = <span class="token function">ConvertTo-SecureString</span> <span class="token operator">-</span>String <span class="token string">"P@<span class="token variable">$sw0rd</span>"</span> <span class="token operator">-</span>Force <span class="token operator">-</span>AsPlainText</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And finally you can export your certificate by using export command:</p> <div class="gatsby-code-button-container" data-toaster-id="8378510761735725000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`Export-PfxCertificate -cert cert:\localMachine\my\{thumbprint} \` -FilePath d:\temp\cert.pfx -Password \$pwd`, `8378510761735725000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell"><span class="token function">Export-PfxCertificate</span> <span class="token operator">-</span>cert cert:\localMachine\my\<span class="token punctuation">{</span>thumbprint<span class="token punctuation">}</span> ` <span class="token operator">-</span>FilePath d:\temp\cert<span class="token punctuation">.</span>pfx <span class="token operator">-</span>Password <span class="token variable">$pwd</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>You will need to replace the <code class="language-text">{thumbprint}</code> with the thumbprint you got from the execution of the first command.</p> <p>And Voila, you’ve got a PFX file containing your private key which you can use.</p><![CDATA[Using client certificates for ASP.Net Core App hosted on Azure Web App service]]>https://yashints.dev/blog/2017/05/03/client-certificates-aspnetcore-azure-webapphttps://yashints.dev/blog/2017/05/03/client-certificates-aspnetcore-azure-webappWed, 03 May 2017 00:00:00 GMT<p>Recently we had to communicate with an external API featuring <a href="https://en.wikipedia.org/wiki/Mutual_authentication" target="_blank" rel="nofollow noopener noreferrer">mutual authentication</a> using client certificates (AKA two way SSL).</p> <!--more--> <p>We were using ASP.Net Core hosted on Azure Web App service and had to call the API’s using <a href="https://msdn.microsoft.com/en-us/library/system.net.http.httpclient(v=vs.110).aspx" target="_blank" rel="nofollow noopener noreferrer">HTTPClient</a> (There is another way of enabling this on Azure using <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview" target="_blank" rel="nofollow noopener noreferrer">Azure Resource Manager</a> which I will mention later).</p> <h1 id="upload-your-certificate" style="position:relative;"><a href="#upload-your-certificate" aria-label="upload your certificate permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Upload your certificate</h1> <p>The very first thing you will need to achieve this is a certificate. The only thing that matters when you are uploading your certificate to Azure is that it should match the domain you are using.</p> <p>I’ve tried to use the default certificate but no luck since it is a wild card and Azure won’t load that in certificate store for your web app (it is a shared service).</p> <p>You can upload your certificate by following the steps in <a href="https://azure.microsoft.com/en-au/blog/using-certificates-in-azure-websites-applications/" target="_blank" rel="nofollow noopener noreferrer">this</a> <a href="https://www.microsoft.com/en-au/" target="_blank" rel="nofollow noopener noreferrer">Microsoft</a> blog post. It is very detailed with pictures for each step and easy to follow.</p> <p>When you are finished with that all you need to do is to capture the thumbprint of your certificate which you can find on your SSL certificates menu on the Web App page.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/8ee2a2780c8d8bd3622476a194e00117/c352c/cert.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 46.29629629629629%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAdu1Yhh//8QAFhAAAwAAAAAAAAAAAAAAAAAAARAR/9oACAEBAAEFAjag/wD/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAWEAADAAAAAAAAAAAAAAAAAAABESD/2gAIAQEABj8CCr//xAAZEAABBQAAAAAAAAAAAAAAAAAQARExQWH/2gAIAQEAAT8hpGuhif/aAAwDAQACAAMAAAAQYw//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxAn/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGhABAAIDAQAAAAAAAAAAAAAAAQARIEFRof/aAAgBAQABPxAMGDZH0Soj1lYf/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Certificate" title="" src="/static/8ee2a2780c8d8bd3622476a194e00117/47311/cert.jpg" srcset="/static/8ee2a2780c8d8bd3622476a194e00117/6f81f/cert.jpg 270w, /static/8ee2a2780c8d8bd3622476a194e00117/09d21/cert.jpg 540w, /static/8ee2a2780c8d8bd3622476a194e00117/47311/cert.jpg 1080w, /static/8ee2a2780c8d8bd3622476a194e00117/c352c/cert.jpg 1464w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>The way we’ve implemented this is to have different certificates for each web app with its own domain and then we’ve put them in <code class="language-text">appSettings.[env].json</code> files.</p> <p>This will make our lives easier because we don’t have deal with <code class="language-text">.pfx</code> files and their passwords, and in the other hand we don’t have to hard code any thumbprint in our code (remember that they will change when you renew a certificate at some point).</p> <h1 id="load-the-certificate" style="position:relative;"><a href="#load-the-certificate" aria-label="load the certificate permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Load the certificate</h1> <p>Now the only thing remaining is to access the certificate inside your code. Before that you will need to let Azure know you are going to access it otherwise it won’t load them for you.</p> <p>This is done using an application settings called <code class="language-text">WEBSITE_LOAD_CERTIFICATES</code> which you can set on your application settings section.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1007px; " > <a class="gatsby-resp-image-link" href="/static/8ff002d527e6c2044eaec811d63478ab/c30b1/loadcertappsetting.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 15.555555555555555%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAADABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAduggL//xAAVEAEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAQABBQIv/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BJ//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABYQAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAQABPyEq/wD/2gAMAwEAAgADAAAAEPvP/8QAFREBAQAAAAAAAAAAAAAAAAAAEDH/2gAIAQMBAT8Qg//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/EGf/xAAWEAADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQEAAT8QcjpCH//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Load Certificate" title="" src="/static/8ff002d527e6c2044eaec811d63478ab/c30b1/loadcertappsetting.jpg" srcset="/static/8ff002d527e6c2044eaec811d63478ab/6f81f/loadcertappsetting.jpg 270w, /static/8ff002d527e6c2044eaec811d63478ab/09d21/loadcertappsetting.jpg 540w, /static/8ff002d527e6c2044eaec811d63478ab/c30b1/loadcertappsetting.jpg 1007w" sizes="(max-width: 1007px) 100vw, 1007px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>For the value you can set either your <strong>thumbprint</strong> or <strong>*</strong> which means it will load all the available certificates. I found <a href="https://azure.microsoft.com/en-au/blog/using-certificates-in-azure-websites-applications/" target="_blank" rel="nofollow noopener noreferrer">this</a> blog useful about how to do this step.</p> <p>Once you’ve done this, it is only the matter of loading the certificate from the store. The bellow code shows you how you can do this:</p> <div class="gatsby-code-button-container" data-toaster-id="94098561008932680000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`private HttpClient CreateHttpClient(IConfiguration configuration) { var handler = new HttpClientHandler(); httpClient = new HttpClient(handler); X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); certStore.Open(OpenFlags.ReadOnly); X509Certificate2Collection certCollection = certStore.Certificates.Find( X509FindType.FindByThumbprint, configuration.GetValue<string>(&quot;CertificateThumbprint&quot;), false); // Get the first cert with the thumbprint if (certCollection.Count > 0) { X509Certificate2 cert = certCollection[0]; handler.ClientCertificateOptions = ClientCertificateOption.Manual; handler.SslProtocols = SslProtocols.Tls12; handler.ClientCertificates.Add(cert); } certStore.Close(); return httpClient; }`, `94098561008932680000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-csharp line-numbers"><code class="language-csharp"><span class="token keyword">private</span> <span class="token return-type class-name">HttpClient</span> <span class="token function">CreateHttpClient</span><span class="token punctuation">(</span><span class="token class-name">IConfiguration</span> configuration<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword">var</span></span> handler <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">HttpClientHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> httpClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">HttpClient</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">X509Store</span> certStore <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">X509Store</span><span class="token punctuation">(</span>StoreName<span class="token punctuation">.</span>My<span class="token punctuation">,</span> StoreLocation<span class="token punctuation">.</span>CurrentUser<span class="token punctuation">)</span><span class="token punctuation">;</span> certStore<span class="token punctuation">.</span><span class="token function">Open</span><span class="token punctuation">(</span>OpenFlags<span class="token punctuation">.</span>ReadOnly<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">X509Certificate2Collection</span> certCollection <span class="token operator">=</span> certStore<span class="token punctuation">.</span>Certificates<span class="token punctuation">.</span><span class="token function">Find</span><span class="token punctuation">(</span> X509FindType<span class="token punctuation">.</span>FindByThumbprint<span class="token punctuation">,</span> configuration<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetValue</span><span class="token generic class-name"><span class="token punctuation">&lt;</span><span class="token keyword">string</span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token string">"CertificateThumbprint"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Get the first cert with the thumbprint</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>certCollection<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> <span class="token class-name">X509Certificate2</span> cert <span class="token operator">=</span> certCollection<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> handler<span class="token punctuation">.</span>ClientCertificateOptions <span class="token operator">=</span> ClientCertificateOption<span class="token punctuation">.</span>Manual<span class="token punctuation">;</span> handler<span class="token punctuation">.</span>SslProtocols <span class="token operator">=</span> SslProtocols<span class="token punctuation">.</span>Tls12<span class="token punctuation">;</span> handler<span class="token punctuation">.</span>ClientCertificates<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>cert<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> certStore<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">return</span> httpClient<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <div class="custom-block info"><div class="custom-block-body"> <strong>Note:</strong> This code snippet is just a sample and the intention is only to show you how to load a certificate, moreover, it is not a best practice.</div></div> <p>The other thing to keep in mind is to provide an HTTPS address for your HTTPClient otherwise it wouldn’t be two way authentication.</p> <h1 id="enable-client-certificate-on-azure" style="position:relative;"><a href="#enable-client-certificate-on-azure" aria-label="enable client certificate on azure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Enable client certificate on Azure</h1> <p>The other way you can achieve this is to configure the <code class="language-text">mutual authentication</code> on Azure itself rather than doing it manual like above. <a href="https://docs.microsoft.com/en-us/azure/app-service-web/app-service-web-configure-tls-mutual-auth" target="_blank" rel="nofollow noopener noreferrer">This</a> blog post is a very good resource for doing this, however I will summarise it here as well.</p> <p>All you need is this code snippet to enable it:</p> <div class="gatsby-code-button-container" data-toaster-id="61469590859767660000" data-toaster-class="gatsby-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;location&quot;: &quot;My Web App Location&quot;, &quot;properties&quot;: { &quot;clientCertEnabled&quot;: true } }`, `61469590859767660000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"My Web App Location"</span><span class="token punctuation">,</span> <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"clientCertEnabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>You will need to replace the <code class="language-text">location</code> value with your web app location. You can update this using Azure Resource Manager as well if you are not using <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates" target="_blank" rel="nofollow noopener noreferrer">ARM templates</a>.</p> <p>And as mentioned in the blog post for <code class="language-text">ARM Template</code> from <code class="language-text">Powershell</code>, you will need to escape the <code class="language-text">@</code> symbol for the JSON file with a back tick <strong>`</strong>.</p> <p>Also note this will enable the <code class="language-text">mutual authentication</code> for all the services under this Web App and makes it mandatory. So if you have just a web app and you don’t want your normal clients to use a client certificate don’t use this option.</p><![CDATA[Setting up VSTS CI/CD for a SPA app using AngularCLI, ASPNetCore (Part 1)]]>https://yashints.dev/blog/2017/04/27/vsts-cicd-angularcli-aspnetcorehttps://yashints.dev/blog/2017/04/27/vsts-cicd-angularcli-aspnetcoreThu, 27 Apr 2017 00:00:00 GMT<p>Recently I was assigned to a green field project where we had to create an initial structure of a project which was going to be written in <a href="https://angular.io/" target="_blank" rel="nofollow noopener noreferrer">Angular 2</a> using <a href="https://github.com/angular/angular-cli" target="_blank" rel="nofollow noopener noreferrer">Angular CLI</a> for front end side and ASP.Net Core for back-end.</p> <!--more--> <p>We had to use <a href="https://www.visualstudio.com/team-services/" target="_blank" rel="nofollow noopener noreferrer">VSTS</a> (Visual Studio Team Services) as our source control and build and deployment pipeline. The result was then deployed to <a href="https://azure.microsoft.com/en-au/services/app-service/web/" target="_blank" rel="nofollow noopener noreferrer">Azure Web Apps</a> and the aim was to make this happen.</p> <p>After some digging and trying the new version of <a href="https://www.visualstudio.com/vs/whatsnew/" target="_blank" rel="nofollow noopener noreferrer">Visual Studio 2017</a> and setting the initial build steps, I found out that VSTS does not support the <code class="language-text">csproj</code> files yet. Therefore, I had to go back and use visual studio 2015 with <code class="language-text">project.json</code> file.</p> <p>On the other hand since we were using Angular CLI we couldn’t merge it easily in one project with our ASP.Net Core project since it hides the actual webpack config file.</p> <p>At least it wasn’t something we could do quickly and we had to prepare a <a href="https://en.wikipedia.org/wiki/Proof_of_concept" target="_blank" rel="nofollow noopener noreferrer">POC</a> to get a taste of what was going to happen in the product.</p> <p>So I started googling and found a good <a href="http://asp.net-hacker.rocks/2016/09/19/aspnetcore-and-angular2-using-dotnetcli-and-vscode.html" target="_blank" rel="nofollow noopener noreferrer">article</a> from <strong>Jürgen Gutsch</strong> showing how to simply merge them using two different projects and a simple front end build before building the web app.</p> <p>I won’t go into too much details here, but basically you would build the Angular project and modify the config to write the output files into <code class="language-text">wwwroot</code> folder. Yes I know, simple.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 200px; " > <a class="gatsby-resp-image-link" href="/static/3cac19ec7e7b41ec7f240e5035a0f79b/e07e9/simples.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 101%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAQDAgX/xAAYAQACAwAAAAAAAAAAAAAAAAABAwACBP/aAAwDAQACEAMQAAAB8+vCqGV2bmk0GNxFh//EABwQAAICAgMAAAAAAAAAAAAAAAIRAAEDEBIhIv/aAAgBAQABBQKvMBmR12KIcPEZltmNqPX/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREQ/9oACAEDAQE/AVILf//EABkRAAIDAQAAAAAAAAAAAAAAAAACARARMf/aAAgBAgEBPwF90XhNf//EABsQAAICAwEAAAAAAAAAAAAAAAARAQIQEjEy/9oACAEBAAY/AmhRWJrjVoWwzh5jH//EABwQAQADAAIDAAAAAAAAAAAAAAEAESExcRBBgf/aAAgBAQABPyFJBZX2RheDmpWMrOIxuwv7CLZZO+EsOHuJyh8f/9oADAMBAAIAAwAAABBgCAD/xAAXEQEBAQEAAAAAAAAAAAAAAAABEQAQ/9oACAEDAQE/EKRlSmOf/8QAGBEBAAMBAAAAAAAAAAAAAAAAAQAQETH/2gAIAQIBAT8QIexuZ1X/xAAcEAEBAAIDAQEAAAAAAAAAAAABEQAhMUFxEJH/2gAIAQEAAT8QF3KWgGbAEoafcK+7bHDXHvqB0Bw5GlSwZ3hAE5NeuUCNJDTCg0F0PP78/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="simples" title="" src="/static/3cac19ec7e7b41ec7f240e5035a0f79b/e07e9/simples.jpg" srcset="/static/3cac19ec7e7b41ec7f240e5035a0f79b/e07e9/simples.jpg 200w" sizes="(max-width: 200px) 100vw, 200px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>By now your project structure may be looking like this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 919px; " > <a class="gatsby-resp-image-link" href="/static/57613e5a904cd18d5c8a55b6a5cd8e7f/4d723/project.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 73.7037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUBBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAGn0zqCaD//xAAaEAEAAwADAAAAAAAAAAAAAAABAAIRBBIi/9oACAEBAAEFAtNydY8RbhYPU//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/AVf/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQIBAT8BiY//xAAdEAABAwUBAAAAAAAAAAAAAAABAAIxEBMhYZGS/9oACAEBAAY/Apb6qXXTnSkcUji//8QAGxAAAwACAwAAAAAAAAAAAAAAAAERMWGRwfD/2gAIAQEAAT8hakS3WBLMvkjZEA9AiK0E9XZ//9oADAMBAAIAAwAAABCsL//EABcRAAMBAAAAAAAAAAAAAAAAAAABEVH/2gAIAQMBAT8QrKw//8QAFxEBAAMAAAAAAAAAAAAAAAAAABFhcf/aAAgBAgEBPxCNMn//xAAdEAACAgEFAAAAAAAAAAAAAAABEQAhQTFxgZHx/9oACAEBAAE/EBsoaNgbCGAWPIZwmOs5rwVVvq5XfAGSZXM9ZH//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Project Structure" title="" src="/static/57613e5a904cd18d5c8a55b6a5cd8e7f/4d723/project.jpg" srcset="/static/57613e5a904cd18d5c8a55b6a5cd8e7f/6f81f/project.jpg 270w, /static/57613e5a904cd18d5c8a55b6a5cd8e7f/09d21/project.jpg 540w, /static/57613e5a904cd18d5c8a55b6a5cd8e7f/4d723/project.jpg 919w" sizes="(max-width: 919px) 100vw, 919px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>That done, I started to setup the VSTS build steps. Well that is very straight forward, you just have to give the steps the right order so start by create an empty build.</p> <p><strong>1. Get the source code</strong></p> <p>The very first step is to get the source from source control. Define your repository and the branch you are working on.</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/1379ac9db0a62c0ab66d56a6f5fdb697/907fc/getsource.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAG6AD//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAYEAACAwAAAAAAAAAAAAAAAAAAEQEQIf/aAAgBAQABPyFKDa//2gAMAwEAAgADAAAAEIPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGRABAQEAAwAAAAAAAAAAAAAAAREAQZGh/9oACAEBAAE/EFo3zBJZcDy9b//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Get Source" title="" src="/static/1379ac9db0a62c0ab66d56a6f5fdb697/47311/getsource.jpg" srcset="/static/1379ac9db0a62c0ab66d56a6f5fdb697/6f81f/getsource.jpg 270w, /static/1379ac9db0a62c0ab66d56a6f5fdb697/09d21/getsource.jpg 540w, /static/1379ac9db0a62c0ab66d56a6f5fdb697/47311/getsource.jpg 1080w, /static/1379ac9db0a62c0ab66d56a6f5fdb697/0047d/getsource.jpg 1620w, /static/1379ac9db0a62c0ab66d56a6f5fdb697/274e1/getsource.jpg 2160w, /static/1379ac9db0a62c0ab66d56a6f5fdb697/907fc/getsource.jpg 2571w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>2. Restore dot net packages</strong></p> <p>Add a command line task and name it restore (you can call it something else this is just to make each step clear). Then type <code class="language-text">dotnet</code> in the tool text box and <code class="language-text">restore</code> in the arguments.</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/8f8658a58b44c8d17dd9f673a4f36f99/11e85/restore.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 34.81481481481482%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAHABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3aAH/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFxAAAwEAAAAAAAAAAAAAAAAAARARQf/aAAgBAQABPyGGY//aAAwDAQACAAMAAAAQAA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAgMAAAAAAAAAAAAAAAABABEhMYH/2gAIAQEAAT8QAugazUNTrP/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Restore Packages" title="" src="/static/8f8658a58b44c8d17dd9f673a4f36f99/47311/restore.jpg" srcset="/static/8f8658a58b44c8d17dd9f673a4f36f99/6f81f/restore.jpg 270w, /static/8f8658a58b44c8d17dd9f673a4f36f99/09d21/restore.jpg 540w, /static/8f8658a58b44c8d17dd9f673a4f36f99/47311/restore.jpg 1080w, /static/8f8658a58b44c8d17dd9f673a4f36f99/0047d/restore.jpg 1620w, /static/8f8658a58b44c8d17dd9f673a4f36f99/274e1/restore.jpg 2160w, /static/8f8658a58b44c8d17dd9f673a4f36f99/11e85/restore.jpg 2533w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>3. Versioning if intended</strong></p> <p>If you care about versioning this is the time for it. What we chose to follow was <a href="http://semver.org/" target="_blank" rel="nofollow noopener noreferrer">SemVer</a> so we put the major and minor numbers in <code class="language-text">project.json</code> and got the rest from date and revision.</p> <p>Then all we had to do was to create a <code class="language-text">PowerShell</code> script which extracted those and put them together to form the complete version and set it in <code class="language-text">project.json</code> and <code class="language-text">AssemblyInfo</code> files.</p> <p>The <code class="language-text">PowerShell</code> script would as simple as:</p> <div class="gatsby-code-button-container" data-toaster-id="17495858933081055000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`Write-Output &quot;Getting version from Build number&quot; \$jsonpath = &quot;\$Env:WebSourceFolder\project.json&quot; \$json = Get-Content -Path \$jsonpath -Raw | ConvertFrom-Json -ErrorAction Ignore \$BuildVersion = [regex]::matches(\$Env:BUILD_BUILDNUMBER, &quot;\d+\.\d+&quot;) Write-Output &quot;Build Version extracted =&gt; \$BuildVersion&quot; \$Version = \$json.version + &quot;.&quot; + \$BuildVersion Write-Output &quot;App Version constructed =&gt; \$Version&quot; \$json.version = \$Version \$json | ConvertTo-Json -depth 100 | Out-File \$jsonpath Write-Output &quot;Applied Version&quot;</pre>`, `17495858933081055000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell"><span class="token function">Write-Output</span> <span class="token string">"Getting version from Build number"</span> <span class="token variable">$jsonpath</span> = <span class="token string">"<span class="token variable">$Env</span>:WebSourceFolder\project.json"</span> <span class="token variable">$json</span> = <span class="token function">Get-Content</span> <span class="token operator">-</span>Path <span class="token variable">$jsonpath</span> <span class="token operator">-</span>Raw <span class="token punctuation">|</span> <span class="token function">ConvertFrom-Json</span> <span class="token operator">-</span>ErrorAction Ignore <span class="token variable">$BuildVersion</span> = <span class="token namespace">[regex]</span>::matches<span class="token punctuation">(</span><span class="token variable">$Env</span>:BUILD_BUILDNUMBER<span class="token punctuation">,</span> <span class="token string">"\d+\.\d+"</span><span class="token punctuation">)</span> <span class="token function">Write-Output</span> <span class="token string">"Build Version extracted =&amp;gt; <span class="token variable">$BuildVersion</span>"</span> <span class="token variable">$Version</span> = <span class="token variable">$json</span><span class="token punctuation">.</span>version <span class="token operator">+</span> <span class="token string">"."</span> <span class="token operator">+</span> <span class="token variable">$BuildVersion</span> <span class="token function">Write-Output</span> <span class="token string">"App Version constructed =&amp;gt; <span class="token variable">$Version</span>"</span> <span class="token variable">$json</span><span class="token punctuation">.</span>version = <span class="token variable">$Version</span> <span class="token variable">$json</span> <span class="token punctuation">|</span> <span class="token function">ConvertTo-Json</span> <span class="token operator">-</span>depth 100 <span class="token punctuation">|</span> <span class="token function">Out-File</span> <span class="token variable">$jsonpath</span> <span class="token function">Write-Output</span> <span class="token string">"Applied Version"</span>&lt;<span class="token operator">/</span>pre></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><strong>4. Run the versioning script in build</strong></p> <p>As you can see we are extracting the major and minor from <code class="language-text">project.json</code> and date and revision from build number. In order to set that in the first place you need to define the build output format as follow in the options tab of the build:</p> <div class="gatsby-code-button-container" data-toaster-id="72946545702890780000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\$(BuildDefinitionName)_\$(Year:yy)\$(DayOfYear)\$(rev:.rr)`, `72946545702890780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">$<span class="token punctuation">(</span>BuildDefinitionName<span class="token punctuation">)</span>_$<span class="token punctuation">(</span>Year:yy<span class="token punctuation">)</span>$<span class="token punctuation">(</span>DayOfYear<span class="token punctuation">)</span>$<span class="token punctuation">(</span>rev:<span class="token punctuation">.</span>rr<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>Now you can create a <code class="language-text">PowerShell</code> task and run this script and name it versioning. Leave the type to “File Path” and write the script path inside its box.</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/9312a7cd03cf2c6e68f6a7c38badcb20/f642c/version.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.48148148148149%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3aAH/8QAFRABAQAAAAAAAAAAAAAAAAAAEEH/2gAIAQEAAQUCh//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABcQAAMBAAAAAAAAAAAAAAAAAAEQITH/2gAIAQEAAT8huhX/AP/aAAwDAQACAAMAAAAQAA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAACAgMBAAAAAAAAAAAAAAAAAREhMUFxgf/aAAgBAQABPxBJaChcMWN+kdP/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Versioning" title="" src="/static/9312a7cd03cf2c6e68f6a7c38badcb20/47311/version.jpg" srcset="/static/9312a7cd03cf2c6e68f6a7c38badcb20/6f81f/version.jpg 270w, /static/9312a7cd03cf2c6e68f6a7c38badcb20/09d21/version.jpg 540w, /static/9312a7cd03cf2c6e68f6a7c38badcb20/47311/version.jpg 1080w, /static/9312a7cd03cf2c6e68f6a7c38badcb20/0047d/version.jpg 1620w, /static/9312a7cd03cf2c6e68f6a7c38badcb20/274e1/version.jpg 2160w, /static/9312a7cd03cf2c6e68f6a7c38badcb20/f642c/version.jpg 2521w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>5. Building the solution</strong></p> <p>Time to build the solution. Create a “Visual Studio Build” task and write the solution file’s path (leave it as default which usually works), then <code class="language-text">$(BuildPlatform)</code> in the platform box. Don’t forget to change the Visual Studio version to 2015, otherwise your build will fail.</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/761f5a4d558b5dec3d82bfb8595aff01/3c389/build.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 60%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe5qwA//xAAVEAEBAAAAAAAAAAAAAAAAAAAgQf/aAAgBAQABBQKH/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAIP/aAAgBAQAGPwJf/8QAGRAAAgMBAAAAAAAAAAAAAAAAARAAETFB/9oACAEBAAE/IR1VFnIMX//aAAwDAQACAAMAAAAQgA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAEAAgEFAAAAAAAAAAAAAAABABEhEDFRcYH/2gAIAQEAAT8QY2LgqBgtns3+pmNP/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Building Solution" title="" src="/static/761f5a4d558b5dec3d82bfb8595aff01/47311/build.jpg" srcset="/static/761f5a4d558b5dec3d82bfb8595aff01/6f81f/build.jpg 270w, /static/761f5a4d558b5dec3d82bfb8595aff01/09d21/build.jpg 540w, /static/761f5a4d558b5dec3d82bfb8595aff01/47311/build.jpg 1080w, /static/761f5a4d558b5dec3d82bfb8595aff01/0047d/build.jpg 1620w, /static/761f5a4d558b5dec3d82bfb8595aff01/274e1/build.jpg 2160w, /static/761f5a4d558b5dec3d82bfb8595aff01/3c389/build.jpg 2540w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>6. Installing npm packages</strong></p> <p>Ok we’re now done with server side steps apart from any possible tests. Time to build our client side app for which first you should restore all of <code class="language-text">npm</code> packages.</p> <p>You can do this by creating a <code class="language-text">npm</code> task which by default it will be prepared for install so leave the defaults as is. If there are any changes in future and you don’t see the command, just type <code class="language-text">install</code> in the npm command box.</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/9401bc4e657c5b9cb8a97ebbae591ce5/03e07/npminstall.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.074074074074076%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAdynIwD/xAAVEAEBAAAAAAAAAAAAAAAAAAAgQf/aAAgBAQABBQKH/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAIP/aAAgBAQAGPwJf/8QAFxAAAwEAAAAAAAAAAAAAAAAAARAxkf/aAAgBAQABPyEaZj//2gAMAwEAAgADAAAAEJAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBABAAIBBQAAAAAAAAAAAAAAAQARMRAhQWGR/9oACAEBAAE/EGJUpHBA2ldvsywwaf/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="NPM Install" title="" src="/static/9401bc4e657c5b9cb8a97ebbae591ce5/47311/npminstall.jpg" srcset="/static/9401bc4e657c5b9cb8a97ebbae591ce5/6f81f/npminstall.jpg 270w, /static/9401bc4e657c5b9cb8a97ebbae591ce5/09d21/npminstall.jpg 540w, /static/9401bc4e657c5b9cb8a97ebbae591ce5/47311/npminstall.jpg 1080w, /static/9401bc4e657c5b9cb8a97ebbae591ce5/0047d/npminstall.jpg 1620w, /static/9401bc4e657c5b9cb8a97ebbae591ce5/274e1/npminstall.jpg 2160w, /static/9401bc4e657c5b9cb8a97ebbae591ce5/03e07/npminstall.jpg 2539w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>7. Run JS tests</strong></p> <p>If you have any JS tests this is the time to run them. By default the <code class="language-text">Angular CLI</code> is setup in a way that the tests can be executed using <code class="language-text">npm test</code> command. So create another <code class="language-text">npm</code> task and call it “run js tests”.</p> <p>The only thing to remember is that you have to set the working folder (I am using build variables but you can fully type that) correct, this is where you specify your Angular project root folder. Now the only thing left is to write <code class="language-text">test</code> in the command box.</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/e6859e6e51c001926b952b863d1175a3/5deef/jstests.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.48148148148149%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3KAD/8QAFhAAAwAAAAAAAAAAAAAAAAAAARAx/9oACAEBAAEFAhF//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFxAAAwEAAAAAAAAAAAAAAAAAARARYf/aAAgBAQABPyErp//aAAwDAQACAAMAAAAQgA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAgMAAAAAAAAAAAAAAAABABEhQWH/2gAIAQEAAT8QAVoRqBgldZ//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="JS Tests" title="" src="/static/e6859e6e51c001926b952b863d1175a3/47311/jstests.jpg" srcset="/static/e6859e6e51c001926b952b863d1175a3/6f81f/jstests.jpg 270w, /static/e6859e6e51c001926b952b863d1175a3/09d21/jstests.jpg 540w, /static/e6859e6e51c001926b952b863d1175a3/47311/jstests.jpg 1080w, /static/e6859e6e51c001926b952b863d1175a3/0047d/jstests.jpg 1620w, /static/e6859e6e51c001926b952b863d1175a3/274e1/jstests.jpg 2160w, /static/e6859e6e51c001926b952b863d1175a3/5deef/jstests.jpg 2517w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>8. Build the client application</strong></p> <p>Time has come to build the Angular project. This can be done by running another <code class="language-text">npm</code> task. You just have to make sure that you have already defined the <code class="language-text">ng</code> command to run <code class="language-text">Angular CLI</code>.</p> <p>All you need to do now is to type <code class="language-text">run</code> as command and then “ng build” as argument. This step is the key since it will build the client project, bundle everything and copy them into <code class="language-text">wwwroot</code> folder of the web project.</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/bc0233c8264116276683aa2c0a0b6158/5e845/buildjs.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.48148148148149%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3KAD/8QAFRABAQAAAAAAAAAAAAAAAAAAEEH/2gAIAQEAAQUCh//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABYQAAMAAAAAAAAAAAAAAAAAAAEQkf/aAAgBAQABPyEW/wD/2gAMAwEAAgADAAAAEAAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGBABAAMBAAAAAAAAAAAAAAAAAQARMYH/2gAIAQEAAT8QZRUsbkMnWf/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="NPM build" title="" src="/static/bc0233c8264116276683aa2c0a0b6158/47311/buildjs.jpg" srcset="/static/bc0233c8264116276683aa2c0a0b6158/6f81f/buildjs.jpg 270w, /static/bc0233c8264116276683aa2c0a0b6158/09d21/buildjs.jpg 540w, /static/bc0233c8264116276683aa2c0a0b6158/47311/buildjs.jpg 1080w, /static/bc0233c8264116276683aa2c0a0b6158/0047d/buildjs.jpg 1620w, /static/bc0233c8264116276683aa2c0a0b6158/274e1/buildjs.jpg 2160w, /static/bc0233c8264116276683aa2c0a0b6158/5e845/buildjs.jpg 2535w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>9. Run server side tests</strong></p> <p>Almost there. This is the time to run your server side tests. You can do that by creating a Visual Studio Test task. Default values will suffice unless you might want to customise them.</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/8200743d4967e6e26b4c624ea138d467/e46e4/webtests.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 51.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMBBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe6nQ0H/xAAWEAEBAQAAAAAAAAAAAAAAAAABEDH/2gAIAQEAAQUCMhf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAYEAADAQEAAAAAAAAAAAAAAAAAARAxQf/aAAgBAQABPyHqKNgp/9oADAMBAAIAAwAAABBwD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABsQAQACAwEBAAAAAAAAAAAAAAERMQAQIUFR/9oACAEBAAE/EOggFPMoTem4lj5lNf/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Server Side Tests" title="" src="/static/8200743d4967e6e26b4c624ea138d467/47311/webtests.jpg" srcset="/static/8200743d4967e6e26b4c624ea138d467/6f81f/webtests.jpg 270w, /static/8200743d4967e6e26b4c624ea138d467/09d21/webtests.jpg 540w, /static/8200743d4967e6e26b4c624ea138d467/47311/webtests.jpg 1080w, /static/8200743d4967e6e26b4c624ea138d467/0047d/webtests.jpg 1620w, /static/8200743d4967e6e26b4c624ea138d467/274e1/webtests.jpg 2160w, /static/8200743d4967e6e26b4c624ea138d467/e46e4/webtests.jpg 2538w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>10. Publish the web project</strong></p> <p>Although these steps might seems a lot to do, they are pretty straight forward. Time to pack and create a publish artifact. First you will need to run <code class="language-text">dotnet publish</code> from root of your ASP.Net Core app.</p> <p>To do this you need a command line task. You can pass your build configuration and publish directory to this command as well. I’ve done this as build variables.</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/a60f7857686582761cca2d390a7e3154/9a38d/publish.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 52.96296296296297%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB3SFiIYv/xAAWEAEBAQAAAAAAAAAAAAAAAAAQAUH/2gAIAQEAAQUCwj//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAVEAEBAAAAAAAAAAAAAAAAAAAQAf/aAAgBAQAGPwJj/8QAFRABAQAAAAAAAAAAAAAAAAAAARD/2gAIAQEAAT8hpNf/2gAMAwEAAgADAAAAEG8P/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8QZ//EAB0QAQABAwUAAAAAAAAAAAAAAAEAEBExIUFRgZH/2gAIAQEAAT8QwXDvBOWdscBbia+V/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Publish" title="" src="/static/a60f7857686582761cca2d390a7e3154/47311/publish.jpg" srcset="/static/a60f7857686582761cca2d390a7e3154/6f81f/publish.jpg 270w, /static/a60f7857686582761cca2d390a7e3154/09d21/publish.jpg 540w, /static/a60f7857686582761cca2d390a7e3154/47311/publish.jpg 1080w, /static/a60f7857686582761cca2d390a7e3154/0047d/publish.jpg 1620w, /static/a60f7857686582761cca2d390a7e3154/274e1/publish.jpg 2160w, /static/a60f7857686582761cca2d390a7e3154/9a38d/publish.jpg 2541w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>11. Archive the published output</strong></p> <p>The only remaining steps are archive the files and drop them in a folder so you can use it in release. For archive there is already a predefined task called <code class="language-text">Archive Files</code>.</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/59bb5944b7332470dbd87b7b04e445b0/3c389/archive.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 52.222222222222214%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHuPOyhB//EABcQAQADAAAAAAAAAAAAAAAAABABMUH/2gAIAQEAAQUCwij/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAYEAADAQEAAAAAAAAAAAAAAAAAARAxkf/aAAgBAQABPyFdimIp/9oADAMBAAIAAwAAABDgz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQABBAMAAAAAAAAAAAAAAAEAEBEhMUFRkf/aAAgBAQABPxDEu7N8zTIk9iQRbdR0/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Archive artifact output" title="" src="/static/59bb5944b7332470dbd87b7b04e445b0/47311/archive.jpg" srcset="/static/59bb5944b7332470dbd87b7b04e445b0/6f81f/archive.jpg 270w, /static/59bb5944b7332470dbd87b7b04e445b0/09d21/archive.jpg 540w, /static/59bb5944b7332470dbd87b7b04e445b0/47311/archive.jpg 1080w, /static/59bb5944b7332470dbd87b7b04e445b0/0047d/archive.jpg 1620w, /static/59bb5944b7332470dbd87b7b04e445b0/274e1/archive.jpg 2160w, /static/59bb5944b7332470dbd87b7b04e445b0/3c389/archive.jpg 2540w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p><strong>12. Publish the archived file</strong></p> <p>And at last you need to publish this artifact. Create a task called <code class="language-text">Publish Artifact</code> and add drop to its name (for clarity). Then type your archive directory and name into correspondent boxes.</p> <p>You will need to set the artifact type to <code class="language-text">Server</code> which means it copies the file to the same build server.</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/8794e08d253629504f6146c4955129fc/67a70/drop.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 52.222222222222214%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHuTTQA/8QAFhABAQEAAAAAAAAAAAAAAAAAARAx/9oACAEBAAEFAjIX/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAIP/aAAgBAQAGPwJf/8QAFxAAAwEAAAAAAAAAAAAAAAAAAAEQwf/aAAgBAQABPyEVNX//2gAMAwEAAgADAAAAEOAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHRAAAgIBBQAAAAAAAAAAAAAAAREAIRAxQXGRof/aAAgBAQABPxBFILK1cZWPYue4RoMrZn//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Drop" title="" src="/static/8794e08d253629504f6146c4955129fc/47311/drop.jpg" srcset="/static/8794e08d253629504f6146c4955129fc/6f81f/drop.jpg 270w, /static/8794e08d253629504f6146c4955129fc/09d21/drop.jpg 540w, /static/8794e08d253629504f6146c4955129fc/47311/drop.jpg 1080w, /static/8794e08d253629504f6146c4955129fc/0047d/drop.jpg 1620w, /static/8794e08d253629504f6146c4955129fc/274e1/drop.jpg 2160w, /static/8794e08d253629504f6146c4955129fc/67a70/drop.jpg 2565w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>Done. Now you can proceed with creating the release. I will explain that in my next post so keep an eye out.</p> <p>Also any comment or improvements are very appreciated.</p><![CDATA[Are you facing docker version error?]]>https://yashints.dev/blog/2017/02/15/are-you-facing-docker-version-errorhttps://yashints.dev/blog/2017/02/15/are-you-facing-docker-version-errorWed, 15 Feb 2017 18:16:00 GMT<p>I was working with my docker image for my pet project and suddenly got an error message:</p> <!--more--> <div class="custom-block danger"><div class="custom-block-body"> client version 1.22 is too old. Minimum supported API version is 1.24, please upgrade your client to a newer version.</div></div> <p>I just opened a command line and typed:</p> <div class="gatsby-code-button-container" data-toaster-id="34852434174062207000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\$ docker version`, `34852434174062207000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre style="counter-reset: linenumber NaN" class="language-powershell line-numbers"><code class="language-powershell">$ docker version</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And guess what? this is the output:</p> <div class="gatsby-highlight" data-language="text"><pre style="counter-reset: linenumber NaN" class="language-text line-numbers"><code class="language-text">Client: Version: 1.13.0-rc7 API version: 1.25 Go version: go1.7.3 Git commit: 48a9e53 Built: Tue Feb 14 17:56:00 UTC 2017 OS/Arch: linux/amd64 Server: Version: 1.13.0-rc7 API version: 1.25 (minimum version 1.24) Go version: go1.7.3 Git commit: 48a9e53 Built: Tue Feb 14 17:56:00 UTC 2017 OS/Arch: linux/amd64&lt;/pre></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Turns out my current version is higher than the error version, so what is going on here.</p> <p>The catch is the <code class="language-text">docker-compose</code> file format has been versioned and therefore we should increment the version requested in the <code class="language-text">docker.yml</code> file.</p> <p>In any docker-compose file that is used with 1.24 or later version of the docker client, we should request version <code class="language-text">2.1</code>.</p> <p>So change your file to look like this and you should be good to go:</p> <div class="gatsby-highlight" data-language="text"><pre style="counter-reset: linenumber NaN" class="language-text line-numbers"><code class="language-text">version: '2.1' services: webapplication102: image: user/myapplication build: context: .</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Here is the <a href="https://github.com/docker/compose/issues/4106" target="_blank" rel="nofollow noopener noreferrer">issue page</a> on <code class="language-text">github</code> if you need more info.</p> <p><strong>Update:</strong></p> <p>Version 3 is released, which means you should be able to put 3 instead of 2.1 in your <code class="language-text">docker-compose.yml</code> file.</p><![CDATA[Troubleshooting Xamarin project issues with visual studio]]>https://yashints.dev/blog/2017/01/09/troubleshooting-xamarin-project-issues-with-visual-studiohttps://yashints.dev/blog/2017/01/09/troubleshooting-xamarin-project-issues-with-visual-studioMon, 09 Jan 2017 00:00:00 GMT<p>Today I started to install Xamarin and create a pet project for myself. While doing so I faced a couple of issues and solved them using a couple of hints from SO which are worth sharing so other new starters like me can fix them quicker than me.</p> <!--more--> <h2 id="android-emulator-opens-but-project-does-not-deploy-and-start" style="position:relative;"><a href="#android-emulator-opens-but-project-does-not-deploy-and-start" aria-label="android emulator opens but project does not deploy and 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>Android emulator opens, but project does not deploy and start</h2> <p>This happens specially using VS <code class="language-text">new > project > run</code> combination. You will see that it builds and everything is fine, however, the emulator starts and your application will appear/not appear at all and drop quickly afterwards. You will most likely get a message like:</p> <div class="custom-block danger"><div class="custom-block-body">Android application is debugging. Could not connect to the debugger.</div></div> <p>And also you might face this message in console:</p> <div class="custom-block danger"><div class="custom-block-body">AOT module ‘mscorlib.dll.so’ not found: dlopen failed: library “/data/app/<your app name>.Droid-1/lib/x86/libaot-mscorlib.dll.so” not found.</div></div> <p>The latter is easy to fix, you just need to open the emulator settings dialog and clear the <code class="language-text">Use Fast Deployment</code> checkbox.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 667px; " > <a class="gatsby-resp-image-link" href="/static/be13cb99893ce0e06d903ad0f266ef22/295bd/image.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 46.666666666666664%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABpUlEQVR42l1Sy27bMBDUl/fWQ3+iPxEURRqgh7QHH9smtl7Uw9aLlCiRoqSgDVpMdwnHSHwYcJdczc7OKphUjToLMckKf7cJmzM4Hk8o8wJN0yAMQxwOB9RV7XMpJY7lERXlURT5tzRN0bYtuq5D8HHn8P7W4MMXjXe3G76JFfOoIFVPBdKTlGXpi4dhgNYa4zj6Uyl1Ab8xgq+PPT790Pie/8bncEPaOlRlTp1DxGGEOIpRnSoMRDDPM4wxsNZiZlD+Ar5jBCONWmfReWSDp39/0FCnh18/sd8f8PiwR98P2LYNzp0J6MNeT9Cj8bF9hUDKHidSUNUNtJmx3tzA3t2hpBEz8kYkBCEgUoE8y1FTnSPSRo1Qw0QNrgi5o1tXLDTSstthvb/HGMcQReHJkjjxZBznWeGXYq1BNxhSabzqN4TsieFknGAn6vj8jIlyVpORsjzP/RY5FiJDkiS0pAKtHNAPGvbs6YXwkrCxZ394g01do2s7/zsoUiU7Bm2a/GzYHqp5Il/ttYfXFwxWzb8L+9XS6ZzDsiweHK9sEcWvt/tC+B/B1pqalwM2gAAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Use Fast Deployment" title="" src="/static/be13cb99893ce0e06d903ad0f266ef22/295bd/image.png" srcset="/static/be13cb99893ce0e06d903ad0f266ef22/01bf6/image.png 270w, /static/be13cb99893ce0e06d903ad0f266ef22/07484/image.png 540w, /static/be13cb99893ce0e06d903ad0f266ef22/295bd/image.png 667w" sizes="(max-width: 667px) 100vw, 667px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <p>The former is happening because of a very stupid option inside hyper-v and you can fix it by opening the hyper-v and from device selection choose your emulator. After that click on settings and navigate to <code class="language-text">processor > Compatibility</code>, then tick the <strong>Migrate to a physical computer with a different processor version</strong> and you should be good to give it a go.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 806px; " > <a class="gatsby-resp-image-link" href="/static/49bc1dff4c7a405d0f4bc81eb684ef35/764be/image9.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 95.18518518518519%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAABnWAAAZ1gEY0crtAAACs0lEQVR42qWU224TMRCG84SACmqF+gA8EKJCHCohcQkXSL3kphJcAE2g2UO2ye4me/Sevd6kDd00+Rk7pbRAuQiWfo3lXX+e8cy48+jVMbb3etja+4r7T3q497iLLbI7z/rY3Tex80JTdnd/gIcvTaXt5wbu7OlKdy8l5w+eHqMzsl186WkwB0OY5gCapsPQTThjGxPfge0PEbEIScyQJAxpmpISZGSVsrUKUsgSdOK0xLdhADvIMDub42IFLJYrxHFMYA2WMYBpGLAsC4zW8kvAFZDgjK3X4zRDp6g4xpMJijxHu1hAjuVqhSiK4QcB+n0NR0ddaGR13YBhmEqmFEU0Ho/heT4BM7CsRCfLGCLfRpUnhJLAlYJGUYRwPIE7GmHieXAcR0kCbHs9d12HYB4qztGImjws0Dk8EXh96OJdN8PBoMUbfYm3BtC1GereMXgQoaxrVGWJqqr+Ks5rAgrykIAnUYODDxrefz5BP5jB4cCwWOHEi1FSogRdiWgaCNpwm24ACzq5Jg/SOEBTcxUu6A5DmQBrBFFWqOln+c9tugFM84rKIqO7ocTQ5p8jCEPKZqY8+BfsD2ChQpoipqxKJUmKZjpFuCkwK0okWa6y5XkBJlRCsngDKpmNgJwL5VVFni6oDufzubIbe8hrAjJGi7/uT46NgWlewqUS8VmO7+ft/wNZXsMKKthMYNYucTpvMT07h+cHqp02CplT64S+T1mO1Me2bVEUBXLq79+B/JpuSQq1Tx6pDM9mp7hYLlXIQjQUck4b1p0gJTfLnhXiEnbtsOm0WT8Osk99Sor0UIZYUucsFi0EdY08rGnElSrZUdQIWcFVVGVZgFMvS1uVOeKEnq8opQmJ0UsR0YKUdP26YlKaFxjSm/lRH+PTIIDlhtBNCyPXgzVyoNG7aQxd/ADpJXwPw/v+PwAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Migrate to a physical computer with a different processor version" title="" src="/static/49bc1dff4c7a405d0f4bc81eb684ef35/764be/image9.png" srcset="/static/49bc1dff4c7a405d0f4bc81eb684ef35/01bf6/image9.png 270w, /static/49bc1dff4c7a405d0f4bc81eb684ef35/07484/image9.png 540w, /static/49bc1dff4c7a405d0f4bc81eb684ef35/764be/image9.png 806w" sizes="(max-width: 806px) 100vw, 806px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p> <h2 id="missing-files-inside-appdatalocalxamarin-folders" style="position:relative;"><a href="#missing-files-inside-appdatalocalxamarin-folders" aria-label="missing files inside appdatalocalxamarin folders permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Missing Files inside AppData\Local\Xamarin Folders</h2> <p>This one happened to me after running the universal Xamarin installer and finishing the steps in visual studio to create a new Xamarin forms project and click build.</p> <p>By this time I was getting different error messages like:</p> <div class="custom-block danger"><div class="custom-block-body">Could not find mudule xxx in ‘Xamarin.Android.Support.Design’</div></div> <p>or</p> <div class="custom-block danger"><div class="custom-block-body">Could not find mudule xxx in ‘Xamarin.Android.Support.v4’</div></div> <p>or any of the following folders:</p> <div class="custom-block danger"><div class="custom-block-body"> Xamarin.Android.Support.Design <br/> | Xamarin.Android.Support.v4 <br/> | Xamarin.Android.Support.v7.AppCompat <br/> | Xamarin.Android.Support.v7.CardView <br/> | Xamarin.Android.Support.v7.MediaRouter <br/> | Xamarin.Android.Support.v7.RecyclerView <br/></div></div> <p>The reason (most probable) is failing in download a file called <code class="language-text">android_m2repository_r10.zip</code> from the google repository. However that is not always the case. For any reason the fix is completely the same.</p> <h3 id="automatic-fix" style="position:relative;"><a href="#automatic-fix" aria-label="automatic fix permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Automatic Fix</h3> <p>Delete the versioned library folder that is giving you errors:</p> <p><strong>Mac Directory:</strong> <code class="language-text">/Users/[Username]/.local/share/Xamarin/{SUPPORT LIBRARY NAME}/{VERSION NUMBER}</code></p> <p><strong>Windows Directory:</strong> <code class="language-text">C:\Users\[Username]\AppData\Local\Xamarin\{SUPPORT LIBRARY NAME}\{VERSION NUMBER}</code></p> <p>Rebuild your project (Which will kickoff a Build Task to re-download the library).</p> <h3 id="manual-fix" style="position:relative;"><a href="#manual-fix" aria-label="manual fix permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Manual Fix</h3> <p>There are two steps to manually fixing this error.</p> <ol> <li>Adding the <code class="language-text">m2repository</code> folder to the <code class="language-text">/content</code> folder.</li> <li>Adding the respective Android Support Library / Google Play Services <code class="language-text">.aar</code> contents to the <code class="language-text">/embedded</code> folder.</li> </ol> <p>You can follow the instruction mentioned on Xamarin troubleshooting guide <a href="https://developer.xamarin.com/guides/android/troubleshooting/resolving-library-installation-errors/" target="_blank" rel="nofollow noopener noreferrer">here</a> to fully resolve the issue.</p> <p>However the short version is:</p> <ul> <li>Get the <code class="language-text">URL</code> of the missing m2repository download</li> <li>Use a <code class="language-text">MD5</code> hash on the download URL from the given table</li> <li>Rename the file to <code class="language-text">{MD5HASH}.zip</code> (Where MD5HASH is the hashed download URL)</li> <li>Place the new hashed .zip file in your <code class="language-text">Xamarin\zips</code> directory</li> </ul> <p>Hope this helps you save some time.</p><![CDATA[How to keep yourself updated (pet projects)]]>https://yashints.dev/blog/2016/11/11/how-to-keep-yourself-updated-pet-projectshttps://yashints.dev/blog/2016/11/11/how-to-keep-yourself-updated-pet-projectsFri, 11 Nov 2016 00:00:00 GMT<p>For us (developers) the most irritating and cumbersome process is to keep ourselves up to date, since every 2 second a new language/tool/technology is born out of nowhere. We know that we have to keep up with them if we want to stay in loop and don’t get left behind.</p> <!--more--> <p>This is awfully worst for consultants since they will spend some time on different engagements and they have to know a bit of everything they will face and also more if they want to lead the client in that area.</p> <p>We all have family/personal stuff to do and usually don’t have enough time to read about everything we face everyday, and we shouldn’t since it is proven to <a href="http://www.cnbc.com/2015/01/26/working-more-than-50-hours-makes-you-less-productive.html" target="_blank" rel="nofollow noopener noreferrer">reduce</a> productivity in the long run. So the question is what are we supposed to do to achieve this?</p> <p>The answer to this is to make a habit for ourselves to spend some <strong>short</strong> but <strong>fixed</strong> time everyday on a side project (usually known as pet project) and keep our hands dirty.</p> <p>Side projects are a great way to grow as a developer, both personally and professionally. They let get out of your comfort zone, learn new skills, and exercise your creative muscles. But it can be hard to get anything done while juggling a day job, kids, friends, family, and countless other commitments.</p> <p>In the past, I’ve tried to cram side project work into the cracks between other items in my calendar. It was frustrating at best; completely ineffective at worst. I constantly felt like I was shortchanging the projects I was <strong><em>most</em></strong> passionate about. So what next?</p> <h1 id="start-with-somethingsmall-but-keep-doing-it" style="position:relative;"><a href="#start-with-somethingsmall-but-keep-doing-it" aria-label="start with somethingsmall but keep doing 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>Start with something small but keep doing it</h1> <p>It is definitely hard to start a project, harder to get back to it after some time and re-start it when you’ve been working on something completely different.</p> <p>So working on it a bit everyday keeps you on track while not bored or tired. If you keep doing it everyday it will be very easy to pick it where you left off since it is still in your mind.</p> <h1 id="no-deadlines-or-pressure" style="position:relative;"><a href="#no-deadlines-or-pressure" aria-label="no deadlines or pressure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>No deadlines or pressure</h1> <p>Don’t put deadlines or pressure on yourself for a side project. It is not a client engagement and you don’t want to loose your excitement about it really soon. Keep focusing on one or two task a week and finish it in a relaxed atmosphere.</p> <p>Take your time, have a juice (not coffee) or fresh fruit handy and let the feeling of small holiday overcome the daily agile mindset. Close the <a href="https://www.facebook.com/" target="_blank" rel="nofollow noopener noreferrer">Facebook</a>, stop scrolling your <a href="https://twitter.com" target="_blank" rel="nofollow noopener noreferrer">Twitter </a>feed and focus on what you promised yourself doing everyday.</p> <p>Once the habit is formed, the pressure is off and you start feeling joy about doing something you feel passionate about. If you feel week about forming a habit read something like <a href="http://99u.com/articles/17123/5-scientific-ways-to-build-habits-that-stick" target="_blank" rel="nofollow noopener noreferrer">this</a>. These point are not from me, but from proven scientific articles and resources I’ve red in the past.</p> <h1 id="track-your-progress-and-praise-yourself" style="position:relative;"><a href="#track-your-progress-and-praise-yourself" aria-label="track your progress and praise 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>Track your progress and praise yourself</h1> <p>Keep track of what is achieved and what is to be done. This way you will have a sense of how you’re doing in terms of your milestones.</p> <p>Don’t put extra effort if you feel you’re behind, but focus on maintaining your daily habit. This will automatically fix the issue by keeping your energy focused on the project and creating that great feeling of the fact that you’re spending sometime for yourself doing what you love.</p> <p>I myself had the issue of working on a client for a long time and not learning any new stuff, but after I got the habit, I felt great learning new stuff and having that man cave feeling. Furthermore, I started to eat fruits instead of dinner and that helped me a lot by fixing my insomnia issue.</p> <p>I got used to go to bunnings and buy something for my other pet project (I love making some wooden crafts).</p> <h1 id="shift-the-project-time-to-time" style="position:relative;"><a href="#shift-the-project-time-to-time" aria-label="shift the project time to time permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Shift the project time to time</h1> <p>Don’t work on something for too long. as we see new languages and technologies introduced everyday, we should shift our pet project to use different languages/technologies accordingly.</p> <p>I love front end specifically, however try to keep track of security stuff, azure, IoT, Hololens, and etc. to keep my excite level up.</p> <p>My approach to this is to complete a project I start working on and then create a new one using the new tech I want to get familiar with.</p> <p>If  I want to learn a new language in the save space, I will rewrite my last one with the language, which helps me face different challenges to implement something in different languages.</p> <h1 id="talk-about-your-pet-project-somewhere" style="position:relative;"><a href="#talk-about-your-pet-project-somewhere" aria-label="talk about your pet project somewhere permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Talk about your pet project somewhere</h1> <p>This one doesn’t have to do anything with your pet project, but helps you find the weakness points and new challenges since it is exposed to people who love asking questions and learn new things.</p> <p>Even if it is an internal brown bag session, or presentation, or you are talking on an external event like meetups or conferences that project helps you gather the contents easily and demo something which even demo gods cannot prevent it (since you’ve played with it enough previously).</p> <p>Hope this helps you keep up to date and if you find something that can be added to this please leave comments here.</p><![CDATA[How to show your leadership skills even if you're not a leader]]>https://yashints.dev/blog/2016/10/26/how-to-show-your-leadership-skills-even-if-youre-not-a-leaderhttps://yashints.dev/blog/2016/10/26/how-to-show-your-leadership-skills-even-if-youre-not-a-leaderWed, 26 Oct 2016 00:00:00 GMT<p>I am currently working towards a promotion to Senior Consultant and as part of the process I have needed to demonstrate my leadership skills and abilities.  Working solo on an engagement with a client who won’t let me go, I have not been in an actual team lead role, and this has made it challenging to demonstrate team leadership skills.  I figure that others might be in a similar position, so thought it worth sharing some of my lessons.</p> <!--more--> <p>When your manager hands over the reins of a project to you, it’s a sure sign you are a safe and trusted pair of hands.   Here’s your opportunity to highlight your leadership skills and abilities. But what if you’re put in charge of leadership responsibilities without a formal title, or worst you’re not in charge at all but have to prove your abilities in this area?</p> <p>I did some research on how you can demonstrate your leadership skills and abilities without a being officially in the role, and found some interesting articles around this topic.</p> <p>Let’s discuss some critical areas that we should all consider when in a position of influence and leadership to other team members in a way that enables  them to trust and follow you throughout the journey.</p> <h2 id="lead-by-doing-something-practical-as-an-example" style="position:relative;"><a href="#lead-by-doing-something-practical-as-an-example" aria-label="lead by doing something practical as an example permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Lead by doing something practical as an example</h2> <p>Irrespective of role, everyone has the ability to demonstrate leadership skills and abilities by doing something practical.  Demonstrating leadership may involve taking on something complex to support other team members, defusing a conflict, making difficult decisions, having tough conversations etc.</p> <p>But remember, it’s not just about ‘what you do’, but also ‘how you do it’ and the ‘outcome of the activity’.  Some examples will be  measurable by your manager/team lead, and others may be more subjective.</p> <p>On one of my engagements, some practical examples I have undertaken have included picking complex PBI’s, helping the team lead with complex decisions, doing this in a way that he didn’t feel I was interfering (using subtle influence techniques to get him on-board), but at the same time he could see I was the one who helped him get there (reinforcing my value to the client).</p> <p>Consequently he started to trust me little by little and our relationship became stronger day by day. These days he is confident in letting me drive the direction of the project based on my knowledge of the client, project and its requirements.  Later on, he specifically called me out when feedback about the success of the team. The flow on effect of this is that other team members became aware of my success, strong relationships and increased influence, and this resulted in a noticeable shift to the level of respect team members showed towards me and my decisions.</p> <p>The team also started coming to me to ask my opinion on how to do ‘stuff’.  Aside from being able to demonstrate my leadership skills and abilities, the feeling was so amazing and unbelievable that I started to realise what a great achievement was this.</p> <h2 id="listen-first-talk-last" style="position:relative;"><a href="#listen-first-talk-last" aria-label="listen first talk last permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Listen first, talk last</h2> <p>This is very critical in a sense that sometimes we think we should take control of the meeting and talk and talk for hours so others will know how awesome we are and how much we know, or because we think they need to hear what we have to say.</p> <p>However, throughout my experience and with help of some internal training on soft skills, I realised that one of the most required leadership skills is to encourage dialog.</p> <p>By doing this you show you respect everyone equally, you get a diverse set of ideas and opinions, you will learn something about the people, their business, and/or the project, it will help you avoid assumptions, and you will have time to think about everything being said.</p> <p>As they say, if you’re busy talking, you’re not listening. You can guess that by respecting others this will help you gain their respect.</p> <h2 id="dont-take-sides" style="position:relative;"><a href="#dont-take-sides" aria-label="dont take sides permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Don’t take sides</h2> <p>If you’re in a role which requires you to assign tasks to others, it’s important that you don’t deliberately or accidentally assign the favourable tasks to your close friends or the people you get along with the most, whilst assigning less favourable ones to others.</p> <p>It’s important to ensure that all team members have a good mix of tasks where practicable and tasks are assigned in a way that everyone feels happy or at least that it has been a fair process, and is motivated to do a great job to deliver the desired outcome.</p> <p>By doing this you show that you are fair and trustworthy,  and this helps to keep the environment as harmonious as possible. Let me give you an example to elaborate more on this:</p> <p>I was working with other local developers on a project. I had already built the trust so that was my chance to assign tasks between ourselves in a way that everyone feels good about it.</p> <p>Since one of them was a back end guru, but, didn’t have any experience at front end development, I suggested to assign the UI task to him and the rest to others as we were already engaged in previous similar tasks.</p> <p>He was a bit hesitant at first but by explaining my goal on how much fun he would have working on the UI side and also how he would able to build his experience in this area, he accepted the decision happily.</p> <p>I was constantly supporting him by giving guidance and support as required, and he was enjoying the sprint. To be honest I had never seen him as happy as he was after he had successfully completed the work.</p> <p>On the other hand, others were happy as well since they had a chance to work in the different areas and explore the patterns we were using. A total win win situation you might say.</p> <h2 id="pull-your-weight-and-even-more" style="position:relative;"><a href="#pull-your-weight-and-even-more" aria-label="pull your weight and even more permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Pull your weight and even more</h2> <p>We discussed how you should assign the tasks in a way that keeps everyone happy or at least feels fair; however, you should always demonstrate that you are ready to get your hands dirty (do the hard and less favourable stuff), and help others along the way if they need it.</p> <p>I’ve been always ready to pick the toughest PBI’s and the ones that nobody was willing to do.</p> <p>For example, converting a legacy app or fixing a bug that was there for a long time and nobody knew why it was happening.</p> <p>Whilst others see the negative, I identify the silver linings. This has helped me showcase my strengths and that I care about the team and its success. You’ll exert the most influence when others see you leading by example and working as hard – if not harder – than they are.</p> <h2 id="take-responsibility" style="position:relative;"><a href="#take-responsibility" aria-label="take responsibility permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Take responsibility</h2> <p>This point is as important as any of the above points. After completing a project or any milestone there would be always moments where the team can receive both positive recognition and constructive feedback to help them grow.</p> <p>The most important part is that no matter what, how, and when something went wrong a true leader will take responsibility and support his/her team rather than apportion blame.</p> <p>A leader should show everybody that he or she can be depended upon, that is a reliable person. Avoid pointing fingers and  call out a blaming culture if you see one. The same thing is true about when everything goes well and there is praise.</p> <p>You should remember how you got there and always acknowledge the contribution of others.  In the case that a specific person has done a great job, ensure they  receive the right level of recognition for their contribution.</p> <p>I have had the chance to express someone’s good efforts as well as other times when I had to admit that my decision was not the best one and take responsibility of my choices.</p> <p>Admitting that you were wrong and could have done better is a great sign of strength, maturity and leadership.</p> <h2 id="keep-developing-your-leadership-skills" style="position:relative;"><a href="#keep-developing-your-leadership-skills" aria-label="keep developing your leadership skills permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Keep developing your leadership skills</h2> <p>Some people are born leaders, but most of us have to learn it the hard way.</p> <p>The best way to boost your leadership skills is via on-the-job training, with regular feedback and coaching to help you to continually hone your skills.</p> <p>In my case I didn’t have a chance to be a lead; however, I have proactively arranged shadowing opportunities, requested peer and client feedback, and arranged coaching.</p> <p>This has not only helped me improve my skills, but also demonstrate my skills and abilities, the progress I have made, gain trust amongst my peers, leaders and clients, and build a reputation which enabled me to be the lead behind the scenes.</p> <p>There are other ways like researching, reading books and articles on the subject, classroom or online learning, and also learn from those around you how to be able to be a good lead.</p> <p>Being entrusted with a team project is an exciting opportunity to demonstrate your leadership skills. Even though your official title hasn’t changed, there are many ways you can show your client and colleagues that you’ve got what it takes to be a leader and earn their respect.</p><![CDATA[Getting to know webpack]]>https://yashints.dev/blog/2016/09/11/getting-to-know-webpackhttps://yashints.dev/blog/2016/09/11/getting-to-know-webpackSun, 11 Sep 2016 00:00:00 GMT<p>At its core, <a href="https://webpack.js.org/" target="_blank" rel="nofollow noopener noreferrer">webpack</a> is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles.</p> <!--more--> <p>I am trying to provide a kinda step-by-step guide on how to simply setup webpack and get familiar with it. So, let’s get started:</p> <h2 id="step-1-initial-setup" style="position:relative;"><a href="#step-1-initial-setup" aria-label="step 1 initial 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>Step 1: initial setup</h2> <p>I am using VS code but you can use any other editor. Open up your empty folder with VS code and then open a terminal. Remember you’ve got to have installed node globally.</p> <p>Now run <code class="language-text">npm init</code>, you’ll be asked a couple of questions which you can easily bypass by pressing <code class="language-text">enter</code>.</p> <h2 id="step-2-install-the-necessary-packages" style="position:relative;"><a href="#step-2-install-the-necessary-packages" aria-label="step 2 install the necessary packages permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Step 2: install the necessary packages</h2> <p>All of webpack modules and loaders would be installed as dev dependency as they are not required for deployment.</p> <p>1- <a href="http://webpack.github.io/" target="_blank" rel="nofollow noopener noreferrer">webpack</a>, you may install the webpack globally but for the time being I am going to set it up as dev dependency.</p> <div class="gatsby-code-button-container" data-toaster-id="56284567932854010000" data-toaster-class="gatsby-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 i -D webpack webpack-dev-server`, `56284567932854010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i <span class="token parameter variable">-D</span> webpack webpack-dev-server</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p> </p> <h3 id="loaders" style="position:relative;"><a href="#loaders" aria-label="loaders permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a href="https://webpack.github.io/docs/loaders.html" target="_blank" rel="nofollow noopener noreferrer">loaders</a></h3> <p>We will need the bellow loaders for the purpose of this guideline. You might be wondering what is a loader. Well to put it simply (from webpack), loaders allow you to pre-process files as you <code class="language-text">require()</code> or “load” them.</p> <p>Loaders are kind of like tasks in other build tools, and provide a powerful way to handle frontend build steps. Loaders can transform files from a different language like, CoffeeScript to JavaScript, or inline images as data URLs. Loaders even allow you to do things like <code class="language-text">require()</code> css files right in your JavaScript!</p> <p>now run this commands:</p> <div class="gatsby-code-button-container" data-toaster-id="11639024417882538000" data-toaster-class="gatsby-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 i -D style-loader css-loader sass-loader node-sass file-loader url-loader postcss-loader babel-loader babel-core babel-preset-es2015 eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import extract-text-webpack-plugin npm i bootstrap --save`, `11639024417882538000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> i <span class="token parameter variable">-D</span> style-loader css-loader sass-loader node-sass file-loader url-loader postcss-loader babel-loader babel-core babel-preset-es2015 eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import extract-text-webpack-plugin <span class="token function">npm</span> i bootstrap <span class="token parameter variable">--save</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Don’t worry, I will go through these one by one:</p> <h3 id="babel-loader" style="position:relative;"><a href="#babel-loader" aria-label="babel loader permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><a href="https://www.npmjs.com/package/babel-loader" target="_blank" rel="nofollow noopener noreferrer">babel-loader</a></h3> <p>This package allows transpiling JavaScript files using Babel and webpack.</p> <p>Here I am assuming, you will be using ES6 and have some idea on <a href="https://babeljs.io/" target="_blank" rel="nofollow noopener noreferrer">babel</a> which is a compiler for writing next generation JavaScript. We will be doing our setup using babel6, which is its latest version and differs a lot from its older versions.</p> <p>Since babel-loader depends number of modules from babel, we will be installing all of them together. Make sure to read about them.</p> <ul> <li><em><a href="https://www.npmjs.com/package/babel-core" target="_blank" rel="nofollow noopener noreferrer">babel-core</a>.</em></li> <li><em><a href="https://www.npmjs.com/package/babel-preset-es2015" target="_blank" rel="nofollow noopener noreferrer">babel-preset-es2015</a></em> - Babel preset for all es2015 plugins.</li> </ul> <p>Following loaders are all used to deal with static resources like css, fonts, images, etc.</p> <ul> <li><em><a href="https://www.npmjs.com/package/small-style-loader" target="_blank" rel="nofollow noopener noreferrer">style-loader</a></em> Adds CSS to the DOM by injecting a <code class="language-text">&lt;style></code> tag.</li> <li><em><a href="https://www.npmjs.com/package/css-loader" target="_blank" rel="nofollow noopener noreferrer">css-loader</a></em> this modules helps loading css files and preparing them for being used by other loaders such as style-loader.</li> <li><em><a href="https://www.npmjs.com/package/file-loader" target="_blank" rel="nofollow noopener noreferrer">file-loader</a></em> By default file-loader returns the MD5 hash of the file’s contents with the original extension.</li> <li><em><a href="https://www.npmjs.com/package/url-loader" target="_blank" rel="nofollow noopener noreferrer">url-loader</a></em> url-loader is a good starting point and it’s the perfect option for development purposes as you don’t have to care about the size of the resulting bundle. It comes with a limit option that can be used defer image generation to file-loader after certain limit is reached. This way you can inline small files to your JavaScript bundles while generating separate files for the bigger ones.</li> <li><em><a href="https://www.npmjs.com/package/sass-loader" target="_blank" rel="nofollow noopener noreferrer">sass-loader</a></em> Adds support for compiling sass files and preparing them for css-loader.</li> <li><em><a href="https://www.npmjs.com/package/postcss-loader" target="_blank" rel="nofollow noopener noreferrer">postcss-loader</a></em> postcss loader for webpack to post-processes your CSS with postcss plugins.</li> </ul> <p>I think you can easily find the use of other loaders on the <a href="https://webpack.github.io/docs/" target="_blank" rel="nofollow noopener noreferrer">webpack</a> documentation repository.</p> <h3 id="add-script-to-code-classlanguage-textpackagejsoncode-to-run-code-classlanguage-textwebpack-dev-servercode-with-node" style="position:relative;"><a href="#add-script-to-code-classlanguage-textpackagejsoncode-to-run-code-classlanguage-textwebpack-dev-servercode-with-node" aria-label="add script to code classlanguage textpackagejsoncode to run code classlanguage textwebpack dev servercode with node permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Add script to <code class="language-text">package.json</code> to run <code class="language-text">webpack-dev-server</code> with node</h3> <p>Add this to scripts section of your <code class="language-text">package.json</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="56423450898100990000" data-toaster-class="gatsby-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;start&quot;: &quot;webpack-dev-server --hot --inline&quot;`, `56423450898100990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-json line-numbers"><code class="language-json"><span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"webpack-dev-server --hot --inline"</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>I am using <code class="language-text">--inline</code> and <code class="language-text">--hot</code> flags to tell <code class="language-text">webpack-dev-server</code> to use hot-reloading for development purposes.</p> <h2 id="step-3-create-the-project-files" style="position:relative;"><a href="#step-3-create-the-project-files" aria-label="step 3 create the project files permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Step 3: create the project files</h2> <p>Cool, I think we are now ready to jump to creating necessary files for our project.</p> <p>We will start by creating a couple of empty folders as the structure of the project.</p> <ul> <li><code class="language-text">public</code>: is used to serve all the files that are accessible to outside world.</li> <li><code class="language-text">src</code>: contains our js files.</li> <li><code class="language-text">css</code>: contains our sass files.</li> </ul> <p>For start create a file named <code class="language-text">app.js</code> in the <code class="language-text">src directory</code> with the bellow code:</p> <div class="gatsby-code-button-container" data-toaster-id="86394242223740130000" data-toaster-class="gatsby-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 'bootstrap/dist/css/bootstrap.css' import '../css/app.scss' import MyClass from './dependency' document.write('&lt;h2&gt; This is a demo..! &lt;/h2&gt;') document.write(MyClass.getTemplate()) console.log('app loaded')`, `86394242223740130000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token string">'bootstrap/dist/css/bootstrap.css'</span> <span class="token keyword">import</span> <span class="token string">'../css/app.scss'</span> <span class="token keyword">import</span> MyClass <span class="token keyword">from</span> <span class="token string">'./dependency'</span> document<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token string">'&amp;lt;h2&amp;gt; This is a demo..! &amp;lt;/h2&amp;gt;'</span><span class="token punctuation">)</span> document<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>MyClass<span class="token punctuation">.</span><span class="token function">getTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'app loaded'</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Next thing would be to create the <code class="language-text">MyClass</code> inside the <code class="language-text">dependency.js</code>, I called it dependency to show you it is just a file that is being imported into another and webpack deals with those beautifully.</p> <div class="gatsby-code-button-container" data-toaster-id="56618927310610240000" data-toaster-class="gatsby-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 MyClass = class Me { static getClassName() { return Me.name } static getTemplate() { return \` <div class=&quot;row&quot;> <div class=&quot;col-xs-6&quot;> <label>Name:</label> <input class=&quot;form-control&quot; type=&quot;text&quot; /> </div> <div class=&quot;col-xs-12 link&quot;> <a href=&quot;#&quot;><h2>Me</h2></a> <div> </div>\` } } export default MyClass console.log('dependency loaded')`, `56618927310610240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">const</span> MyClass <span class="token operator">=</span> <span class="token keyword">class</span> <span class="token class-name">Me</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token function">getClassName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Me<span class="token punctuation">.</span>name <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token function">getTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> &lt;div class="row"> &lt;div class="col-xs-6"> &lt;label>Name:&lt;/label> &lt;input class="form-control" type="text" /> &lt;/div> &lt;div class="col-xs-12 link"> &lt;a href="#">&lt;h2>Me&lt;/h2>&lt;/a> &lt;div> &lt;/div></span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> MyClass console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'dependency loaded'</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Then we add the <code class="language-text">scss</code> file inside <code class="language-text">css</code> folder:</p> <div class="gatsby-code-button-container" data-toaster-id="45203199907504410000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\$body-bg: steelblue; body { background-color: \$body-bg; h2 { font-size: 2em; color: white; } label { color: white; } a { display: flex; } }`, `45203199907504410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="scss"><pre style="counter-reset: linenumber NaN" class="language-scss line-numbers"><code class="language-scss"><span class="token property"><span class="token variable">$body-bg</span></span><span class="token punctuation">:</span> steelblue<span class="token punctuation">;</span> <span class="token selector">body </span><span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token variable">$body-bg</span><span class="token punctuation">;</span> <span class="token selector">h2 </span><span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">label </span><span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">a </span><span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now is time to create the main entry point of the app so called <code class="language-text">index.html</code> inside <code class="language-text">public</code> folder:</p> <div class="gatsby-code-button-container" data-toaster-id="75035180308423020000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!DOCTYPE html> <html> <head> <title>Webpack demo</title> <link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; src=&quot;./public/assets/style.css&quot; /> </head> <body class=&quot;container&quot;> <script type=&quot;text/javascript&quot; src=&quot;./public/assets/bundle.js&quot;></script> </body> </html>`, `75035180308423020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Webpack demo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></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>text/css<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>./public/assets/style.css<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>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</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>container<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>script</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>text/javascript<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>./public/assets/bundle.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>We are pretty much done with the files, so lets create the configuration required by webpack.</p> <p>Create a file called <code class="language-text">webpack.config.js</code> in the root:</p> <div class="gatsby-code-button-container" data-toaster-id="80247992219002470000" data-toaster-class="gatsby-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 path = require('path') var ExtractTextPlugin = require('extract-text-webpack-plugin') var autoprefixer = require('autoprefixer') module.exports = { context: path.resolve('src'), entry: './app', output: { path: path.resolve('public/'), publicPath: '/public/assets/', filename: 'bundle.js', }, resolve: { root: __dirname, extensions: ['', '.js', '.es6'], }, devServer: { contentBase: 'public', }, devtool: 'source-map', module: { preLoaders: [ { test: /\.js?\$/, loader: 'eslint-loader', exclude: 'node_modules' }, ], loaders: [ { test: /\.js\$/, loader: 'babel-loader', exclude: /node_modules/, query: { presets: ['es2015'], }, }, { test: /\.scss\$/, loader: ExtractTextPlugin.extract( 'style-loader', 'css-loader!postcss-loader!sass-loader' ), exclude: /node_modules/, }, { test: /\.css\$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader'), }, { test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?\$/, loader: 'url?limit=10000&amp;mimetype=application/font-woff', }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?\$/, loader: 'url?limit=10000&amp;mimetype=application/octet-stream', }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?\$/, loader: 'file', }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?\$/, loader: 'url?limit=10000&amp;mimetype=image/svg+xml', }, ], }, postcss: function() { return [autoprefixer] }, plugins: [new ExtractTextPlugin('style.css')], }`, `80247992219002470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span> <span class="token keyword">var</span> ExtractTextPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'extract-text-webpack-plugin'</span><span class="token punctuation">)</span> <span class="token keyword">var</span> autoprefixer <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'autoprefixer'</span><span class="token punctuation">)</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">context</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'src'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">entry</span><span class="token operator">:</span> <span class="token string">'./app'</span><span class="token punctuation">,</span> <span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'public/'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">publicPath</span><span class="token operator">:</span> <span class="token string">'/public/assets/'</span><span class="token punctuation">,</span> <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token string">'bundle.js'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">resolve</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">root</span><span class="token operator">:</span> __dirname<span class="token punctuation">,</span> <span class="token literal-property property">extensions</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">''</span><span class="token punctuation">,</span> <span class="token string">'.js'</span><span class="token punctuation">,</span> <span class="token string">'.es6'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">devServer</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">contentBase</span><span class="token operator">:</span> <span class="token string">'public'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">devtool</span><span class="token operator">:</span> <span class="token string">'source-map'</span><span class="token punctuation">,</span> <span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">preLoaders</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.js?$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'eslint-loader'</span><span class="token punctuation">,</span> <span class="token literal-property property">exclude</span><span class="token operator">:</span> <span class="token string">'node_modules'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.js$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'babel-loader'</span><span class="token punctuation">,</span> <span class="token literal-property property">exclude</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">node_modules</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">presets</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'es2015'</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 literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.scss$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> ExtractTextPlugin<span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span> <span class="token string">'style-loader'</span><span class="token punctuation">,</span> <span class="token string">'css-loader!postcss-loader!sass-loader'</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">exclude</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">node_modules</span><span class="token regex-delimiter">/</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 literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.css$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> ExtractTextPlugin<span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span><span class="token string">'style-loader'</span><span class="token punctuation">,</span> <span class="token string">'css-loader'</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 literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'url?limit=10000&amp;amp;mimetype=application/font-woff'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.ttf(\?v=\d+\.\d+\.\d+)?$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'url?limit=10000&amp;amp;mimetype=application/octet-stream'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.eot(\?v=\d+\.\d+\.\d+)?$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'file'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.svg(\?v=\d+\.\d+\.\d+)?$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'url?limit=10000&amp;amp;mimetype=image/svg+xml'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function-variable function">postcss</span><span class="token operator">:</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">return</span> <span class="token punctuation">[</span>autoprefixer<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token keyword">new</span> <span class="token class-name">ExtractTextPlugin</span><span class="token punctuation">(</span><span class="token string">'style.css'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>I’ll explain the configuration file section by section.</p> <p>The most important parts are entry points and output of webpack.</p> <ul> <li><code class="language-text">context</code>: this flag defines the root of the source files (for us js files). This is used to prevent repeating the full path while referring to source files.</li> <li><code class="language-text">entry</code>: this can be one or multiple files, depending on which one you use you should alter your output respectively.</li> <li><code class="language-text">output</code>: this is an object containing a couple of key/values. The first one is path which indicates which directory should be used for output. Second is the <code class="language-text">publicPath</code> which specifies the public URL address of the output files when referenced in a browser. For loaders that embed <code class="language-text">&lt;script></code> or <code class="language-text">&lt;link></code> tags or reference assets like images, <code class="language-text">publicPath</code> is used as the <code class="language-text">href</code> or <code class="language-text">url()</code> to the file when it’s different then their location on disk (as specified by path).</li> <li><code class="language-text">resolve</code>: options affecting the resolving of modules, extensions is an array of file extensions that should be parsed by webpack.</li> <li><code class="language-text">devServer</code>: these are the configuration of <code class="language-text">devServer</code> used for customising how devServer should work. I am using<code class="language-text">contentBase</code> for pointing the root of public as entry point.</li> <li><code class="language-text">devtool</code>: this one is used to tell webpack it should create <code class="language-text">source-map</code> files for debugging purposes.</li> <li><code class="language-text">module</code>: the main configuration flag is module.</li> <li><code class="language-text">preloaders</code>: this section can be used for anything that needs to be done before loading. <code class="language-text">Linting</code> is a good example which I’ve setup to use <code class="language-text">ESList</code>. This way it webpack gives you error on linting errors.</li> <li><code class="language-text">loaders</code>: I’ve explained this before, generally this is list of loaders used to create the bundle.</li> <li><code class="language-text">postcss</code>: this one is used to tell webpack what should it do after loading css files. <code class="language-text">Autoprefixer</code> is used to prefix any css attribute which has browser specific equivalent.</li> <li><code class="language-text">plugins</code>: this is the list of <code class="language-text">plugins</code> you might use with webpack. I am using <code class="language-text">extract-text-webpack-plugin</code> to force webpack to generate css output outside of js bundle.</li> </ul> <p>Long setup nah?</p> <p>Believe me this is the last one. You can now type <code class="language-text">npm start</code> to run the project and see the result.</p> <div class="gatsby-code-button-container" data-toaster-id="23958971359680213000" data-toaster-class="gatsby-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 start`, `23958971359680213000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-bash line-numbers"><code class="language-bash"><span class="token function">npm</span> start</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>You can now open your browser and type <code class="language-text">localhost:8080</code> and it will open up the <code class="language-text">index.html</code> for you.</p> <p>Hope you’ve enjoyed the guide.</p><![CDATA[Preparation steps for Angular 2 migration]]>https://yashints.dev/blog/2016/07/13/preparation-steps-for-angular-2-migrationhttps://yashints.dev/blog/2016/07/13/preparation-steps-for-angular-2-migrationWed, 13 Jul 2016 00:00:00 GMT<p>I’ve seen many ways to shape an Angular app in different companies. This means when we try to upgrade to Angular 2 some of them might be easy to migrate compared to others.</p> <!--more--> <p>So why we don’t try to write some code that is easy to migrate even before trying to upgrade???</p> <p>According to Angular official website there are a few keys and patterns to follow which lets us make the transition smoother when the time comes. But first let’s discuss why we should upgrade.</p> <h2 id="why-upgrade" style="position:relative;"><a href="#why-upgrade" aria-label="why upgrade permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 Upgrade</h2> <p>You might have not noticed but Angular 1.x can be very dangerous in the hand of a developer who does not know how stuff works and only wants to get the task done without thinking of the consequences.</p> <p>Thinking about all of the watches that will be put in a page plus a code that can be very poor designed is very scary and need to be considered by every team lead or team member specially during code reviews.</p> <p>Anyway below you can find a couple of strong reasons on why we should think of moving towards Angular 2:</p> <ul> <li><strong>Better Performance</strong> - Angular 2 comes with a way faster change detection, template pre-compilation, faster bootstrap time, view caching and plenty other things that make the framework pretty fast.</li> <li><strong>Server-side Rendering</strong> - The next version of Angular has been split up into two parts, an application layer and a render layer. This enables us to run Angular in other environments than the browser like Web Workers or even servers.</li> <li><strong>More powerful Templating</strong> - The new template syntax is statically analyzable, removes many directives and integrates better with Web Components and other elements.</li> <li><strong>Better Ecosystem</strong> - Of course, at the time of writing this article, this is not true. But the Angular 2 ecosystem will eventually be better and more interesting to us in the future.</li> </ul> <h2 id="consider-following-angular-style-guide" style="position:relative;"><a href="#consider-following-angular-style-guide" aria-label="consider following angular style 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>Consider Following Angular Style Guide</h2> <p>The <a href="https://angular.io/guide/styleguide" target="_blank" rel="nofollow noopener noreferrer">Angular Style Guides</a> is a collection of useful patterns and practices that helps developers write readable, maintainable, cleaner and efficient code.  It contains a wealth of information about how to write and organize Angular code - and equally importantly - how <strong>not</strong> to write and organize Angular code.</p> <p>In writing Angular 2, the team members tries to maintain the <strong>good</strong> parts while get rid of the <strong>bad</strong> ones. Although there are way more than that to be said but general idea is that it should be a framework which people can rely on in their production environments.</p> <p>There are a few particular rules in there that I would like to bold here:</p> <ol> <li>There should be one component per file, which let’s us not only have maintainable code but also makes it easy to migrate them one at a time regardless of the destination framework (e.g Angular 2 or React).</li> <li>The <a href="https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#folders-by-feature-structure" target="_blank" rel="nofollow noopener noreferrer">Folders-by-Feature Structure</a> and <a href="https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modularity" target="_blank" rel="nofollow noopener noreferrer">Modularity</a> rules define similar principles on a higher level which tell us different parts of the app should be placed in different folders and modules.</li> </ol> <h2 id="dont-choose-anything-else-than-amodule-loader" style="position:relative;"><a href="#dont-choose-anything-else-than-amodule-loader" aria-label="dont choose anything else than amodule loader permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Don’t choose anything else than a module loader</h2> <p>JavaScript admittedly has plenty of flaws, but one of the largest and most prominent is the lack of a module system: a way to split up your application into a series of smaller files that can depend on each other to function correctly. While doing so having large number of smaller files is better than small number of large files, but it does not work well if we have to load them all into Html file by script tags.</p> <p>Because of dependencies that exists with this structure the need for a module loader is vital. There are a couple of good tools out there like Webpack, Browserify or SystemJs which pretty much are making use of typescript built in module system.</p> <p>By specifying <em>import</em> and <em>export</em> in modules we define which modules can be exported and which ones depend on another.</p> <h2 id="we-should-migrate-to-typescript" style="position:relative;"><a href="#we-should-migrate-to-typescript" aria-label="we should migrate to typescript permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>We should migrate to TypeScript</h2> <p>Because Angular 2 itself is recommending to use that, we should migrate our current code to TypeScript even before starting the migration so there would be one less concern when the day comes. By just importing TypeScript compiler and renaming files from <code class="language-text">*.js</code> to <code class="language-text">*.ts</code> wouldn’t be enough. You have to at least follow some of the ES6 new features which you can find here (<a href="/2016/07/06/es6-new-features-part-i/">part 1</a>, <a href="/2016/07/07/es6-new-features-part-ii/">part 2</a>, <a href="/2016/07/11/es6-new-features-part-iii/">part 3</a>). That’s why I started with them as one of the most important prerequisites of the process.</p> <h2 id="directives-as-components" style="position:relative;"><a href="#directives-as-components" aria-label="directives as 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>Directives as Components</h2> <p>Angular 2 is heavily dependent on Components which basically are a portion of UI whose got a special logic behind that. The UI part can be a template but by containing them in a <em>directive</em> you can make sure that migration process would be easier.</p> <p>Well that somehow makes things in perspective but to be more precise a directive which contains the template, controller and bindings required to deliver that functionality. Based on Angular website a directive should cover bellow items to be Angular 2 compatible:</p> <ul> <li><code class="language-text">restrict: 'E'</code>. Components are usually used as elements.</li> <li><code class="language-text">scope: {}</code> - an isolate scope. In Angular 2, components are always isolated from their surroundings, and we should do this in Angular 1 too.</li> <li><code class="language-text">bindToController: {}</code>. Component inputs and outputs should be bound to the controller instead of using the <code class="language-text">$scope</code>.</li> <li><code class="language-text">controller</code> and <code class="language-text">controllerAs</code>. Components have their own controllers.</li> <li><code class="language-text">template</code> or <code class="language-text">templateUrl</code>. Components have their own templates. Also it is mentioned that the directive should not use <code class="language-text">compile</code>, <code class="language-text">replace: true</code>, <code class="language-text">priority</code> and <code class="language-text">terminal</code>.</li> </ul> <p>This is how a ideal directive looks like:</p> <div class="gatsby-code-button-container" data-toaster-id="9128115392921443000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export function myDetailDirective() { return { restrict: 'E', scope: {}, bindToController: { myInfo: '=', getCreditCardInfo: '&', }, template: \` <h2>My name is: {{ctrl.myInfo.myName}}</h2> <button ng-click=&quot;ctrl.onClick()&quot;>Get card info</button> \`, controller: function() { this.onClick = () => { this.getCreditCardInfo({ name: this.myInfo }) } }, controllerAs: 'ctrl', } }`, `9128115392921443000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">myDetailDirective</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">restrict</span><span class="token operator">:</span> <span class="token string">'E'</span><span class="token punctuation">,</span> <span class="token literal-property property">scope</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">bindToController</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">myInfo</span><span class="token operator">:</span> <span class="token string">'='</span><span class="token punctuation">,</span> <span class="token literal-property property">getCreditCardInfo</span><span class="token operator">:</span> <span class="token string">'&amp;'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> &lt;h2>My name is: {{ctrl.myInfo.myName}}&lt;/h2> &lt;button ng-click="ctrl.onClick()">Get card info&lt;/button> </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token function-variable function">controller</span><span class="token operator">:</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">this</span><span class="token punctuation">.</span><span class="token function-variable function">onClick</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">this</span><span class="token punctuation">.</span><span class="token function">getCreditCardInfo</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>myInfo <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 literal-property property">controllerAs</span><span class="token operator">:</span> <span class="token string">'ctrl'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you are already using Angular 1.5 you should use its Component API which helps you define such directives. This API enforces you to use controllerAs syntax and also has good default values for <code class="language-text">scope</code> and <code class="language-text">restrict</code>.</p> <p>The above directive looks like below:</p> <div class="gatsby-code-button-container" data-toaster-id="56532004686072470000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export const myDetail = { bindings: { myInfo: '=', getCreditCardInfo: '&', }, template: \` <h2>My name is: {{ ctrl.myInfo.myName }}</h2> <button ng-click=&quot;ctrl.onClick()&quot;>Get card info</button> \`, controller: function() { this.onClick = () => { this.getCreditCardInfo(this.myInfo) } }, }`, `56532004686072470000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> myDetail <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">bindings</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">myInfo</span><span class="token operator">:</span> <span class="token string">'='</span><span class="token punctuation">,</span> <span class="token literal-property property">getCreditCardInfo</span><span class="token operator">:</span> <span class="token string">'&amp;'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> &lt;h2>My name is: {{ ctrl.myInfo.myName }}&lt;/h2> &lt;button ng-click="ctrl.onClick()">Get card info&lt;/button> </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token function-variable function">controller</span><span class="token operator">:</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">this</span><span class="token punctuation">.</span><span class="token function-variable function">onClick</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">this</span><span class="token punctuation">.</span><span class="token function">getCreditCardInfo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>myInfo<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>{: .box-note} <strong>Note:</strong> I had to remove the $ from above code because of mark down rendering errors.</p> <h2 id="upgrade-using-the-given-adapter" style="position:relative;"><a href="#upgrade-using-the-given-adapter" aria-label="upgrade using the given adapter permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Upgrade using the given Adapter</h2> <p>When everyone was thinking of how to deal with breaking changes introduced in the very initial introduction of Angular 2, they were trying to tackle this issue to make it easier to upgrade. They came up with <em>ng-upgrade,</em> an awesome Adapter which let’s you mix Angular 1 and 2 code together.</p> <p>This way, (if you’ve already done the steps mentioned earlier) you can start migrating your components one by one and not worry about what happens with current state of the product. The story gets more exciting as directives and services in one application can interact with the other one which is amazing (and also <strong>dangerous</strong> in the wrong hands).</p> <p>In order for this to happen four things need to be in place:</p> <ul> <li><strong>Dependency Injection</strong> - Exposing Angular 2 services into Angular 1 components and vice-versa.</li> <li><strong>Component Nesting</strong> - Angular 1 directives can be used in Angular 2 components and Angular 2 components can be used in Angular 1 directives.</li> <li><strong>Content Projection / Transclusion</strong> - Angular 1 components transclude Angular 2 components and Angular 2 component project Angular 1 directives.</li> <li><strong>Change Detection</strong> - Angular 1 scope digest and change detectors in Angular 2 are interleaved.</li> </ul> <p>With these four things being interoperable, we can already start upgrading our applications component by component. Routing is another part that can help but is not necessarily mandatory, since we can totally stick with any Angular 1 routing system while upgrading.</p> <p>An example is shown in the following code to illustrate what we talked about:</p> <div class="gatsby-code-button-container" data-toaster-id="89930956152879710000" data-toaster-class="gatsby-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 { UpgradeAdapter } from '@angular/upgrade' var adapter = new UpgradeAdapter() var app = angular.module('myApp', []) adapter.bootstrap(document.body, ['myApp'])`, `89930956152879710000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> UpgradeAdapter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/upgrade'</span> <span class="token keyword">var</span> adapter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UpgradeAdapter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">var</span> app <span class="token operator">=</span> angular<span class="token punctuation">.</span><span class="token function">module</span><span class="token punctuation">(</span><span class="token string">'myApp'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> adapter<span class="token punctuation">.</span><span class="token function">bootstrap</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'myApp'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Cool now we can take advantage of ng-upgrade in our Angular 1 app and start migrating to Angular 2. Of course there are a lot more to do but you get the idea.</p> <h2 id="user-service-instead-of-factory" style="position:relative;"><a href="#user-service-instead-of-factory" aria-label="user service instead of factory permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>User service instead of factory</h2> <p>If you are planning to upgrade to Angular 2 and also the language you are using like ES6, it completely makes sense that you should use <code class="language-text">.service()</code> instead of <code class="language-text">.factory()</code> where a service can be potentially a class.</p> <p>In Angular 2, a service is also just a class, so this seems like a logical step to undertake.</p> <p>I think that’s enough for making you think about the steps you have to take to be ready take off. For a full documentation on preparation you can read <a href="https://angular.io/guide/upgrade" target="_blank" rel="nofollow noopener noreferrer">this page</a>.</p><![CDATA[ES6 new features (Part III)]]>https://yashints.dev/blog/2016/07/11/es6-new-features-part-iiihttps://yashints.dev/blog/2016/07/11/es6-new-features-part-iiiMon, 11 Jul 2016 00:00:00 GMT<p>Well for a long time I wanted to write a blog post about migrating Angular 1.x to 2, however, before doing so I thought it is really helpful to write about some prerequisites of that.</p> <!--more--> <p>This is the third article in ES6 new features series.</p> <p><a href="/2016/07/06/es6-new-features-part-i/">Part I</a></p> <p><a href="/2016/07/07/es6-new-features-part-ii/">Part II</a></p> <h3 id="9-classes-in-es6" style="position:relative;"><a href="#9-classes-in-es6" aria-label="9 classes in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>9. Classes in ES6</h3> <p>In many ways, they are a sham. Javascript classes don’t really exist other than for cosmetic reasons. They are syntactic sugar over existing Javascript prototypical inheritance. The reason for this was to ensure backwards compatibility, classes merely give you a cleaner way to organise your code.</p> <p>If you love object-oriented programming (OOP), then you’ll love this feature. In ES5 there wan not a <em>class</em> keyword.</p> <div class="gatsby-code-button-container" data-toaster-id="45408928356401240000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class myClass { constructor(name = 'default', age = 80) { this.name = name this.age = age } sayName() { alert(this.name) } sayAge() { alert(this.age) } } const myInstance = new myClass() myInstance.sayName()`, `45408928356401240000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">myClass</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">'default'</span><span class="token punctuation">,</span> age <span class="token operator">=</span> <span class="token number">80</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name <span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age <span class="token punctuation">}</span> <span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">sayAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>age<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> myInstance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">myClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> myInstance<span class="token punctuation">.</span><span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Notice that I’m using default parameter values for name and age. Also, method names don’t need to have the word <code class="language-text">function</code> or the colon (<code class="language-text">:</code>) anymore.</p> <p>When it comes to inheritance it is very similar to OOP programming languages such as C# or any other one. The basic inheritance can be implemented as follow:</p> <div class="gatsby-code-button-container" data-toaster-id="16856281258377658000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`class childClass extends myClass { constructor(name, age) { super(name, age) } // Override the someClass method above sayName() { // This will call someClass.sayName() triggering the old alert // Which will just display our name super.sayName() // This will trigger the new alert which has labels and our age alert('Name:' + this.name + ' Age:' + this.age) } } const myChild = new childClass('dwayne', 27) myChild.sayName()`, `16856281258377658000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">childClass</span> <span class="token keyword">extends</span> <span class="token class-name">myClass</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> age<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// Override the someClass method above</span> <span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// This will call someClass.sayName() triggering the old alert</span> <span class="token comment">// Which will just display our name</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// This will trigger the new alert which has labels and our age</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Name:'</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">+</span> <span class="token string">' Age:'</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>age<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> myChild <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">childClass</span><span class="token punctuation">(</span><span class="token string">'dwayne'</span><span class="token punctuation">,</span> <span class="token number">27</span><span class="token punctuation">)</span> myChild<span class="token punctuation">.</span><span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Notice that to call the parent constructor, effortlessly invoke <code class="language-text">super()</code> with expected parameters. Isn’t it amazing?</p> <h3 id="10-modules-in-es6" style="position:relative;"><a href="#10-modules-in-es6" aria-label="10 modules in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>10. Modules in ES6</h3> <p>As you might now, there were no native modules support in JavaScript before ES6. People came up with AMD, RequireJS, CommonJS and other workarounds. Now there are modules with <code class="language-text">import</code> and <code class="language-text">export</code> operands.</p> <p>The ES6 module standard has two parts:</p> <ul> <li>Declarative syntax (for importing and exporting)</li> <li>Programmatic loader API: to configure how modules are loaded and to conditionally load modules</li> </ul> <div class="gatsby-code-button-container" data-toaster-id="75606043570745340000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`export const myName = 'Yaser' export function getCreditCardNumber() { //Not implemented yet, you can leave yours //in the comments for the moment 😉 }`, `75606043570745340000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> myName <span class="token operator">=</span> <span class="token string">'Yaser'</span> <span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">getCreditCardNumber</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//Not implemented yet, you can leave yours</span> <span class="token comment">//in the comments for the moment 😉</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In other modules, we use <code class="language-text">import {myName} from 'my-module'</code>syntax. For example:</p> <div class="gatsby-code-button-container" data-toaster-id="1346658628833963300" data-toaster-class="gatsby-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 { myName, getCreditCardNumber } from 'module' console.log(myName) // Yaser`, `1346658628833963300`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> myName<span class="token punctuation">,</span> getCreditCardNumber <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'module'</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>myName<span class="token punctuation">)</span> <span class="token comment">// Yaser</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Or we can import everything as a variable in other modules and use it as an object literal:</p> <div class="gatsby-code-button-container" data-toaster-id="89333452577981970000" data-toaster-class="gatsby-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 * as myData from 'module' console.log(myData.myName) // Yaser`, `89333452577981970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> myData <span class="token keyword">from</span> <span class="token string">'module'</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>myData<span class="token punctuation">.</span>myName<span class="token punctuation">)</span> <span class="token comment">// Yaser</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Modules that only export single values are very popular in the <code class="language-text">Node.js</code> community. But they are also common in front-end development where you often have constructors/classes for models, with one model per module. An ECMAScript 6 module can pick a <em>default export</em>, the most important exported value. Default exports are especially easy to import.</p> <p>The following ES6 module “is” a single function:</p> <div class="gatsby-code-button-container" data-toaster-id="40041166602540020000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`//------ myFunc.js ------ export default function () { ... }; //------ main1.js ------ import myFunc from 'myFunc'; myFunc();`, `40041166602540020000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token comment">//------ myFunc.js ------</span> <span class="token keyword">export</span> <span class="token keyword">default</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 operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">//------ main1.js ------</span> <span class="token keyword">import</span> myFunc <span class="token keyword">from</span> <span class="token string">'myFunc'</span><span class="token punctuation">;</span> <span class="token function">myFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>An ES6 module whose default export is a class looks as follows:</p> <div class="gatsby-code-button-container" data-toaster-id="2279013762950832000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`//------ MyClass.js ------ export default class { ... }; //------ main2.js ------ import MyClass from 'MyClass'; let instance = new MyClass();`, `2279013762950832000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token comment">//------ MyClass.js ------</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">class</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">//------ main2.js ------</span> <span class="token keyword">import</span> MyClass <span class="token keyword">from</span> <span class="token string">'MyClass'</span><span class="token punctuation">;</span> <span class="token keyword">let</span> instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And finally having both default and named exports together will look like something like the following code. I used some underscore metadata to show how it can be used and simplify everything.</p> <div class="gatsby-code-button-container" data-toaster-id="28646006156067426000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`//------ underscore.js ------ export default function (obj) { ... }; export function each(obj, iterator, context) { ... } export { each as forEach }; //------ main.js ------ import _, { each } from 'underscore';`, `28646006156067426000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token comment">//------ underscore.js ------</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">obj</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 keyword">export</span> <span class="token keyword">function</span> <span class="token function">each</span><span class="token punctuation">(</span><span class="token parameter">obj<span class="token punctuation">,</span> iterator<span class="token punctuation">,</span> context</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">export</span> <span class="token punctuation">{</span> each <span class="token keyword">as</span> forEach <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">//------ main.js ------</span> <span class="token keyword">import</span> _<span class="token punctuation">,</span> <span class="token punctuation">{</span> each <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'underscore'</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="11-how-to-use-it" style="position:relative;"><a href="#11-how-to-use-it" aria-label="11 how to use 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>11. How to use it</h3> <p>Well ES6 is not currently supported by all browsers and also those who does support it only have implemented part of it, so you need a safe way to utilise its power.</p> <p>Here there are a couple of options but apparently best of which is Babel (which is a compiler). You can run it as a standalone tool or use with your build system. There are Babel <a href="http://babeljs.io/docs/setup" target="_blank" rel="nofollow noopener noreferrer">plugins</a> for Grunt, Gulp and webpack (again my favourite).</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; " > <a class="gatsby-resp-image-link" href="/static/7661763e0327bc0424519492e721976e/e5715/babel.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 59.25925925925925%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAABcElEQVR42qWQ3UoCURDHzwOV66prQu6XF6HrEgSSeNNLdN0L9Ajdd5cSEXRVWURYQmR033olIoor+MF++G/n2LHuQh34MWfmzPzPzGH1qoWzUxU353k81mycHGs4qmTwdGmjXi3iobagcW1znq9s3F1YUW2Urwos3Ec5qmM7mQRsK41iXsF+UUF+LwU5EUcyRchIEYrMzwIRc68svIApaRnlkoHKoYlKOYfSgY6sugtVyyKRlBGTtiBJ25Div8SiOCa8OP/cMd1QUSiYMHIkpEPTdZimBiNC07Mrw9pfn/h4u0XjpYlm85XTar3DaTtwnBVoL2Bh6GMw6MF1R/A9D2EYYj6fY11jnkeCA4xGkaDvc8EgCPh5FaiHelkQBd1ulwuOx2NMJhNMp9Mls9mMe8oTVEOxqCWoxou24xOScqfTQb/fXzbTyuuuzQVd112+JKYi/pp45L/HuCBNRyvQX2xqXLDX62E4HPIp6WM3EfwGnjwH2lnKMS8AAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="babel" title="" src="/static/7661763e0327bc0424519492e721976e/e5715/babel.png" srcset="/static/7661763e0327bc0424519492e721976e/01bf6/babel.png 270w, /static/7661763e0327bc0424519492e721976e/07484/babel.png 540w, /static/7661763e0327bc0424519492e721976e/e5715/babel.png 768w" sizes="(max-width: 768px) 100vw, 768px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" decoding="async" /> </a> </span></p><![CDATA[ES6 new features (Part II)]]>https://yashints.dev/blog/2016/07/07/es6-new-features-part-iihttps://yashints.dev/blog/2016/07/07/es6-new-features-part-iiThu, 07 Jul 2016 00:00:00 GMT<p>Well for a long time I wanted to write a blog post about migrating Angular 1.x to 2, however, before doing so I thought it is really helpful to write about some prerequisites of that.</p> <!--more--> <p>This is the second article in ES6 new features series.</p> <p><a href="/2016/07/06/es6-new-features-part-i/">Part I</a></p> <p><a href="/2016/07/11/es6-new-features-part-iii/">Part III</a></p> <h3 id="6-arrow-functions-in-es6" style="position:relative;"><a href="#6-arrow-functions-in-es6" aria-label="6 arrow functions in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>6. Arrow Functions in ES6</h3> <p>Do you remember the fat functions of CoffeeScript? Now we have them in ES6. An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target).</p> <p>Arrow functions are always anonymous. The fat arrows are amazing because they would make your <code class="language-text">this</code> behave properly, i.e., <code class="language-text">this</code> will have the same value as in the context of the function—it won’t mutate. The mutation typically happens each time you create a closure.</p> <div class="gatsby-code-button-container" data-toaster-id="16632067499612168000" data-toaster-class="gatsby-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 a = ['Hydrogen', 'Helium', 'Lithium', 'Beryl­lium'] var a2 = a.map(function(s) { return s.length }) var a3 = a.map(s => s.length)`, `16632067499612168000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> a <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'Hydrogen'</span><span class="token punctuation">,</span> <span class="token string">'Helium'</span><span class="token punctuation">,</span> <span class="token string">'Lithium'</span><span class="token punctuation">,</span> <span class="token string">'Beryl­lium'</span><span class="token punctuation">]</span> <span class="token keyword">var</span> a2 <span class="token operator">=</span> a<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">s</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> s<span class="token punctuation">.</span>length <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">var</span> a3 <span class="token operator">=</span> a<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">s</span> <span class="token operator">=></span> s<span class="token punctuation">.</span>length<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The parenthesis <code class="language-text">()</code> are optional for single params in an arrow function signature. You need them when you use more than one param.</p> <div class="gatsby-code-button-container" data-toaster-id="30523390225543890000" data-toaster-class="gatsby-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 ids = ['56', '5632'] var messages = ids.map(function(value, index, list) { return 'ID of ' + index + ' element is ' + value + ' ' // explicit return })`, `30523390225543890000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> ids <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'56'</span><span class="token punctuation">,</span> <span class="token string">'5632'</span><span class="token punctuation">]</span> <span class="token keyword">var</span> messages <span class="token operator">=</span> ids<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">value<span class="token punctuation">,</span> index<span class="token punctuation">,</span> list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'ID of '</span> <span class="token operator">+</span> index <span class="token operator">+</span> <span class="token string">' element is '</span> <span class="token operator">+</span> value <span class="token operator">+</span> <span class="token string">' '</span> <span class="token comment">// explicit return</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>And more eloquent version of the code in ES6 with parenthesis around params and implicit return:</p> <div class="gatsby-code-button-container" data-toaster-id="83276506583223270000" data-toaster-class="gatsby-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 ids = ['56', '5632'] var messages = ids.map( (value, index, list) => \`ID of \${index} element is \${value} \` ) // implicit return`, `83276506583223270000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> ids <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'56'</span><span class="token punctuation">,</span> <span class="token string">'5632'</span><span class="token punctuation">]</span> <span class="token keyword">var</span> messages <span class="token operator">=</span> ids<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token parameter">value<span class="token punctuation">,</span> index<span class="token punctuation">,</span> list</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">ID of </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"> element is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token comment">// implicit return</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="7-promises-in-es6" style="position:relative;"><a href="#7-promises-in-es6" aria-label="7 promises in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>7. Promises in ES6</h3> <p>Promises have been a controversial topic. There were a lot of promise implementations with slightly different syntax. q, bluebird, deferred.js, vow, avow, jquery deferred to name just a few.</p> <p>Promises have been around quite a while and are defined by a spec called Promise/A+. ES6 has adopted this spec for its Promise implementation.</p> <p>Promises give us a way to handle asynchronous processing in a more synchronous fashion. They represent a value that we can handle at some point in the future. And, better than callbacks here, Promises give us guarantees about that future value, specifically:</p> <ol> <li>No other registered handlers of that value can change it (<em>the Promise is immutable</em>)</li> <li>We are guaranteed to receive the value, regardless of when we register a handler for it, even if it’s already resolved (<em>in contrast to events, which can incur race conditions</em>).</li> </ol> <div class="gatsby-code-button-container" data-toaster-id="48159550146785080000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// an immediately resolved promise var p2 = Promise.resolve('foo') // can get it after the fact, unlike events p2.then(res => console.log(res)) var p = new Promise(function(resolve, reject) { setTimeout(() => resolve(4), 2000) }) // handler can't change promise, just value p.then(res => { res += 2 console.log(res) }) // still gets 4 p.then(res => console.log(res))`, `48159550146785080000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token comment">// an immediately resolved promise</span> <span class="token keyword">var</span> p2 <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span> <span class="token comment">// can get it after the fact, unlike events</span> p2<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">var</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// handler can't change promise, just value</span> p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res <span class="token operator">+=</span> <span class="token number">2</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// still gets 4</span> p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The standard way to create a Promise is by using the <code class="language-text">new Promise</code> constructor which accepts a handler that is given two functions as parameters. The first handler (<em>typically named</em> <code class="language-text">resolve</code>) is a function to call with the future value when it’s ready; and the second handler (<em>typically named</em> <code class="language-text">reject</code>) is a function to call to reject the Promise if it can’t resolve the future value.</p> <div class="gatsby-code-button-container" data-toaster-id="80166773650045710000" data-toaster-class="gatsby-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 p = new Promise(function(resolve, reject) { if (/* condition */) { resolve(/* value */); // fulfilled successfully } else { reject(/* reason */); // error, rejected } });`, `80166773650045710000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</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 comment">/* condition */</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token comment">/* value */</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// fulfilled successfully</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">reject</span><span class="token punctuation">(</span><span class="token comment">/* reason */</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// error, rejected</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>And with ES6 arrow functions:</p> <div class="gatsby-code-button-container" data-toaster-id="4406127203410959000" data-toaster-class="gatsby-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 wait1000 = new Promise((resolve, reject) => { setTimeout(resolve, 1000) }).then(() => { console.log('Yay!') })`, `4406127203410959000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> wait1000 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">1000</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">then</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> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Yay!'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Now with a slight modification we can revise that to look like this:</p> <div class="gatsby-code-button-container" data-toaster-id="6522295941170708000" data-toaster-class="gatsby-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 wait1000 = () => new Promise((resolve, reject) => { setTimeout(resolve, 1000) }) wait1000() .then(function() { console.log('Yay!') return wait1000() }) .then(function() { console.log('Wheeyee!') })`, `6522295941170708000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> <span class="token function-variable function">wait1000</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token function">wait1000</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 keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Yay!'</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">wait1000</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">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Wheeyee!'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h3 id="8-block-scoped-constructs-let-and-const" style="position:relative;"><a href="#8-block-scoped-constructs-let-and-const" aria-label="8 block scoped constructs let and const permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>8. Block-Scoped Constructs Let and Const</h3> <p>ES6 provides two new ways of declaring variables: <code class="language-text">let</code> and <code class="language-text">const</code>, which mostly replace the ES5 way of declaring variables, <code class="language-text">var</code>. <code class="language-text">let</code> works similarly to <code class="language-text">var</code>, but the variable it declares is <em>block-scoped</em>, it only exists within the current block.</p> <p><code class="language-text">var</code> is <em>function-scoped</em>. In the following code, you can see that the <code class="language-text">let</code>-declared variable <code class="language-text">tmp</code> only exists with the block that starts in line A:</p> <div class="gatsby-code-button-container" data-toaster-id="74014278061094100000" data-toaster-class="gatsby-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 order(x, y) { if (x > y) { // (A) let tmp = x x = y y = tmp } console.log(tmp === x) // ReferenceError: tmp is not defined return [x, y] }`, `74014278061094100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">order</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">></span> y<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// (A)</span> <span class="token keyword">let</span> tmp <span class="token operator">=</span> x x <span class="token operator">=</span> y y <span class="token operator">=</span> tmp <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>tmp <span class="token operator">===</span> x<span class="token punctuation">)</span> <span class="token comment">// ReferenceError: tmp is not defined</span> <span class="token keyword">return</span> <span class="token punctuation">[</span>x<span class="token punctuation">,</span> y<span class="token punctuation">]</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><code class="language-text">const</code> works like <code class="language-text">let</code>, but the variable you declare must be immediately initialized, with a value that can’t be changed afterwards.</p> <div class="gatsby-code-button-container" data-toaster-id="68065107053004790000" data-toaster-class="gatsby-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 foo; // SyntaxError: missing = in const declaration const bar = 123; bar = 456; // TypeError: \`bar\` is read-only`, `68065107053004790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">const</span> foo<span class="token punctuation">;</span> <span class="token comment">// SyntaxError: missing = in const declaration</span> <span class="token keyword">const</span> bar <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> bar <span class="token operator">=</span> <span class="token number">456</span><span class="token punctuation">;</span> <span class="token comment">// TypeError: `bar` is read-only</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Since <code class="language-text">for-of</code> creates one <em>binding</em> (storage space for a variable) per loop iteration, it is OK to <code class="language-text">const</code>-declare the loop variable:</p> <div class="gatsby-code-button-container" data-toaster-id="45327191395233540000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`for (const x of ['a', 'b']) { console.log(x) } // Output: // a // b`, `45327191395233540000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> x <span class="token keyword">of</span> <span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</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>x<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// Output:</span> <span class="token comment">// a</span> <span class="token comment">// b</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The following table gives an overview of six ways in which variables can be declared in ES6:</p> <table> <thead> <tr> <th align="left"></th> <th align="left">Hoisting</th> <th align="left">Scope</th> <th align="left">Creates global properties</th> </tr> </thead> <tbody> <tr> <td align="left"><code class="language-text">var</code></td> <td align="left">Declaration</td> <td align="left">Function</td> <td align="left">Yes</td> </tr> <tr> <td align="left"><code class="language-text">let</code></td> <td align="left">Temporal dead zone</td> <td align="left">Block</td> <td align="left">No</td> </tr> <tr> <td align="left"><code class="language-text">const</code></td> <td align="left">Temporal dead zone</td> <td align="left">Block</td> <td align="left">No</td> </tr> <tr> <td align="left"><code class="language-text">function</code></td> <td align="left">Complete</td> <td align="left">Block</td> <td align="left">Yes</td> </tr> <tr> <td align="left"><code class="language-text">class</code></td> <td align="left">No</td> <td align="left">Block</td> <td align="left">No</td> </tr> <tr> <td align="left"><code class="language-text">import</code></td> <td align="left">Complete</td> <td align="left">Module-global</td> <td align="left">No</td> </tr> </tbody> </table><![CDATA[ES6 new features (Part I)]]>https://yashints.dev/blog/2016/07/06/es6-new-features-part-ihttps://yashints.dev/blog/2016/07/06/es6-new-features-part-iWed, 06 Jul 2016 00:00:00 GMT<p>Well for a long time I wanted to write a blog post about migrating Angular 1.x to 2, however, before doing so I thought it is really helpful to write about some prerequisites of that.</p> <!--more--> <p>This is the first article in ES6 new features series.</p> <p><a href="/2016/07/07/es6-new-features-part-ii/">Part II</a></p> <p><a href="/2016/07/11/es6-new-features-part-iii/">Part III</a></p> <p>Number one in the list would be ES6. Which is the topic of today’s post. ES6 (often referred to as “Harmony”) is the upcoming sixth major release of the ECMAScript language specification.</p> <p>However, that does not put things in perspective. I prefer to say it is the newest JavaScript implementation, simple as that.</p> <p>I just briefly list them here and go through one by one:</p> <ol> <li>Default Parameters in ES6</li> <li>Template Literals in ES6</li> <li>Multi-line Strings in ES6</li> <li>Destructuring Assignment in ES6</li> <li>Enhanced Object Literals in ES6</li> <li>Arrow Functions in ES6</li> <li>Promises in ES6</li> <li>Block-Scoped Constructs Let and Const</li> <li>Classes in ES6</li> <li>Modules in ES6 Although it might look like a short list but they are the most important ones.</li> </ol> <h3 id="1-default-parameters-in-es6" style="position:relative;"><a href="#1-default-parameters-in-es6" aria-label="1 default parameters in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Default Parameters in ES6</h3> <p>If you remember previously we had to explicitly specify a value if the coming parameter to a method didn’t have one.</p> <div class="gatsby-code-button-container" data-toaster-id="80721021988063150000" data-toaster-class="gatsby-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 bar = function(foo) { var temp = foo || 'default value' }`, `80721021988063150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> <span class="token function-variable function">bar</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">foo</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> temp <span class="token operator">=</span> foo <span class="token operator">||</span> <span class="token string">'default value'</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Now it is like one of high level languages such as C#.</p> <div class="gatsby-code-button-container" data-toaster-id="470693334445826370" data-toaster-class="gatsby-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 bar = function(foo = 'default value') { //code goes here }`, `470693334445826370`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> <span class="token function-variable function">bar</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>foo <span class="token operator">=</span> <span class="token string">'default value'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//code goes here</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <h3 id="2-template-literals-in-es6" style="position:relative;"><a href="#2-template-literals-in-es6" aria-label="2 template literals in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Template Literals in ES6</h3> <p>Template literals or interpolation in other languages is a way to output variables in the string. So in ES5 we had to break the string like this:</p> <div class="gatsby-code-button-container" data-toaster-id="77744996947828900000" data-toaster-class="gatsby-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 fullname = firstname + ' ' + lastname`, `77744996947828900000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> fullname <span class="token operator">=</span> firstname <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">+</span> lastname</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>In ES6 though you can use the new syntax ${} which is again like C#:</p> <div class="gatsby-code-button-container" data-toaster-id="89872337883628190000" data-toaster-class="gatsby-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 fullname = \`Your name is \${firstname} \${lastname}.\``, `89872337883628190000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> fullname <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Your name is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstname<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lastname<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.</span><span class="token template-punctuation string">`</span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h3 id="3-multi-line-strings-in-es6" style="position:relative;"><a href="#3-multi-line-strings-in-es6" aria-label="3 multi line strings in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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. Multi-line Strings in ES6</h3> <p>Previously we had to use + to shape multiple line strings something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="52754362211501630000" data-toaster-class="gatsby-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 fourAgreements = 'You have the right to be you.' + 'You can only be you when you do your best.'`, `52754362211501630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> fourAgreements <span class="token operator">=</span> <span class="token string">'You have the right to be you.'</span> <span class="token operator">+</span> <span class="token string">'You can only be you when you do your best.'</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <p>But in ES6 they introduced the multi-line string literal ` which makes life easier:</p> <div class="gatsby-code-button-container" data-toaster-id="61869132494956850000" data-toaster-class="gatsby-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 fourAgreements = \`You have the right to be you. You can only be you when you do your best.\``, `61869132494956850000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> fourAgreements <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">You have the right to be you. You can only be you when you do your best.</span><span class="token template-punctuation string">`</span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <h3 id="4-destructuring-assignment-in-es6" style="position:relative;"><a href="#4-destructuring-assignment-in-es6" aria-label="4 destructuring assignment in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4. Destructuring Assignment in ES6</h3> <p>This can be a little confusing as there is some logic behind it. In ES5 when we wanted to extract  some properties from an object we should define them as below:</p> <div class="gatsby-code-button-container" data-toaster-id="49005286586818580000" data-toaster-class="gatsby-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 data = \$('body').data(), // data has properties cat and mouse house = data.cat, mouse = data.mouse`, `49005286586818580000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> data <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'body'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// data has properties cat and mouse</span> house <span class="token operator">=</span> data<span class="token punctuation">.</span>cat<span class="token punctuation">,</span> mouse <span class="token operator">=</span> data<span class="token punctuation">.</span>mouse</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>In ES6, we can replace the ES5 code above with these statements:</p> <div class="gatsby-code-button-container" data-toaster-id="10005330785487354000" data-toaster-class="gatsby-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 { cat, mouse } = \$('body').data() // we'll get house and mouse variables`, `10005330785487354000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> <span class="token punctuation">{</span> cat<span class="token punctuation">,</span> mouse <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'body'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// we'll get house and mouse variables</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <h3 id="5-enhanced-object-literals-in-es6" style="position:relative;"><a href="#5-enhanced-object-literals-in-es6" aria-label="5 enhanced object literals in es6 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>5. Enhanced Object Literals in ES6</h3> <p>First of all let’s see what is an object literal. An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces (<code class="language-text">{}</code>).</p> <p>What you can do with object literals now in ES6 is mind blowing! It has started from something like a glorified JSON in ES5 to something like a class in ES6.</p> <div class="gatsby-code-button-container" data-toaster-id="60148990017844060000" data-toaster-class="gatsby-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 sales = 'Toyota' function carTypes(name) { if (name === 'Honda') { return name } else { return &quot;Sorry, we don't sell &quot; + name + '.' } } var car = { myCar: 'Saturn', getCar: carTypes('Honda'), special: sales } console.log(car.myCar) // Saturn console.log(car.getCar) // Honda console.log(car.special) // Toyota`, `60148990017844060000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> sales <span class="token operator">=</span> <span class="token string">'Toyota'</span> <span class="token keyword">function</span> <span class="token function">carTypes</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>name <span class="token operator">===</span> <span class="token string">'Honda'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> name <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 string">"Sorry, we don't sell "</span> <span class="token operator">+</span> name <span class="token operator">+</span> <span class="token string">'.'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> car <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">myCar</span><span class="token operator">:</span> <span class="token string">'Saturn'</span><span class="token punctuation">,</span> <span class="token literal-property property">getCar</span><span class="token operator">:</span> <span class="token function">carTypes</span><span class="token punctuation">(</span><span class="token string">'Honda'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">special</span><span class="token operator">:</span> sales <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>car<span class="token punctuation">.</span>myCar<span class="token punctuation">)</span> <span class="token comment">// Saturn</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>car<span class="token punctuation">.</span>getCar<span class="token punctuation">)</span> <span class="token comment">// Honda</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>car<span class="token punctuation">.</span>special<span class="token punctuation">)</span> <span class="token comment">// Toyota</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Additionally, you can use a numeric or string literal for the name of a property or nest an object inside another. The following example uses these options.</p> <div class="gatsby-code-button-container" data-toaster-id="92567401221926630000" data-toaster-class="gatsby-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 car = { manyCars: { a: 'Saab', b: 'Jeep' }, 7: 'Mazda' } console.log(car.manyCars.b) // Jeep console.log(car[7]) // Mazda`, `92567401221926630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> car <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">manyCars</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">a</span><span class="token operator">:</span> <span class="token string">'Saab'</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token string">'Jeep'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token operator">:</span> <span class="token string">'Mazda'</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>car<span class="token punctuation">.</span>manyCars<span class="token punctuation">.</span>b<span class="token punctuation">)</span> <span class="token comment">// Jeep</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>car<span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// Mazda</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>In ES6 Object Literals are extended to support setting the prototype at construction, shorthand for <code class="language-text">foo: foo</code> assignments, defining methods, making super calls, and computing property names with expressions.</p> <div class="gatsby-code-button-container" data-toaster-id="20401898083475410000" data-toaster-class="gatsby-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 obj = { // __proto__ __proto__: theProtoObj, // Shorthand for ‘handler: handler’ handler, // Methods toString() { // Super calls return 'd ' + super.toString() }, // Computed (dynamic) property names ['prop_' + (() => 42)()]: 42, }`, `20401898083475410000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">// __proto__</span> <span class="token literal-property property">__proto__</span><span class="token operator">:</span> theProtoObj<span class="token punctuation">,</span> <span class="token comment">// Shorthand for ‘handler: handler’</span> handler<span class="token punctuation">,</span> <span class="token comment">// Methods</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 comment">// Super calls</span> <span class="token keyword">return</span> <span class="token string">'d '</span> <span class="token operator">+</span> <span class="token keyword">super</span><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">// Computed (dynamic) property names</span> <span class="token punctuation">[</span><span class="token string">'prop_'</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token number">42</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token number">42</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div><![CDATA[Angular dependency injection and possible issues around it]]>https://yashints.dev/blog/2016/07/02/angular-dependecy-injection-and-possible-issues-around-ithttps://yashints.dev/blog/2016/07/02/angular-dependecy-injection-and-possible-issues-around-itSat, 02 Jul 2016 00:00:00 GMT<p>Have you ever wondered why you angular code works perfectly in you dev environment but not in production?</p> <!--more--> <p>Angular leverages dependency injection all across the framework. It works with functions defined for <code class="language-text">controller</code>, <code class="language-text">directive</code>, <code class="language-text">service</code>, <code class="language-text">factory</code>, etc. This can create an issue when minifying JavaScript assets. To illustrate this issue let’s late a look at a test controller:</p> <div class="gatsby-code-button-container" data-toaster-id="97701695264420560000" data-toaster-class="gatsby-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 TestCtrl(\$scope, \$log) { \$scope.\$watch('random-event', function() { \$log.log('hello world') }) } angular.module('test').controller('TestCtrl', TestCtrl)`, `97701695264420560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">TestCtrl</span><span class="token punctuation">(</span><span class="token parameter">$scope<span class="token punctuation">,</span> $log</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> $scope<span class="token punctuation">.</span><span class="token function">$watch</span><span class="token punctuation">(</span><span class="token string">'random-event'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> $log<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello world'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> angular<span class="token punctuation">.</span><span class="token function">module</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 function">controller</span><span class="token punctuation">(</span><span class="token string">'TestCtrl'</span><span class="token punctuation">,</span> TestCtrl<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Here, we’re injecting two services into the controller: <code class="language-text">$scope</code> and <code class="language-text">$log</code>.</p> <p>If we look it the code after minification using any tool (I’ve used uglified here) we should see something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="37524895584050300000" data-toaster-class="gatsby-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 TestCtrl(t, l) { t.\$watch('random-event', function() { l.log('hello world') }) } angular.module('test').controller('TestCtrl', TestCtrl)`, `37524895584050300000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">TestCtrl</span><span class="token punctuation">(</span><span class="token parameter">t<span class="token punctuation">,</span> l</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> t<span class="token punctuation">.</span><span class="token function">$watch</span><span class="token punctuation">(</span><span class="token string">'random-event'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> l<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello world'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> angular<span class="token punctuation">.</span><span class="token function">module</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 function">controller</span><span class="token punctuation">(</span><span class="token string">'TestCtrl'</span><span class="token punctuation">,</span> TestCtrl<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>If you’ve guessed that the parameter names in TestCtrl which have changed to t and l does not mean anything to Angular, you are exactly right. Angular doesn’t have any idea that these are actually supposed to be <code class="language-text">$scope</code> and <code class="language-text">$log</code> respectively and will therefor throw an error.</p> <p>To tackle this problem you have the ability to strictly mention the names and order of your dependencies using array syntax. Because the string won’t get minified there is no chance that Angular miss any dependency if written like this:</p> <div class="gatsby-code-button-container" data-toaster-id="76884131081008250000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`angular.module('test').controller('TestCtrl', [ '\$scope', '\$log', function(\$scope, \$log) { \$scope.\$watch('random-event', function() { \$log.log('hello world') }) }, ])`, `76884131081008250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">angular<span class="token punctuation">.</span><span class="token function">module</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 function">controller</span><span class="token punctuation">(</span><span class="token string">'TestCtrl'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">'$scope'</span><span class="token punctuation">,</span> <span class="token string">'$log'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">$scope<span class="token punctuation">,</span> $log</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> $scope<span class="token punctuation">.</span><span class="token function">$watch</span><span class="token punctuation">(</span><span class="token string">'random-event'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> $log<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello world'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>There is another way that I prefer to use and is a bit cleaner as well which is using <code class="language-text">$indject</code> property. This will keep the core readable and maintainable as you would clearly see the order and name of the of the dependencies within your code file:</p> <div class="gatsby-code-button-container" data-toaster-id="80240159186538270000" data-toaster-class="gatsby-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 TestCtrl(\$scope, \$log) { \$scope.\$watch('random-event', function() { \$log.log('hello world') }) } TestCtrl.\$inject = ['\$scope', '\$log'] angular.module('test').controller('TestCtrl', TestCtrl)`, `80240159186538270000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">TestCtrl</span><span class="token punctuation">(</span><span class="token parameter">$scope<span class="token punctuation">,</span> $log</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> $scope<span class="token punctuation">.</span><span class="token function">$watch</span><span class="token punctuation">(</span><span class="token string">'random-event'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> $log<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello world'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> TestCtrl<span class="token punctuation">.</span>$inject <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'$scope'</span><span class="token punctuation">,</span> <span class="token string">'$log'</span><span class="token punctuation">]</span> angular<span class="token punctuation">.</span><span class="token function">module</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 function">controller</span><span class="token punctuation">(</span><span class="token string">'TestCtrl'</span><span class="token punctuation">,</span> TestCtrl<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>That’s better, isn’t it?</p> <p>Now I will show you how it looks like after minification so you would see the difference:</p> <div class="gatsby-code-button-container" data-toaster-id="54053098142459175000" data-toaster-class="gatsby-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 TestCtrl(t, l) { t.\$watch('random-event', function() { l.log('hello world') }) } TestCtrl.\$inject = ['\$scope', '\$log'] angular.module('test').controller('TestCtrl', TestCtrl)`, `54053098142459175000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">TestCtrl</span><span class="token punctuation">(</span><span class="token parameter">t<span class="token punctuation">,</span> l</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> t<span class="token punctuation">.</span><span class="token function">$watch</span><span class="token punctuation">(</span><span class="token string">'random-event'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> l<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello world'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> TestCtrl<span class="token punctuation">.</span>$inject <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'$scope'</span><span class="token punctuation">,</span> <span class="token string">'$log'</span><span class="token punctuation">]</span> angular<span class="token punctuation">.</span><span class="token function">module</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 function">controller</span><span class="token punctuation">(</span><span class="token string">'TestCtrl'</span><span class="token punctuation">,</span> TestCtrl<span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div><![CDATA[An awesome SQL operator]]>https://yashints.dev/blog/2016/06/21/an-awesome-sql-operatorhttps://yashints.dev/blog/2016/06/21/an-awesome-sql-operatorTue, 21 Jun 2016 00:00:00 GMT<p>I was working on a problem and I was desperate to do a clean job and not create a mess that no one can maintain it, and accidentally I read an article about SQL <code class="language-text">Apply</code> operator.</p> <!--more--> <p>The <code class="language-text">APPLY</code> operator allows you to invoke a table-valued function for each row returned by an outer table expression of a query.</p> <p>The table-valued function acts as the right input and the outer table expression acts as the left input. The advantage over inner join is that it is faster and you can handle conditional joins easily using this trick. A quick reminder on the terms.</p> <blockquote> <p>INNER JOIN is the most used construct in SQL: it joins two tables together, selecting only those row combinations for which a JOIN condition is true.</p> </blockquote> <div class="gatsby-code-button-container" data-toaster-id="77807046797913820000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`SELECT * FROM tblUser JOIN tblProfile ON tblUser.Id = tblProfile.UserId`, `77807046797913820000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="sql"><pre style="counter-reset: linenumber NaN" class="language-sql line-numbers"><code class="language-sql"><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> tblUser <span class="token keyword">JOIN</span> tblProfile <span class="token keyword">ON</span> tblUser<span class="token punctuation">.</span>Id <span class="token operator">=</span> tblProfile<span class="token punctuation">.</span>UserId</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>But for some tasks the sets are not self-sufficient. For instance, let’s consider the following query: We have <code class="language-text">tblUser</code> and <code class="language-text">tblProfile</code>. <code class="language-text">tblProfile</code> has a column called <code class="language-text">rowcount</code>.</p> <p>For each row from <code class="language-text">tblUser</code> we need to select first <code class="language-text">rowcount</code> rows from <code class="language-text">tblProfile</code>, ordered by <code class="language-text">tblProfile.Id</code>.</p> <p>We cannot come up with a join condition here. The join condition, should it exist, would involve the row number, which is not present in <code class="language-text">tblProfile</code>, and there is no way to calculate a row number only from the values of columns of any given row in <code class="language-text">tblProfile</code>.</p> <p>That’s where the <code class="language-text">CROSS APPLY</code> can be used:</p> <div class="gatsby-code-button-container" data-toaster-id="24169132686901264000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`SELECT _ FROM tblUser CROSS APPLY ( SELECT TOP (tblUser.rowcount) FROM tblProfile ORDER BY Id ) t2`, `24169132686901264000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="sql"><pre style="counter-reset: linenumber NaN" class="language-sql line-numbers"><code class="language-sql"><span class="token keyword">SELECT</span> _ <span class="token keyword">FROM</span> tblUser <span class="token keyword">CROSS</span> <span class="token keyword">APPLY</span> <span class="token punctuation">(</span> <span class="token keyword">SELECT</span> <span class="token keyword">TOP</span> <span class="token punctuation">(</span>tblUser<span class="token punctuation">.</span><span class="token keyword">rowcount</span><span class="token punctuation">)</span> <span class="token keyword">FROM</span> tblProfile <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> Id <span class="token punctuation">)</span> t2</code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><strong>Summary:</strong></p> <p>While most queries which employ <code class="language-text">CROSS APPLY</code> can be rewritten using an <code class="language-text">INNER JOIN</code>, <code class="language-text">CROSS APPLY</code> can yield better execution plan and better performance, since it can limit the set being joined yet before the join occurs.</p><![CDATA[Angular or React???]]>https://yashints.dev/blog/2016/06/21/angular-or-reacthttps://yashints.dev/blog/2016/06/21/angular-or-reactTue, 21 Jun 2016 00:00:00 GMT<p>Spoiler alert: we cannot compare these two as they are different in nature, but, I try to go through some points you to need to consider, when choosing a front end technology.</p> <!--more--> <p>When you <strong>deploy</strong> your app you probably want to delay sending unnecessary files to client and increase the page load speed. Well if that’s the case Angular has very little support for that as you can lazy load html templates.</p> <p>Although you can do so for the JS files but you eventually end up with a spaghetti code which is hard to maintain and also takes some time to completely address what you need.</p> <p>In this area React is the winner as it simply is JS and doesn’t care, you can lazy load files with RequireJS and also integrate with frameworks like WebPack.</p> <p>I think <strong>learning</strong> Angular would take more time than React. As some people including  me have experienced you can learn React to a good extent in about a week. With Angular, however, it takes some time to learn the basics and then it gets harder as you go like a marriage.</p> <p>Good <strong>abstraction</strong> is priceless. Abstraction provides fast development and hides details that are not necessary for the developer using a library.</p> <p>Angular is week in keeping people away from its model state as so many developers have had to debug its internal state as they were debugging their code. React’s abstraction has led to it being less flexible like not be able to add attributes to Html tags (which I think is fixed by mixins implementation). However in total React is the winner.</p> <p><strong>Data model complexity</strong> is another factor which means how it is structured to be shown in view later on. Angular is suffering from relying heavily in scope because of the copy-n-compare. React gives you the ability to choose without facing performance hits and the outcome depends on whether you are a good or bad coder.</p> <p>Next thing to consider is <strong>binding</strong>. Angular allows you to bind only to model. This means that you cannot bind to a server/async service. If you want to do that you have to have intermediate models and even then you will suffer from the explicit watches and digest cycle.</p> <p>React on the other hand provides syntactic sugar for binding which is called valueLink. It is a single attribute for both “Value” and “onChange” properties. This is so simple to believe that it is doing what you want but it does and if you understand it well, you can implement any of your needs easily.</p> <p>Then it comes <strong>debugging</strong>. With debugging you want to achieve mostly two things. First why you logic is not working and second why the HTML outcome does not look like what you wanted to be.</p> <p>Angular does a good job of providing constructs that are logical, like services. If used correctly, they make the code easier to test and debug, but any good programmer will try to separate code and logic with or without them.</p> <p>React has two main scenarios - updating the model/doing other actions as a result of user events; and the one-way rendering flow which is always the same. This means that there are fewer places to look for your bugs and the stack traces have clear distinction between React’s code, and your own. They normally don’t mix. React also has less magic, and it’s all concentrated in one place - the vDom comparison. It is a closed black box but in our experience, it worked as expected.</p> <p>Time to discuss <strong>performance tweaking</strong>. In Angular you need to count the number of scopes, global scope variables and functions (which makes scope heavy and sometimes tided to other scopes) and in some cases you have to implement a component in pure js as you can find heaps of articles on Angular perf tuning.</p> <p>On the other hand React makes it easy to take control of performance by letting you choose between customising when the DOM should be updated by yourself or let React take care of it by a simple comparison of the vDOM. Of course if your model if complex you need to do it yourself by implementing a custom ShouldComponentUpdate method to use efficient way of doing state and dirty checks.</p> <p>Next comes my favourite <strong>Code Reuse</strong>. No one can deny the fact that there are thousands of libraries ready to use for Angular. The point here is to not use too many libraries from different vendors due to namespace and priority collisions. React lets you do that by creating reusable components and it is super easy to create complex hierarchical component structures that can be used for future needs. But the winner is Angular as you can almost find anything from a simple date only directive to a complex file upload with background ajax calls to upload your file with nice UI which has progress bar and everything.</p> <p>Templating is another important feature of any front end framework. Angular is a clear winner in this case but not in all aspects and you will see why when I walk you through an example. Imagine that you are writing a repeater which looks like this in React:</p> <div class="gatsby-code-button-container" data-toaster-id="1172650089019700000" data-toaster-class="gatsby-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 createItem = function(itemText) { return <li> {itemText} </li> } return <ul> {this.props.items.map(createItem)} </ul>`, `1172650089019700000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> <span class="token function-variable function">createItem</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">itemText</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>li<span class="token operator">></span> <span class="token punctuation">{</span>itemText<span class="token punctuation">}</span> <span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token operator">&lt;</span>ul<span class="token operator">></span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>createItem<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>In Angular this will be like:</p> <div class="gatsby-code-button-container" data-toaster-id="42882423565812620000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<ul> <li ng-repeat=&quot;item in items&quot;><span ng-bind=&quot;item&quot;></span></li> </ul>`, `42882423565812620000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">ng-repeat</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>item in items<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">ng-bind</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>item<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 punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Which one is better to you?</p> <p>The question here will be how do we get advantage of all of React’s benefits while preserving this great feature of Angular.</p> <p>The answer is by using rt pre-compiled templates. You can find more information on this <a href="http://wix.github.io/react-templates/" target="_blank" rel="nofollow noopener noreferrer">here</a>.</p> <p>Thanks to this awesome feature the code above will become:</p> <div class="gatsby-code-button-container" data-toaster-id="70498750859012250000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<ul> <li rt-repeat=&quot;item in items&quot;>{item} at index {itemIndex}</li> </ul>`, `70498750859012250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">rt-repeat</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>item in items<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{item} at index {itemIndex}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>And this is a true <strong>if expression</strong> which means this will not render if the condition is false:</p> <div class="gatsby-code-button-container" data-toaster-id="74593524974002420000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<label rt-if=&quot;chips.isGoodForHealth&quot;> I don't think so </label>`, `74593524974002420000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">rt-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chips.isGoodForHealth<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> I don't think so <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>It is nice, isn’t it. Now wait for this sugar:</p> <div class="gatsby-code-button-container" data-toaster-id="10190034685673898000" data-toaster-class="gatsby-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 rt-scope=&quot;this.getItems() as items&quot; title=&quot;{item.title}&quot;> Item Description: {item.description}<br /> Last viewed at: <span rt-class=&quot;{status:true, lasSeen:this.lastSeen(item) > '25-11-2015'}&quot; >{item.lastSeen}</span > </div>`, `10190034685673898000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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">rt-scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>this.getItems() as items<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{item.title}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Item Description: {item.description}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/></span></span> Last viewed at: <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">rt-class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{status:true, lasSeen:this.lastSeen(item) > '25-11-2015'}<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span>{item.lastSeen}<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>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Also for <strong>transclusion</strong>:</p> <div class="gatsby-code-button-container" data-toaster-id="1694352957841149700" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<span>{this.props.children}</span>`, `1694352957841149700`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>{this.props.children}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span></span></pre></div> <p>And <strong>handling events</strong>:</p> <div class="gatsby-code-button-container" data-toaster-id="44898503119643320000" data-toaster-class="gatsby-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> <div rt-repeat=&quot;task in tasks&quot; style=&quot;font-weight:{task.selected ? 'bold' : 'normal' }&quot; onClick=&quot;() => this.toggleTask(task)&quot; > {task.title} </div> <button onClick=&quot;{this.save}&quot;>Save</button> </div>`, `44898503119643320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><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">rt-repeat</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>task in tasks<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token selector">font-weight:</span><span class="token punctuation">{</span>task.selected ? <span class="token string">'bold'</span> <span class="token punctuation">:</span> <span class="token string">'normal'</span> <span class="token punctuation">}</span></span><span class="token punctuation">"</span></span></span> <span class="token special-attr"><span class="token attr-name">onClick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">toggleTask</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token punctuation">></span></span> {task.title} <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>button</span> <span class="token special-attr"><span class="token attr-name">onClick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>save<span class="token punctuation">}</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Save<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></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p><strong>Conclusion</strong>: It seems that the question is wrong basically because each framework has something special to offer and is used it a specific scenario. Also you can combine them together (we’ve done that in one project and it is very nice and easy to get done) to use the React’s fast rendering experience along with end-to-end features of Angular. Of course there are a lot of other ways to combine React with other techs to replace Angular but they have their own pros and cons.</p><![CDATA[ng-repeat and groupBy filter]]>https://yashints.dev/blog/2016/06/18/ng-repeat-and-groupby-filterhttps://yashints.dev/blog/2016/06/18/ng-repeat-and-groupby-filterSat, 18 Jun 2016 00:00:00 GMT<p>TL/DR,</p> <p>If you are using angular-filter already don’t read this.</p> <p>Recently I was working on a task for creating a responsive UI which involved changing the html select with a button. Then with a click or tap on the button there should be a list shown like a drop down. Well I though ok let’s do that and quickly started using bootstrap dropdown.</p> <!--more--> <p>Then when it came to showing the list I needed to do a group by and well I did this:</p> <div class="gatsby-code-button-container" data-toaster-id="32426346934400872000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<ul> <li data-ng-repeat=&quot;facility in facilities | groupBy: 'region.name'&quot;></li> </ul>`, `32426346934400872000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">data-ng-repeat</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>facility in facilities | groupBy: 'region.name'<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>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div> <p>Well at that point I wasn’t aware that I needed <code class="language-text">Angular-Filter.js</code> in order to achieve what I wanted, because you can use a group by statement in <code class="language-text">ngOptions</code> in a select:</p> <div class="gatsby-code-button-container" data-toaster-id="6441998007419003000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<select ng-model=&quot;myColor&quot; ng-options=&quot;color.name group by color.shade for color in colors&quot; > </select>`, `6441998007419003000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">ng-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>myColor<span class="token punctuation">"</span></span> <span class="token attr-name">ng-options</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>color.name group by color.shade for color in colors<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>select</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>The problem was that I didn’t want another file added to our current bundle, so I decided to think how to do that without importing that dependency. Well for those who hadn’t face this situation there are a couple of ways to get the desired result: 1- You can create a filter and added to your app. Then use it inside <code class="language-text">ngRepeat</code>. This is what I did as my first attempt:</p> <div class="gatsby-code-button-container" data-toaster-id="31194556348184244000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`angular.module('myApp', []).filter('groupBy', function() { return function(data, key) { if (!(data && key)) return var result = {} for (var i = 0; i < data.length; i++) { if (!result[data[i][key]]) result[data[i][key]] = [] result[data[i][key]].push(data[i]) } return result } })`, `31194556348184244000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">angular<span class="token punctuation">.</span><span class="token function">module</span><span class="token punctuation">(</span><span class="token string">'myApp'</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">filter</span><span class="token punctuation">(</span><span class="token string">'groupBy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span> key</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><span class="token punctuation">(</span>data <span class="token operator">&amp;&amp;</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">var</span> result <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">var</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> data<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span> result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<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> result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> result <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>When I tried it out I got errors on console. The error was infinite loop in the angular digest cycle. The digest cycle is the stage in which Angular ensures the changes of the model have settled, so that it can render the view with the updated changes.</p> <p>In order to do that, Angular starts a loop in which each iteration evaluates all the template expressions of the view, as well as the watcher functions of the <code class="language-text">$scope</code>.</p> <p>If in the current iteration the result is the same as the previous one, then Angular will exit the loop. Otherwise, it will try again. If after 10 attempts things haven’t settled, Angular will exit with an error: The <a href="https://docs.angularjs.org/error/$rootScope/infdig" target="_blank" rel="nofollow noopener noreferrer">Infinite digest loop error</a>.</p> <p>It’s because the <code class="language-text">ngRepeat</code> directive adds a watcher  into its container’s <code class="language-text">$scope</code> for the collection that’s being iterated.</p> <p>This means that in our case, the <code class="language-text">ngRepeat</code> directive is doing this, which is causing the error:</p> <div class="gatsby-code-button-container" data-toaster-id="25837017479871373000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\$scope.\$watchCollection(&quot;students | groupBy: 'class'&quot;, function ngRepeatAction(collection) { ... }`, `25837017479871373000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">$scope<span class="token punctuation">.</span><span class="token function">$watchCollection</span><span class="token punctuation">(</span><span class="token string">"students | groupBy: 'class'"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">ngRepeatAction</span><span class="token punctuation">(</span><span class="token parameter">collection</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span></span></pre></div> <p>Since the <code class="language-text">$filter</code> is returning a new <code class="language-text">Object</code> containing new arrays every time it runs, this causes the digest cycle to get into an infinite loop for the <code class="language-text">$watchCollection</code> function.</p> <p>Well I had to revise my code and had a couple of options again. The first one is a code used by  <a href="https://github.com/a8m" target="_blank" rel="nofollow noopener noreferrer">Ariel Mashraki (a8m)</a> and is a very clever way. The only issue is that it cannot be combined with other filters:</p> <div class="gatsby-code-button-container" data-toaster-id="192154082980389150" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.filter('groupBy', function (\$timeout) { return function (data, key) { if (!key) return data; var outputPropertyName = '__groupBy__' + key; if(!data[outputPropertyName]){ var result = {}; for (var i=0;i&lt;data.length;i++) { if (!result[data[i][key]]) result[data[i][key]]=[]; result[data[i][key]].push(data[i]); } Object.defineProperty(data, outputPropertyName, {enumerable:false, configurable:true, writable: false, value:result}); \$timeout(function(){delete data[outputPropertyName];},0,false); } return data[outputPropertyName]; }; })`, `192154082980389150`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token string">'groupBy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">$timeout</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span> key</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>key<span class="token punctuation">)</span> <span class="token keyword">return</span> data<span class="token punctuation">;</span> <span class="token keyword">var</span> outputPropertyName <span class="token operator">=</span> <span class="token string">'__groupBy__'</span> <span class="token operator">+</span> key<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>data<span class="token punctuation">[</span>outputPropertyName<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token punctuation">{</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">var</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span>i<span class="token operator">&amp;</span>lt<span class="token punctuation">;</span>data<span class="token punctuation">.</span>length<span class="token punctuation">;</span>i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span> result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<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> result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> outputPropertyName<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">enumerable</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">configurable</span><span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">writable</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">value</span><span class="token operator">:</span>result<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">$timeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">delete</span> data<span class="token punctuation">[</span>outputPropertyName<span class="token punctuation">]</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 boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> data<span class="token punctuation">[</span>outputPropertyName<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Well it is simply creating a non-enumerable property in the original <code class="language-text">Array</code> that is being filtered with the result of the ‘groupBy’.</p> <p>This way, when the digest cycle triggers the <code class="language-text">$filter</code>, the <code class="language-text">$filter</code> will first check if the property has already been set. If it hasn’t, it will do the <code class="language-text">groupBy</code> and will save the result in the non-enumerable property.</p> <p>If the property has already been set, it will return the cached value. Also, notice that there is a <code class="language-text">$timeout</code> that deletes that property after the digest cycle has finished.</p> <p>The second one is the one used by  <a href="https://github.com/m59peacemaker" target="_blank" rel="nofollow noopener noreferrer">Johnny Hauser (m59peacemaker)</a> which is cleaner and you can use it with other filters as well:</p> <div class="gatsby-code-button-container" data-toaster-id="86664064206236580000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`angular.module(&quot;pmkr.filters&quot;, []) .filter('groupBy', ['pmkr.filterStabilize', function(stabilize) { return stabilize(function(data, key) { if (!(data & amp; & amp; key)) return; var result = {}; for (var i = 0; i & lt; data.length; i++) { if (!result[data[i][key]]) result[data[i][key]] = []; result[data[i][key]].push(data[i]) } return result; }); }]) .factory('pmkr.filterStabilize', [ 'pmkr.memoize', function(memoize) { function service(fn) { function filter() { var args = [].slice.call(arguments); // always pass a copy of the args so that the // original input can't be modified args = angular.copy(args); // return the \`fn\` return value or input // reference (makes \`fn\` return optional) var filtered = fn.apply(this, args) || args[0]; return filtered; } var memoized = memoize(filter); return memoized; } return service; } ]) .factory('pmkr.memoize', [ function() { function service() { return memoizeFactory.apply(this, arguments); } function memoizeFactory(fn) { var cache = {}; function memoized() { var args = [].slice.call(arguments); var key = JSON.stringify(args); var fromCache = cache[key]; if (fromCache) { return fromCache; } cache[key] = fn.apply(this, arguments); return cache[key]; } return memoized; } return service; } ]);`, `86664064206236580000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript">angular<span class="token punctuation">.</span><span class="token function">module</span><span class="token punctuation">(</span><span class="token string">"pmkr.filters"</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">filter</span><span class="token punctuation">(</span><span class="token string">'groupBy'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'pmkr.filterStabilize'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">stabilize</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">stabilize</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span> key</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><span class="token punctuation">(</span>data <span class="token operator">&amp;</span> amp<span class="token punctuation">;</span> <span class="token operator">&amp;</span> amp<span class="token punctuation">;</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token punctuation">{</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">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&amp;</span> lt<span class="token punctuation">;</span> data<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span> result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<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> result<span class="token punctuation">[</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> result<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">factory</span><span class="token punctuation">(</span><span class="token string">'pmkr.filterStabilize'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">'pmkr.memoize'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">memoize</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">service</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> args <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>arguments<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// always pass a copy of the args so that the</span> <span class="token comment">// original input can't be modified</span> args <span class="token operator">=</span> angular<span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// return the `fn` return value or input</span> <span class="token comment">// reference (makes `fn` return optional)</span> <span class="token keyword">var</span> filtered <span class="token operator">=</span> <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span> <span class="token operator">||</span> args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">return</span> filtered<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> memoized <span class="token operator">=</span> <span class="token function">memoize</span><span class="token punctuation">(</span>filter<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> memoized<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> service<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">factory</span><span class="token punctuation">(</span><span class="token string">'pmkr.memoize'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">service</span><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">memoizeFactory</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<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">memoizeFactory</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> cache <span class="token operator">=</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">memoized</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> args <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>arguments<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> key <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> fromCache <span class="token operator">=</span> cache<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>fromCache<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> fromCache<span class="token punctuation">;</span> <span class="token punctuation">}</span> cache<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> cache<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> memoized<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> service<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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <p>Just be careful that if you are doing it for large arrays you may face some performance issues with this solution.</p> <p>2- Group by your list in your controller and use two <code class="language-text">ng-repeat</code> to simulate the original list. This one very simple and I don’t get deep into it. You can easily use a library like underscore and use its group by like this:</p> <div class="gatsby-code-button-container" data-toaster-id="65968661999898720000" data-toaster-class="gatsby-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 list = _(facilities).groupBy(function(o) { return o.region.name })`, `65968661999898720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token keyword">var</span> list <span class="token operator">=</span> <span class="token function">_</span><span class="token punctuation">(</span>facilities<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">groupBy</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">o</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> o<span class="token punctuation">.</span>region<span class="token punctuation">.</span>name <span class="token punctuation">}</span><span class="token punctuation">)</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span></span></pre></div><![CDATA[How to show or hide content without any JS library or code]]>https://yashints.dev/blog/2016/06/18/how-to-show-or-hide-content-without-any-js-library-or-codehttps://yashints.dev/blog/2016/06/18/how-to-show-or-hide-content-without-any-js-library-or-codeSat, 18 Jun 2016 00:00:00 GMT<p>Mentioning this is trivial as no one seems to notice this while using default JQuery show and hide methods to show or hide an element on a page. As you might have noticed this before when you use <code class="language-text">hide()</code>, the element gets a  <code class="language-text">display:none;</code> style. The problem is when you use <code class="language-text">show()</code> to show the element again and here is when you see<code class="language-text">display:block;</code> is added to element styles.</p> <!--more--> <p>The problem compounds when animations get added into the mix (tons of inline CSS). I’m not saying don’t use them, but there are better ways and you can clean up after yourself in the DOM. Here’s an example for a simple hide/show.</p> <h2 id="html" style="position:relative;"><a href="#html" aria-label="html permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>HTML</h2> <div class="gatsby-code-button-container" data-toaster-id="24201282903426670000" data-toaster-class="gatsby-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;#target1&quot; class=&quot;trigger&quot;>Toggle Content area 1</a> <div id=&quot;target1&quot; class=&quot;content&quot;>the content you want to hide/show</div>`, `24201282903426670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-html line-numbers"><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>#target1<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>trigger<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Toggle Content area 1<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">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>target1<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>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>the content you want to hide/show<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span></span></pre></div> <h2 id="css" style="position:relative;"><a href="#css" aria-label="css permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CSS</h2> <div class="gatsby-code-button-container" data-toaster-id="7264621049311714000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// with this method I get to choose how I want to hide the content .is-hidden { position: absolute; top: -9999px; left: -9999px; } // and I can easily make it work w/o JS .content:target { position: static; }`, `7264621049311714000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-css line-numbers"><code class="language-css"><span class="token selector">// with this method I get to choose how I want to hide the content .is-hidden</span> <span class="token punctuation">{</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">top</span><span class="token punctuation">:</span> -9999px<span class="token punctuation">;</span> <span class="token property">left</span><span class="token punctuation">:</span> -9999px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">// and I can easily make it work w/o JS .content:target</span> <span class="token punctuation">{</span> <span class="token property">position</span><span class="token punctuation">:</span> static<span class="token punctuation">;</span> <span class="token punctuation">}</span></code><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="javascript" style="position:relative;"><a href="#javascript" aria-label="javascript permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>JavaScript</h2> <div class="gatsby-code-button-container" data-toaster-id="45242146995871924000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`\$('.trigger').on('click', function(e) { e.preventDefault(); var target = \$(this).attr('href'); // returns #target1 // see if the target area is hidden if( \$(target).hasClass('is-hidden') ) { // if it's hidden, remove the class, but hide it so we can softly fade it in \$(target).removeClass('is-hidden').hide().fadeIn(250, function(){ // because fadeIn() adds some inline CSS, let's remove it to clean up the DOM \$(target).removeAttr('style'); }); } else { // fade out the content \$(target)fadeOut(250, function(){ // once it's faded out, add the class and clean up the DOM \$(this).addClass('is-hidden').removeAttr('style'); }); } });`, `45242146995871924000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" 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 style="counter-reset: linenumber NaN" class="language-javascript line-numbers"><code class="language-javascript"><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'.trigger'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> target <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">attr</span><span class="token punctuation">(</span><span class="token string">'href'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// returns #target1</span> <span class="token comment">// see if the target area is hidden</span> <span class="token keyword">if</span><span class="token punctuation">(</span> <span class="token function">$</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">hasClass</span><span class="token punctuation">(</span><span class="token string">'is-hidden'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// if it's hidden, remove the class, but hide it so we can softly fade it in</span> <span class="token function">$</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">removeClass</span><span class="token punctuation">(</span><span class="token string">'is-hidden'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">hide</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fadeIn</span><span class="token punctuation">(</span><span class="token number">250</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// because fadeIn() adds some inline CSS, let's remove it to clean up the DOM</span> <span class="token function">$</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">removeAttr</span><span class="token punctuation">(</span><span class="token string">'style'</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> <span class="token comment">// fade out the content</span> <span class="token function">$</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token function">fadeOut</span><span class="token punctuation">(</span><span class="token number">250</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// once it's faded out, add the class and clean up the DOM</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addClass</span><span class="token punctuation">(</span><span class="token string">'is-hidden'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">removeAttr</span><span class="token punctuation">(</span><span class="token string">'style'</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><span aria-hidden="true" class="line-numbers-rows" style="white-space: normal; width: auto; left: 0;"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div> <h2 id="why-should-you-be-concerned" style="position:relative;"><a href="#why-should-you-be-concerned" aria-label="why should you be concerned permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 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 should you be concerned?</h2> <p>I’ve been using this method for a very long time. I prefer it because it’s a cleaner separation between CSS and JavaScript and I’m not forced to use jQuery’s hide/show method of <code class="language-text">display:none</code> (which really isn’t good for accessibility).</p> <p>Of course, the <code class="language-text">fadeIn()</code> method could also be moved into a CSS animation at this point to clean this up even further.</p>