<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Azure Static Web Apps Blog</title>
        <link>https://www.azurestaticwebapps.dev/blog</link>
        <description>Azure Static Web Apps Blog</description>
        <lastBuildDate>Sat, 30 Apr 2022 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[It's the SWA-anniversary!!]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/swanniversary</link>
            <guid>https://www.azurestaticwebapps.dev/blog/swanniversary</guid>
            <pubDate>Sat, 30 Apr 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[View the latest Schedule & Speaker Lineup at https://aka.ms/swaanniversary]]></description>
            <content:encoded><![CDATA[<p><img loading="lazy" src="/assets/images/swanniversary-d632d17c49b5e3631d39ad0c230f2ad8.png" width="1920" height="1080" class="img_ev3q"></p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>SWA ANNIVERSARY SCHEDULE &amp; SPEAKERS</div><div class="admonitionContent_S0QG"><p>View the latest Schedule &amp; Speaker Lineup at <a href="https://aka.ms/swaanniversary" target="_blank" rel="noopener noreferrer">https://aka.ms/swaanniversary</a></p></div></div><hr><p>On May 12, 2021, the <a href="https://docs.microsoft.com/azure/static-web-apps/overview?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">Azure Static Web Apps</a> service hit a significant milestone - <a href="https://azure.microsoft.com/en-us/updates/azure-static-web-apps-is-now-generally-available/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">becoming generally available</a> with support for many of the popular <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/front-end-frameworks" target="_blank" rel="noopener noreferrer">front-end frameworks and static site generators</a> used for modern web app development.</p><p>On May 12, 2022, Azure Static Web Apps will make the first-year anniversary of that milestone - making this the perfect time to look back on all the progress made, and look ahead to what's in store next.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="celebrate-with-swaanniversary">Celebrate with #SWAanniversary<a href="#celebrate-with-swaanniversary" class="hash-link" aria-label="Direct link to Celebrate with #SWAanniversary" title="Direct link to Celebrate with #SWAanniversary">​</a></h2><p>On May 19, 2022, join us live on <a href="https://docs.microsoft.com/en-us/learn/tv/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">Learn TV</a> for a 2-hour celebration with some of our favorite speakers and guests from both Microsoft and the larger developer community. Can you tell we're excited for this birthday?</p><iframe width="560" height="315" src="https://www.youtube.com/embed/OGlM5CgCwwc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe><p>Check out <a href="https://docs.microsoft.com/en-us/events/learntv/swa-anniversary-may-2022/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">the Event page</a> to learn more about the speakers and topics on the agenda. Add the event to your calendar, and join us live - or bookmark this page and revisit it for links to relevant resources and video replays.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="learn-with-30daysofswa">Learn with #30DaysOfSWA<a href="#learn-with-30daysofswa" class="hash-link" aria-label="Direct link to Learn with #30DaysOfSWA" title="Direct link to Learn with #30DaysOfSWA">​</a></h2><p>But there's more! <em>Are you new to Azure Static Web Apps?</em> Do you want to get a beginner-friendly tour of the core concepts, usage examples, developer tools, and best practices involved in building and deploy modern web applications with this service?</p><p><strong>You're in luck!</strong></p><p>Watch this space for an update on a new content series that will help you jumpstart that learning journey! Throughout the month of May, we'll bring together a diverse group of technologists to share short articles with resources and insights on a curated tour of Static Web Apps - taking you from <strong>code to scale</strong>.</p><p><img loading="lazy" alt="The #30DaysOfSWA logo" src="/assets/images/logo-light-c06a2cb26903f93ddf79056b71d047e9.png" width="724" height="662" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-can-you-participate">How Can You Participate?<a href="#how-can-you-participate" class="hash-link" aria-label="Direct link to How Can You Participate?" title="Direct link to How Can You Participate?">​</a></h2><p>Some actions you can take today to get ready for a fun month of learning:</p><ul><li>Bookmark this Series page or <a href="https://aka.ms/30DaysOfSWA/rss" target="_blank" rel="noopener noreferrer"><strong>Subscribe to the RSS feed</strong></a></li><li>Follow the <a href="https://dev.to/t/staticwebapps" target="_blank" rel="noopener noreferrer"><strong>#staticwebapps tag on dev.to</strong></a> - and consider making a post there!</li><li>Introduce yourself on <a href="https://github.com/orgs/staticwebdev/discussions/categories/-30daysofswa" target="_blank" rel="noopener noreferrer"><strong>our Discussions Forum</strong></a> - tell us what you hope to learn!</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="self-study-resources">Self-Study Resources<a href="#self-study-resources" class="hash-link" aria-label="Direct link to Self-Study Resources" title="Direct link to Self-Study Resources">​</a></h2><p>Our goal is to help make this a beginner-friendly learning journey into Azure Static Web Apps. We hope we inspire you to keep going beyond #30Days - and wanted to share resources to motivate you to keep going. Here are three links to bookmark:</p><ul><li>The <a href="/resources"><strong>Resources</strong></a> page - will be updated with links related to each article in the series, all through May! Use this to explore detours and deep dives.</li><li>The <a href="https://docs.microsoft.com/en-us/learn/paths/azure-static-web-apps/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer"><strong>Microsoft Learn Path</strong></a> - teaches you how to build your first Static Web Apps powered experience - with React, Angular, Vue and Blazor coding options.</li><li>The <a href="https://docs.microsoft.com/en-us/users/nityan/collections/7d2ws6zd1mxmp6?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer"><strong>#30DaysOfSWA Collection</strong></a> - a Microsoft-specific collection of resources (from documentation to videos and code samples) that I will continue to update.</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>event</category>
        </item>
        <item>
            <title><![CDATA[Kickoff #30DaysOfSWA!]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/kickoff</link>
            <guid>https://www.azurestaticwebapps.dev/blog/kickoff</guid>
            <pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to the first day of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to the first day of <strong>#30DaysOfSWA</strong>!!</p><p>Thank you for joining us on this fun and functional tour of <strong>Azure Static Web Apps</strong>. Whether you're new to the technology, or an experienced user, we hope there's something that interests and motivates you to keep going.</p><p><img loading="lazy" src="/assets/images/banner-kickoff-5bd74f140c45f930a6b0629389496a1b.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="hello-30daysofswa">Hello #30DaysOfSWA<a href="#hello-30daysofswa" class="hash-link" aria-label="Direct link to Hello #30DaysOfSWA" title="Direct link to Hello #30DaysOfSWA">​</a></h2><p>Simply put, it's a month-long series of blog posts that provides you a curated and structured tour through the universe of  <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">Azure Static Web Apps</a>. </p><ul><li>Each article will be 5 mins or less in reading time</li><li>Each ends with an activity to help reinforce the learning</li><li>Articles will follow a structured roadmap over 4 weeks</li></ul><p>We've organized the journey into four stages, each building on the previous one in a way that mimics the developer experience with any new technology:</p><ul><li><strong>Week 1:</strong> Focus on Core Concepts, learning terminology and getting setup.</li><li><strong>Week 2:</strong> Focus on Usage Examples with quickstarts &amp; front-end technologies.</li><li><strong>Week 3:</strong> Focus on Dev Tools to develop, debug, test, and deploy, the SWA!</li><li><strong>Week 4:</strong> Focus on Best Practices, from services to end-to-end experiences.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="week-1-roadmap">Week 1 Roadmap<a href="#week-1-roadmap" class="hash-link" aria-label="Direct link to Week 1 Roadmap" title="Direct link to Week 1 Roadmap">​</a></h2><p>We are kicking off week 1 with a focus on <strong>Core Concepts</strong> to get you familiar with the high-level architecture, fundamental components and basic terminology for Azure Static Web Apps. Want a sneak peek at the topics? Here's a visual guide to help you!</p><p><img loading="lazy" alt="Visual sketchnote of roadmap" src="/assets/images/week1-roadmap-7f10986393cc2e96edea4819c3bf9d72.png" width="1000" height="563" class="img_ev3q"></p><p><strong>By the end of week 1 you should know</strong>:</p><ul><li>What Azure Static Web Apps is, and its benefits</li><li>How to get started building SWA or using it for your existing apps</li><li>How to go serverless, adding API capability with Azure Functions</li><li>How to configure SWA - from app behavior to build process</li><li>How to secure SWA - from user authentication to role-based authorization</li><li>How to preview SWA - on pull requests or test branches</li><li>How to deploy SWA - using different code sources, or CI/CD options</li></ul><p>By the end of the week you should be familiar with SWA terminology and developer workflows - and be ready to explore usage scenarios with various front-end frameworks or static site generators!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="take-the-journey">Take The Journey<a href="#take-the-journey" class="hash-link" aria-label="Direct link to Take The Journey" title="Direct link to Take The Journey">​</a></h2><p>They say it takes 30 days to make a habit. It's our hope that doing short bursts of reading and activity with Azure Static Web Apps on a daily basis, will lead to better learning and development habits in general.</p><p>We want to make it easy for you to participate - here are options to follow along:</p><ul><li>Bookmark <a href="https://aka.ms/30DaysofSWA" target="_blank" rel="noopener noreferrer">this site</a> and visit daily</li><li>Subscribe to the <a href="https://aka.ms/30DaysOfSWA/rss" target="_blank" rel="noopener noreferrer">RSS Feed</a> in your favorite Feed Reader</li><li>Visit the <a href="https://dev.to/nitya/series/17901" target="_blank" rel="noopener noreferrer">dev.to Series Page</a> and like, comment on, or bookmark, the posts.</li></ul><p>Want to really get the most from this? Try the exercises each day, and take a moment on a weekly basis, to write a blog post or capture your own notes on what your main takeaways were. As a fan of <a href="https://twitter.com/sketchthedocs" target="_blank" rel="noopener noreferrer">visual storytelling</a> I know that writing things down helps improve your understanding and recall of the material!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="provide-us-feedback">Provide Us Feedback<a href="#provide-us-feedback" class="hash-link" aria-label="Direct link to Provide Us Feedback" title="Direct link to Provide Us Feedback">​</a></h2><p><strong>We want to make this useful and beginner-friendly!</strong> So if you have comments or questions that can help us improve this content, please drop us a note in our <a href="https://github.com/orgs/staticwebdev/discussions/categories/-30daysofswa" target="_blank" rel="noopener noreferrer">Discussions</a> board!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="meet-the-authors">Meet The Authors<a href="#meet-the-authors" class="hash-link" aria-label="Direct link to Meet The Authors" title="Direct link to Meet The Authors">​</a></h2><p>Articles are written by a multi-disciplinary team of contributors from across Microsoft and the community - including members of the Static Web Apps product group and Microsoft Developer Relations. </p><p><img loading="lazy" alt="Banner with people" src="/assets/images/series-people-13a2856edd7022e82a252ed05dffbabc.png" width="1000" height="420" class="img_ev3q"></p><p>We'll keep this page updated on a daily basis, to reflect the latest author whose post was published. We'll kick things off with the authors of this post.</p><ul><li><strong>Nitya Narasimhan</strong>, Senior Cloud Advocate @Microsoft</li><li><strong>Reshmi Sriram</strong>, Static Web Apps PM @Microsoft</li><li><strong>Simona Cotin</strong>, Principal PM @Microsoft </li><li><strong>Glaucia Lemos</strong>, JS Cloud Advocate @Microsoft</li><li><strong>Anthony Chu</strong>, Senior Product PM @Microsoft</li><li><strong>Joseph Lin</strong> Software Engineer @Microsoft, </li><li><strong>Mitali Karmarkar</strong>, Software Engineer @Microsoft</li><li><strong>Michail Shaposhnikov</strong>, Software Engineer @Microsoft</li><li><strong>Chris Noring</strong>, Senior Cloud Advocate @Microsoft</li><li><strong>Jen Looper</strong>, Principal Cloud Advocate @Microsoft</li><li><em>to be updated daily ...</em></li></ul><p>Each post will identify the authors by name, and link to a relevant online profile. This series is a labor of love, so if you like a post - show that author some love by providing feedback or saying hello on their identified profile!</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="lets-get-started">Let's Get Started!<a href="#lets-get-started" class="hash-link" aria-label="Direct link to Let's Get Started!" title="Direct link to Let's Get Started!">​</a></h2><p>I think that's all you need to know for now! Hope your're as excited as we are. Check back for the next post and ... <strong>#LetsDoThis</strong> !!</p><p><img loading="lazy" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDE4IDE4Ij4NCiAgPGRlZnM+DQogICAgPGxpbmVhckdyYWRpZW50IGlkPSJlNmFkNGRmOS0wYWI3LTRiNDktOTcwNi02MjBiNDIzODBmMGIiIHgxPSI5IiB5MT0iMTYuMjM2IiB4Mj0iOSIgeTI9IjUuNTk5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+DQogICAgICA8c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiMwMDViYTEiIC8+DQogICAgICA8c3RvcCBvZmZzZXQ9IjAuNzc1IiBzdG9wLWNvbG9yPSIjMDA3OGQ0IiAvPg0KICAgIDwvbGluZWFyR3JhZGllbnQ+DQogIDwvZGVmcz4NCiAgPGcgaWQ9ImU3ODg1YjljLTk3MTQtNDI3Ni1iZDQxLTU5MWNiN2UwODZhNSI+DQogICAgPHBhdGggZD0iTTAsNS42SDE4YTAsMCwwLDAsMSwwLDBWMTUuNjM1YS42LjYsMCwwLDEtLjYuNkguNmEuNi42LDAsMCwxLS42LS42VjUuNkEwLDAsMCwwLDEsMCw1LjZaIiBmaWxsPSJ1cmwoI2U2YWQ0ZGY5LTBhYjctNGI0OS05NzA2LTYyMGI0MjM4MGYwYikiIC8+DQogICAgPHJlY3QgeD0iMS4zMDkiIHk9IjYuNjU3IiB3aWR0aD0iMTUuNTI3IiBoZWlnaHQ9IjguNTE0IiByeD0iMC42IiBmaWxsPSIjNWVhMGVmIiBvcGFjaXR5PSIwLjYiIC8+DQogICAgPHBhdGggZD0iTS42LDEuNzY0SDE3LjRhLjYuNiwwLDAsMSwuNi42VjUuNmEwLDAsMCwwLDEsMCwwSDBhMCwwLDAsMCwxLDAsMFYyLjM2NUEuNi42LDAsMCwxLC42LDEuNzY0WiIgZmlsbD0iIzAwNWJhMSIgLz4NCiAgICA8cGF0aCBkPSJNNy4xMDksMTMuMjE3bC0uMzIxLjMyYS4xNDQuMTQ0LDAsMCwxLS4yMDUsMEw0LjI1OCwxMS4yMDVhLjI5LjI5LDAsMCwxLDAtLjQxbC4zMjEtLjMyTDcuMTEsMTMuMDEyQS4xNDUuMTQ1LDAsMCwxLDcuMTA5LDEzLjIxN1ptMy42NTMsMCwuMzIxLjMyYS4xNDQuMTQ0LDAsMCwwLC4yMDUsMGwyLjMyNS0yLjMzMmEuMjkuMjksMCwwLDAsMC0uNDFsLS4zMjItLjMyLTIuNTMsMi41MzdBLjE0NS4xNDUsMCwwLDAsMTAuNzYyLDEzLjIxN1oiIGZpbGw9IiNmZmYiIG9wYWNpdHk9IjAuOCIgLz4NCiAgICA8cGF0aCBkPSJNNi44MzEsOC40MzNsLjMyLjMyMWEuMTQ0LjE0NCwwLDAsMSwwLC4yMDVMNC41NzYsMTEuNTI3bC0uMzItLjMyMmEuMjg5LjI4OSwwLDAsMSwwLS40MWwyLjM3LTIuMzYzQS4xNDUuMTQ1LDAsMCwxLDYuODMxLDguNDMzWm00LjIwNywwLS4zMi4zMjFhLjE0NC4xNDQsMCwwLDAsMCwuMjA1bDIuNTc1LDIuNTY4LjMyLS4zMjFhLjI5Mi4yOTIsMCwwLDAsMC0uNDExbC0yLjM3LTIuMzYyQS4xNDQuMTQ0LDAsMCwwLDExLjAzOCw4LjQzNFoiIGZpbGw9IiNmZmYiIC8+DQogICAgPHBhdGggZD0iTTguMTU5LDE0LjM2Myw3LjY0NiwxNC4yYS4xMDUuMTA1LDAsMCwxLS4wNjctLjEzMUw5LjY2OSw3LjU0YS4xLjEsMCwwLDEsLjEzLS4wNjdsLjUxMy4xNjRhLjEuMSwwLDAsMSwuMDY3LjEzTDguMjg5LDE0LjNBLjEuMSwwLDAsMSw4LjE1OSwxNC4zNjNaIiBmaWxsPSIjZmZmIiAvPg0KICAgIDxwYXRoIGQ9Ik0zLjE2NiwzLjg0N2EuNzYuNzYsMCwxLDEtLjc2LS43NkEuNzYuNzYsMCwwLDEsMy4xNjYsMy44NDdaTTQuOCwzLjA4N2EuNzYuNzYsMCwxLDAsLjc2Ljc2QS43Ni43NiwwLDAsMCw0LjgsMy4wODdabTIuMzkzLDBhLjc2Ljc2LDAsMSwwLC43Ni43NkEuNzYuNzYsMCwwLDAsNy4xOTEsMy4wODdaIiBmaWxsPSIjZmZmIiAvPg0KICA8L2c+DQo8L3N2Zz4=" width="18" height="18" class="img_ev3q"></p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
        </item>
        <item>
            <title><![CDATA[#01: Introducing SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/introducing-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/introducing-swa</guid>
            <pubDate>Mon, 02 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 1, Day 1 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 1, Day 1</code> of <strong>#30DaysOfSWA</strong>!! </p><p>This week, we'll focus on the <strong>Core Concepts</strong> behind Azure Static Web Apps, starting with an introduction to SWA and continuing on to building, enhancing, and deploying, your SWA for users to experience. Let's get started today by <em>Introducing Static Web Apps</em>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What is Azure Static Web Apps?</li><li>How is it architected?</li><li>Where can I use it?</li><li>10 Key Features to know</li><li><strong>Exercise:</strong> Explore SWA Examples!</li><li><strong>Resource:</strong> <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview" target="_blank" rel="noopener noreferrer">Static Web Apps Overview</a></li></ul><p><img loading="lazy" src="/assets/images/01-banner-be8d7d0f3d456b78fd3930cbaab95247.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-azure-swa">What is Azure SWA?<a href="#what-is-azure-swa" class="hash-link" aria-label="Direct link to What is Azure SWA?" title="Direct link to What is Azure SWA?">​</a></h2><p><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview" target="_blank" rel="noopener noreferrer">Azure Static Web Apps</a> is a cloud-based service that <strong>automatically</strong> builds and deploys full-stack web apps to Azure <strong>directly from your code repository</strong>. The service works with popular code sources like GitHub, GitLab and BitBucket by default. Look for the <em>Deploying SWA</em> post later this week where we walk through the details here.</p><p>The benefit to you as a developer is that it <strong>simplifies your developer experience</strong>. Just commit changes to your application source code into the repository and step back. The SWA service monitors the codebase for changes, automatically rebuilding and redeploying your app to the hosted endpoint. Look for a <em>Previewing SWA</em> post later this week where we'll talk about built-in support for previewing apps in non-main branches, or in pull requests, that make it easier to manage apps with multiple contributors.</p><p>Prefer a 5-minute video overview? We have you covered!</p><iframe width="560" height="315" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=what-is-azure-static-web-apps-and-what-can-it-be-used-for-1-of-16--azure-tips-and-tricks-static-web-" frameborder="0"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-is-it-architected">How is it Architected?<a href="#how-is-it-architected" class="hash-link" aria-label="Direct link to How is it Architected?" title="Direct link to How is it Architected?">​</a></h2><p>Static Web Apps can be built using popular front-end frameworks including React, Angular, Vue, Svelte, or Blazor. These apps typically consist of a collection of <strong>static content assets</strong> (HTML, JS, CSS and media files) coupled with a <strong>dynamic API endpoint</strong> to handle client interactions in real time.</p><p>Traditional web application deployments use a <em>single web server</em> to serve both the static assets and the API endpoint. This can make scaling these services sub-optimal in terms of global availability and runtime costs.</p><p>With Static Web Apps, we <strong>separate static assets from API endpoints</strong>, allowing each to be scaled using the technology best equipped to do this in a cost-effective manner.</p><ul><li>Static assets get served from geographically-distributed content servers worldwide, distributing the load and speeding up access to users nearby.</li><li>API endpoints are hosted using a <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview" target="_blank" rel="noopener noreferrer">serverless architecture</a>, spinning up compute resources (to execute functions) only as needed, in response to trigger events.</li></ul><p>This architecture - with static content servers, serverless backends, and automated CI/CD workflows - simplifies your development workflow <strong>allowing you to focus your attention on the application logic and user experience</strong> components of your modern web application.</p><p><img loading="lazy" src="/assets/images/01-swa-overview-41d0e428dab8a7da10950b590d54c886.png" width="596" height="441" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="where-can-i-use-it">Where can I use it?<a href="#where-can-i-use-it" class="hash-link" aria-label="Direct link to Where can I use it?" title="Direct link to Where can I use it?">​</a></h2><p>That's a great question!! You can use Static Web Apps to:</p><ul><li>Build modern web apps with front-end frameworks (like Angular, React, Vue etc.)</li><li>Publish static web sites (using Gatsby, Hugo, Astro, Docusaurus, VuePress etc.)</li><li>Deploy web apps with frameworks like Next.js and Nuxt.js.</li></ul><p>You can <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/front-end-frameworks" target="_blank" rel="noopener noreferrer"><strong>configure your existing application</strong></a> to use Azure Static Web Apps using an IDE like VS Code, or using Command-line tools (like Azure CLI and SWA CLI), or through the browser (using the Azure Portal). Look for two posts later this week that dive into this in detail:</p><ul><li><em>Building SWA</em> (tomorrow) on getting started with using SWA in your app.</li><li><em>Configuring SWA</em> (later) on customizing app behaviors and build process.</li></ul><p>But wait - there's one more thing. </p><p><strong>Keep an eye out for an announcement later in the series</strong> where we'll be debuting a new <a href="/showcase">Community Showcase</a> page - here's a sneak preview. You can filter it to see examples from popular front-end technologies, select "open source" to see the repository for inspiration - <strong>and consider adding your own project</strong> at the end of your journey!</p><p><img loading="lazy" src="/assets/images/swa-showcase-5214e0f3f6ea04a71fc5e8c82a94545a.png" width="936" height="826" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="10-things-to-know">10 Things To Know!<a href="#10-things-to-know" class="hash-link" aria-label="Direct link to 10 Things To Know!" title="Direct link to 10 Things To Know!">​</a></h2><p>We've talked about what SWA is, how it's architected, and where you can use it. But what are the key features that make it powerful? <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview#key-features" target="_blank" rel="noopener noreferrer"><strong>Read the Documentation</strong></a> for the detailed list - or scan the visual guide below for a summary!</p><p><img loading="lazy" src="/assets/images/01-ten-things-f6eee9ff7c4e6fe0e5c36ee242cdb594.png" width="3840" height="2160" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise:<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise:" title="Direct link to Exercise:">​</a></h2><p>That was a lot to digest right?  It helps to see some of these ideas in action. So here's two things you can do before we dive into the quickstart tomorrow:</p><ul><li>Visit the <a href="https://github.com/microsoft/static-web-apps-gallery-code-samples" target="_blank" rel="noopener noreferrer">Showcase Gallery</a> repository to see some examples of SWA in Action.</li><li>Follow the <a href="https://dev.to/t/staticwebapps" target="_blank" rel="noopener noreferrer">#staticwebapps</a> tag to see community-posted articles on usage.</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>core-concepts</category>
        </item>
        <item>
            <title><![CDATA[#02: Building SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/building-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/building-swa</guid>
            <pubDate>Tue, 03 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 1, Day 2 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 1, Day 2</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Yesterday we got a quick introduction to Azure Static Web Apps (what it is, how it's architected, and 10 features that make it useful to modern web developers). Today, it's time to dive to dive into <em>Building Static Web Apps</em>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>How can I get started with SWA?</li><li>Using SWA with personal and production projects.</li><li>Building &amp; Deploying your first SWA</li><li><strong>Tutorial</strong> Let's Build a Classic Movie Crawler!</li><li><strong>Exercise</strong> Your turn! And <code>#MayThe4thBeWithYou</code></li><li><strong>Resources:</strong> <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Static Web Apps Quickstarts</a></li></ul><p><img loading="lazy" src="/assets/images/02-banner-5a795a52ea06e154625132bc426ca7d6.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-getting-started">1. Getting Started<a href="#1-getting-started" class="hash-link" aria-label="Direct link to 1. Getting Started" title="Direct link to 1. Getting Started">​</a></h2><p>The Azure Static Web Apps service makes it easy to publish your modern web application directly from its codebase. Let's walk through that process for a basic web application (HTML, CSS, JS) first, to understand the development workflow and configuration options.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="11-requirements">1.1 Requirements<a href="#11-requirements" class="hash-link" aria-label="Direct link to 1.1 Requirements" title="Direct link to 1.1 Requirements">​</a></h3><p>To do this quickstart, you'll need </p><ul><li>a <a href="https://github.com/" target="_blank" rel="noopener noreferrer">GitHub account</a> - you can <a href="https://github.com/signup" target="_blank" rel="noopener noreferrer">signup</a> for a free one if needed.</li><li>an <a href="https://portal.azure.com" target="_blank" rel="noopener noreferrer">Azure account</a> - you can <a href="https://azure.microsoft.com/en-us/free/" target="_blank" rel="noopener noreferrer">signup</a> for a free account to start.</li><li><a href="https://code.visualstudio.com/" target="_blank" rel="noopener noreferrer">Visual Studio Code</a> and <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">this VS Code Extension</a> - if you favor IDEs.</li></ul><p>This approach assumes you favor using an IDE for development, and want to streamline build/deploy into that workflow. I'm a fan of Visual Studio Code so I'll use this approach. If you prefer to use the command line, or a browser, we have you covered! </p><ul><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Quickstart: With Azure CLI</a> - for commandline-driven workflow.</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=vanilla-javascript&amp;pivots=github" target="_blank" rel="noopener noreferrer">Quickstart: With Azure Portal</a> - for browser-driven workflow.</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="12-final-outcome">1.2 Final Outcome<a href="#12-final-outcome" class="hash-link" aria-label="Direct link to 1.2 Final Outcome" title="Direct link to 1.2 Final Outcome">​</a></h3><p>The goal is to take this basic HTML/CSS/JS application and configure it for automatic build/deploy to Azure Static Web Apps. We'll be using this <strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">official quickstart</a></strong> which comes with a  <a href="https://github.com/staticwebdev/vanilla-basic/generate" target="_blank" rel="noopener noreferrer">vanilla-JS application starter template</a> that provides our base application. Feel free to be adventurous and follow these steps with your own vanillaJS codebase.</p><p>We'll clone that starter first - making <strong>GitHub</strong> our default code-hosting provider. Azure Static Web Apps has flexible deployment options so look at tutorials for <strong><a href="https://github.com/staticwebdev/vanilla-basic/generate" target="_blank" rel="noopener noreferrer">BitBucket</a>, <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/gitlab?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">GitLab</a> or <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Azure DevOps</a></strong> if preferred. Watch for the <em>Deploying SWA</em> post later this week for more details.</p><p><img loading="lazy" alt="VanillaJS Quickstart outcome page" src="/assets/images/02-vanillajs-start-55364462b5fedaf66c3f2b0310e39f13.png" width="996" height="279" class="img_ev3q"></p><p>So what does that vanilla-JS starter app do? Not much - it's just a simple title on a blank webpage as shown above. Here's what you'll end up with when done:</p><ul><li><strong>Hosted SWA</strong>: See the <a href="https://witty-desert-019fd800f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">live-deployment here</a> </li><li><strong>Codebase</strong>: See the <a href="https://github.com/fearlessly-dev/my-first-swa" target="_blank" rel="noopener noreferrer">code source repo here</a></li></ul><p>Ready to do this? Let's go!</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="13-build-process">1.3 Build Process<a href="#13-build-process" class="hash-link" aria-label="Direct link to 1.3 Build Process" title="Direct link to 1.3 Build Process">​</a></h3><p>The process is captured in <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">this quickstart document</a> and has the following steps:</p><ul><li><a href="https://github.com/login?return_to=/staticwebdev/vanilla-basic/generate" target="_blank" rel="noopener noreferrer"><strong>Click</strong></a> to generate your vanilla-js app from the template.</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript#clone-the-repository" target="_blank" rel="noopener noreferrer"><strong>Clone</strong></a> the repo to your local machine. Open in Visual Studio Code.</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript#install-azure-static-web-apps-extension" target="_blank" rel="noopener noreferrer"><strong>Install</strong></a> the Azure Static Web Apps extension in VS Code (if not present)</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript#create-a-static-web-app" target="_blank" rel="noopener noreferrer"><strong>Select Azure</strong></a> in the Activity Bar to view Azure Extensions window. You will be prompted to log into Azure and GitHub during this workflow if needed.<ol><li>Select the Static Web Apps section and click "+" to start SWA setup</li><li>Select the relevant Azure subscription to use</li><li>Select the region to deploy to (close to you)</li><li>Select the "Custom" preset - use <code>/src</code> as app location, leave build empty</li><li>Press Enter. Watch for a pop-up notification of build status.</li></ol></li></ul><p>Once deployment completes (you should see the success notification), visit the Azure Extensions window again.Look for the project in the Static Web Apps section and right-click for options. Here are three key ones to know:</p><ol><li><code>Browse Site</code> - click to see the <a href="https://witty-desert-019fd800f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">live-deployed site</a></li><li><code>Edit Workflow</code> - click to see automated <a href="https://github.com/fearlessly-dev/my-first-swa/blob/main/.github/workflows/azure-static-web-apps-witty-desert-019fd800f.yml" target="_blank" rel="noopener noreferrer">GitHub Actions</a> setup for the SWA.</li><li><code>Open in Portal</code> - click to manage the SWA in the Azure Portal.</li></ol><p><strong>That's it!! You just deployed your first Static Web App with just a few clicks and configuration inputs!</strong> 🎉</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="14-lets-unpack">1.4 Let's Unpack<a href="#14-lets-unpack" class="hash-link" aria-label="Direct link to 1.4 Let's Unpack" title="Direct link to 1.4 Let's Unpack">​</a></h3><p>So what happened under the hood? </p><p>If you look at your <a href="https://github.com/fearlessly-dev/my-first-swa" target="_blank" rel="noopener noreferrer">codebase</a> you'll see <strong>one key change</strong> - the Azure SWA service <a href="https://github.com/fearlessly-dev/my-first-swa/commit/1441e25149f1573a7010682e0a431263fbd89cb6" target="_blank" rel="noopener noreferrer">sets up the GitHub Actions workflow</a> for you, directly in the repo using your GitHub credentials. No manual steps needed from you!</p><p>The workflow automates the build/deploy process on both code commit (<code>push</code>) and contribution (<code>pull request</code>) events. So when you make changes to your application code, it triggers the workflow to automatically rebuild and deploy the updated Static Web App. 🙌🏽</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="15-video-tutorial">1.5 Video Tutorial<a href="#15-video-tutorial" class="hash-link" aria-label="Direct link to 1.5 Video Tutorial" title="Direct link to 1.5 Video Tutorial">​</a></h3><p>Want to see a video walkthrough of the process? Check out this 2-minute <a href="https://docs.microsoft.com/en-us/shows/azure-tips-and-tricks-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Static Web Apps: Tips &amp; Tricks</a> video from 2021. It features a different vanilla-JS application but follows the same "Quickstart with Visual Studio Code" steps so you can see them in action! </p><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-deploy-your-first-azure-static-web-apps-3-of-16--azure-tips-and-tricks-static-web-apps"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-there-is-no-try">2. "There is No Try!"<a href="#2-there-is-no-try" class="hash-link" aria-label="Direct link to 2. &quot;There is No Try!&quot;" title="Direct link to 2. &quot;There is No Try!&quot;">​</a></h2><p>You realize today is May 3rd, right? That means tomorrow is May 4 - and what better way to celebrate our favorite movie call-to-action (<code>MayTheFourthBeWithYou</code>) than to pay homage with our own custom crafted movie banner sharing our origin story. </p><p><img loading="lazy" alt="Build a crawler with Azure Static Web Apps" src="/assets/images/02-banner-glaucia-239d13ae2cf19aced204fe0d027a72c0.png" width="1000" height="420" class="img_ev3q"></p><p>Try out this 3-part tutorial to take the basic HTML/CSS/JS application to the next level - and recreate the iconic introduction from the classic <a href="https://en.wikipedia.org/wiki/Star_Wars" target="_blank" rel="noopener noreferrer">Star Wars</a> franchise. Just do the thing! </p><ol><li><a href="https://dev.to/azure/building-star-wars-crawler-with-azure-static-web-apps-part-1-3o39" target="_blank" rel="noopener noreferrer">Part 1: Create basic page and style it with HTML/CSS</a> </li><li><a href="https://dev.to/azure/building-star-wars-crawler-with-azure-static-web-apps-part-2-3hc0" target="_blank" rel="noopener noreferrer">Part 2: Bring moving banner to life with JS</a></li><li><a href="https://dev.to/azure/building-star-wars-crawler-with-azure-static-web-apps-part-3-41ip" target="_blank" rel="noopener noreferrer">Part 3: Use Visual Studio Code to deploy to Static Web Apps</a></li></ol><p><strong>Please Note:</strong> The tutorial is meant only to illustrate the creation of the banner with CSS/JS/HTML and celebrate an iconic movie on an iconic date! The movie logo, music and other iconic elements remain the property of relevant copyright holders and should not be used without permission. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-lets-talk-plans">3. Let's Talk Plans!<a href="#3-lets-talk-plans" class="hash-link" aria-label="Direct link to 3. Let's Talk Plans!" title="Direct link to 3. Let's Talk Plans!">​</a></h2><p>The Azure Static Web Apps service comes with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/plans" target="_blank" rel="noopener noreferrer">two plans</a> - a <strong>Free</strong> plan that is perfect for Personal projects, and a <strong>Standard</strong> (paid) plan that is more appropriate for apps deployed in production. Check out the <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/plans#features" target="_blank" rel="noopener noreferrer">Features Comparison</a> to judge what plan is best for you.</p><p>My personal experience is that, as an individual developer, the free tier is sufficiently generous to explore ideas and host prototypes (for real-world users) or demos (for validating ideas). The free tier also comes with Managed Functions support (to integrate a serverless API capability) out of the box. You will need the Standard plan if you want to "Bring your own functions" instead. For the most part, you should be able to try out all the Exercises in #30DaysOfSWA using the Free tier.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="4-exercise">4: Exercise<a href="#4-exercise" class="hash-link" aria-label="Direct link to 4: Exercise" title="Direct link to 4: Exercise">​</a></h2><p>If you followed along with the quickstart, you should have setup and deployed your first Azure Static Web App using a vanilla-JS starter. Now, time to challenge yourself by trying out one (or both) of these options:</p><ul><li><strong>Complete the other quickstart tutorials</strong> - using <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Azure CLI</a> and <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Azure Portal</a> - to get a sense of how the workflows differ. And join the <a href="/blog/swanniversary">#SWAanniversary</a> event to learn more about <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/local-development" target="_blank" rel="noopener noreferrer">SWA CLI</a> for local development.</li><li><strong>Build your own movie crawler</strong> - follow Glaucia's tutorial to have the default banner running on Azure Static Web Apps - then customize the words to suit <em>your origin story</em> and share it on May 4th (<a href="https://www.starwars.com/star-wars-day" target="_blank" rel="noopener noreferrer">StarWars Day</a>) - and <code>MayThe4thBeWithYou!</code>.</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>core-concepts</category>
        </item>
        <item>
            <title><![CDATA[#03: API-Enabling SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/api-enabling-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/api-enabling-swa</guid>
            <pubDate>Wed, 04 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 1, Day 3 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 1, Day 3</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Yesterday, we built and deployed our first Static Web App (using a vanillaJS template) from a GitHub repo. We used the VS Code Extension and, with just a few clicks, it setup automated GitHub Actions (CI/CD) workflows for us transparently. Today - we learn how we can add <strong>serverless API endpoints</strong> to our application using Azure Functions, helping us scale APIs more effectively with demand.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Why go Serverless with SWA?</li><li>Add API with Azure Functions</li><li>Quickstart: Use Managed Functions</li><li>Bring Your Own Functions</li><li><strong>Example:</strong> Bring <a href="https://github.com/sinedied/azure-swag/" target="_blank" rel="noopener noreferrer">Azure-SWAG</a> to May 4!</li><li><strong>Exercise:</strong> Try it out yourself!</li></ul><p><img loading="lazy" src="/assets/images/03-banner-9229849fe218e3e7721c3687fb4299d8.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-go-serverless">Why Go Serverless?<a href="#why-go-serverless" class="hash-link" aria-label="Direct link to Why Go Serverless?" title="Direct link to Why Go Serverless?">​</a></h2><p>When <a href="/blog/introducing-swa">Introducing SWA</a>, we talked about how static web apps are architected to separate <strong>static content assets</strong> and <strong>dynamic API endpoints</strong> into separate components that can be served and scaled independently.</p><p>In yesterday's post we looked at a basic Static Web App with just content assets (no API). Deploying it with SWA helped us take advantage of Azure's globally-distributed content servers for fast and cost-effective access. Today, we want to add an API endpoint to support dynamic requests from clients. So what does serverless mean, and how do we implement serverless API endpoints?</p><p>In this context, <a href="https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/serverless/web-app" target="_blank" rel="noopener noreferrer">Serverless</a> is about using an event-driven architecture to allocate our compute resources on-demand. So, our API server will scale as demand grows, but be cost-effective when demand drops.</p><p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview" target="_blank" rel="noopener noreferrer">Azure Functions</a> makes implementing your serverless solutions easier. Event handling is implemented with <em>functions</em> (code blocks) that run on compute resources that are dynamically-allocated. Resources can spin up as API requests grow, and spin down as demand drops. <a href="https://docs.microsoft.com/en-us/learn/paths/create-serverless-applications/" target="_blank" rel="noopener noreferrer"><strong>Try this learning path</strong></a> for a deep-dive into using Azure Functions.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="use-azure-functions">Use Azure Functions<a href="#use-azure-functions" class="hash-link" aria-label="Direct link to Use Azure Functions" title="Direct link to Use Azure Functions">​</a></h2><p>Static Web Apps and Azure Functions are integrated seamlessly, enabling key features with respect to security (user data) and routing integrations:</p><ul><li><strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/user-information?tabs=javascript#api-functions" target="_blank" rel="noopener noreferrer">User data access</a></strong> - API functions can directly access user authenticaton and role-based authorization data when handling requests.</li><li><strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/configuration?#routes" target="_blank" rel="noopener noreferrer">API Route access</a></strong> - the application can access the <code>/api</code> route securely, without requiring custom CORS rules.</li></ul><p>But it gets better. Your SWA can be configured for Azure Functions in two ways:</p><ul><li><strong>Managed Functions</strong> - where the Azure Static Web Apps service configures and manages your Azure Functions deployment.</li><li><strong>Bring Your Own Functions</strong> - where you use a pre-existing Azure Functions application and manage the deployment yourself.</li></ul><p>The Free plan supports only the Managed Functions option. It has <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/apis" target="_blank" rel="noopener noreferrer">some limitations</a> - e.g., supports only HTTP triggers and lacks support for <a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview" target="_blank" rel="noopener noreferrer">Durable Functions</a> etc. - but is quick to setup and seamless to use. We'll explore this option today but look for a post in Week 4 that will discuss the <em><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/functions-bring-your-own" target="_blank" rel="noopener noreferrer">Bring Your Own Functions</a></em> approach in detail.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="adding-the-api">Adding the API<a href="#adding-the-api" class="hash-link" aria-label="Direct link to Adding the API" title="Direct link to Adding the API">​</a></h2><p>Want to get some hands-on experience with adding an API endpoint to your Static Web Apps deployment? Check out this <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/add-api?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Quickstart</a> tutorial that builds on the vanilla-JS application you deployed previously. The key steps are:</p><p><strong>1. Setup Azure Functions for SWA</strong></p><ul><li>Install the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions" target="_blank" rel="noopener noreferrer">Azure Functions Extension</a> for VS Code.</li><li>Open your application root folder ("/") - create an "api" subfolder</li><li>Select "Azure Static Web Apps: Create HTTP Function" through Command Palette or select the lightning bolt option in Azure extension menu.</li><li>Enter required configuration information (language="JavaScript", function name="message"), and confirm.</li></ul><p><em>Sit back and wait till the process completes setup.</em> This populates the <code>/api</code> directory with configuration files (*.json) in the root folder, and a <code>/api/message</code> subfolder that contains 2 files:</p><ul><li><em>function.json</em> - defines this function's trigger, bindings and <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=blob#function-code" target="_blank" rel="noopener noreferrer">other settings</a>.</li><li><em>index.js</em> - implements an async function (accessed at <code>/api/message</code>)</li></ul><p><strong>2. Update the index.js file to implement your function</strong> - making sure it returns a desired response given the incoming API request and context (input parameters).</p><p><strong>3. Update your application code to invoke the API</strong> - you can do this by calling <code>fetch('/api/message')</code> directly - the seamless Azure Functions integration ensures that the API routing happens automagically.</p><p><strong>4. Test the integration locally with the SWA CLI</strong>.
The Azure Static Web Apps CLI (SWA CLI) is a tool to support local development for Static Web Apps by emulating required services where needed. Follow <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/add-api?tabs=vanilla-javascript#run-the-frontend-and-api-locally" target="_blank" rel="noopener noreferrer">these steps</a> to install the tools and run/test your app and API together in your local development environment. Look for a detailed 2-part post in Week 3 ("Developer Tools") where we cover the SWA CLI capabilities, configuration, and usage, in more detail.</p><p><strong>5. Update the GitHub Actions workflow with API location</strong></p><p>This is the key step to make sure the Azure Static Web Apps deployment workflow also picks up the new API function.</p><ul><li>Open the default GitHub Actions workflow file for your SWA and update the <code>api_location</code> property to "api".</li><li>Save and commit changes to trigger rebuild and deploy.</li></ul><p><strong>Want to see API in action?</strong> Scroll down to the <code>Exercise</code> section where we walk through a quick activity you can do to build and deploy a Static Web App with GitHub (SWAG) <em>and celebrate #StarWars Day</em> in the process!</p><p><strong>Prefer a video tutorial?</strong> Check out this <a href="https://docs.microsoft.com/en-us/shows/azure-tips-and-tricks-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Static Web Apps: Tips &amp; Tricks</a> that walks through the process from a <em>react-starter</em> template, and showcases the use of remote <a href="https://code.visualstudio.com/docs/remote/create-dev-container" target="_blank" rel="noopener noreferrer">development container</a> for Visual Studio Code that further streamlines your development experience.</p><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-add-an-api-to-your-azure-static-web-app-7-of-16--azure-tips-and-tricks-static-web-apps"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-swag">Exercise: SWAG!<a href="#exercise-swag" class="hash-link" aria-label="Direct link to Exercise: SWAG!" title="Direct link to Exercise: SWAG!">​</a></h2><p>Today is May 4 - Star Wars Day! Wouldn't it be nice if we could celebrate this with our favorite Star Wars quotes? Thankfully, <a href="https://www.twitter.com/sinedied" target="_blank" rel="noopener noreferrer">my colleague Yohan</a> has a great <a href="https://dev.to/sinedied/the-easy-way-to-serverless-web-apps-and-apis-with-azure-swag-2heb" target="_blank" rel="noopener noreferrer">Azure-SWAG</a> template that combines images from <a href="https://unsplash.com" target="_blank" rel="noopener noreferrer">Unsplash</a> with a pre-defined set of quotes in an API function ("/api/quote") </p><p><strong>So I created a version for my <a href="ttps://github.com/nitya/may4-swag" target="_blank" rel="noopener noreferrer">May 4 homage</a></strong>. Here's what that looks like when deployed. Refresh the SWA to get a new image and quote each time (from the API).</p><p><img loading="lazy" alt="May The Fourth Homage App" src="/assets/images/03-may4-a52b69197e93301fb9ee7f81cae37cd0.png" width="975" height="833" class="img_ev3q"></p><ul><li>See the <a href="https://github.com/nitya/may4-swag" target="_blank" rel="noopener noreferrer">Code Repository</a></li><li>See the <a href="https://agreeable-tree-0a216f70f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">Deployed SWA</a></li></ul><p>Your assignment: follow <a href="https://github.com/nitya/may4-swag#steps" target="_blank" rel="noopener noreferrer">these steps</a> to replicate my project, then explore the <a href="https://github.com/nitya/may4-swag/blob/main/api/quote/index.js" target="_blank" rel="noopener noreferrer">index.js</a> code to see how the <code>/api/quote</code> function is implemented and review the <a href="https://github.com/nitya/may4-swag/blob/main/app.js" target="_blank" rel="noopener noreferrer"><code>app.js</code></a> code to see how that API is invoked within the application.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="useful-resources">Useful Resources<a href="#useful-resources" class="hash-link" aria-label="Direct link to Useful Resources" title="Direct link to Useful Resources">​</a></h2><ul><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/apis" target="_blank" rel="noopener noreferrer">API Support in SWA</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/add-api?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Add API with Managed Functions</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/functions-bring-your-own" target="_blank" rel="noopener noreferrer">Bring Your Own Functions</a></li><li><a href="https://github.com/nitya/may4-swag" target="_blank" rel="noopener noreferrer">May4-Swag Demo</a></li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>core-concepts</category>
        </item>
        <item>
            <title><![CDATA[#04: Configuring SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/configuring-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/configuring-swa</guid>
            <pubDate>Thu, 05 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 1, Day 4 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 1, Day 4</code> of <strong>#30DaysOfSWA</strong>!! </p><p>In the past two days we've seen how the Azure Static Web Apps services sets up default CI/CD actions (to automate build/deploy workflows) and transparently configures application to access the API with minimal input from us during setup. But what if we want to <em>customize</em> the build process or application behavior? That's where knowing SWA <em>configuration options</em> can help.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Configuration: Concepts &amp; Files</li><li>Customize: Application Behavior</li><li>Customize: Build Process</li><li>Customize: Environment Settings</li><li><strong>Exercise:</strong> Explore an open source app to see these in action!</li><li><strong>Resource(s):</strong> Links for deeper-dives into the topic</li></ul><p><img loading="lazy" src="/assets/images/04-banner-b63fcb77118b4344c70f7ed8ad277ae3.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="concepts--files">Concepts &amp; Files<a href="#concepts--files" class="hash-link" aria-label="Direct link to Concepts &amp; Files" title="Direct link to Concepts &amp; Files">​</a></h2><p>When we think of configuring the Static Web App, we have three potential targets we can customize:</p><ul><li><strong>Application</strong>: Use the <code>staticwebapp.config.json</code> file (located in the folder specified for <code>app_location</code>) to define rules and properties that customize application behaviors like routing, authentication, networking and more. </li><li><strong>Build</strong>: Static Web Apps automates your build/deploy workflow using GitHub Actions or Azure Pipelines, configurable via the relevant YAML files. For example, this would be the <code>.github/workflows/azure-static-web-apps-xxx.yml</code> file in your repo, for GitHub Actions.</li><li><strong>Environment:</strong> Sometimes configuration values may only be known at runtime - e.g., database connection strings. By using environment variables, you can update the <em>values</em> at runtime without having to change the application code that uses them. Environment variables can be set in the Azure Portal (for production) or in <em>local settings files</em> (for development.)</li></ul><p>Let's take a quick look at what each of these provides, along with resource links for deeper dives that you can explore on your own. Check out the <a href="https://docs.microsoft.com/azure/static-web-apps/configuration-overview#example-scenarios" target="_blank" rel="noopener noreferrer">example scenarios</a> to get a better understanding of which file (or concept) you need to focus on, for specific scenarios.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="config-application">Config: Application<a href="#config-application" class="hash-link" aria-label="Direct link to Config: Application" title="Direct link to Config: Application">​</a></h2><p>Application behavior is configured using the <em>staticwebapp.config.json</em> file located in the folder defined by <code>app_location</code>. Here are a <em>subset</em> of the properties and their purpose:</p><ul><li><p><a href="https://docs.microsoft.com/azure/static-web-apps/configuration#routes" target="_blank" rel="noopener noreferrer"><strong>"routes"</strong></a> - are an array of "route" objects that can each be associated with access rules ("allowedRoles"), actions ("redirect", "rewrite") - and request ("methods") and response ("headers","statusCode") properties.</p></li><li><p><a href="https://docs.microsoft.com/azure/static-web-apps/configuration#fallback-routes" target="_blank" rel="noopener noreferrer"><strong>"navigationFallback"</strong></a> supports applications that rely on client-side routing by providing a server-side fallback route which serves the required page, with filters to control usage.</p></li><li><p><a href="https://docs.microsoft.com/azure/static-web-apps/configuration#response-overrides" target="_blank" rel="noopener noreferrer"><strong>"responseOverrides"</strong></a> allows you to return a custom response instead of default HTTP error codes, for more user-friendly experiences.</p></li><li><p><a href="https://docs.microsoft.com/azure/static-web-apps/configuration#platform" target="_blank" rel="noopener noreferrer"><strong>"platform"</strong></a> sets platform-specific configurations like <em>apiRuntime</em> for API language runtime version.</p><p>There are also configuration properties for authentication, networking, global headers, custom MIME types and more. Check out the <a href="https://docs.microsoft.com/azure/static-web-apps/configuration#file-location" target="_blank" rel="noopener noreferrer">documentation</a> for the complete list and scan this <strong>example</strong> <a href="https://docs.microsoft.com/azure/static-web-apps/configuration#example-configuration-file" target="_blank" rel="noopener noreferrer">staticwebapp.config.json</a> to understand how these are defined.</p></li></ul><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"routes"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/profile*"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"allowedRoles"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"authenticated"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/admin/index.html"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"allowedRoles"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"administrator"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/images/*"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"headers"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"cache-control"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"must-revalidate, max-age=15770000"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/api/*"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"methods"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"GET"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"allowedRoles"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"registeredusers"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/api/*"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"methods"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"PUT"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"POST"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"PATCH"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"DELETE"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"allowedRoles"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"administrator"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/api/*"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"allowedRoles"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"authenticated"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/customers/contoso*"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"allowedRoles"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"administrator"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"customers_contoso"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/login"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"rewrite"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/.auth/login/github"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/.auth/login/twitter"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"statusCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">404</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/logout"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"redirect"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/.auth/logout"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/calendar*"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"rewrite"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/calendar.html"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"route"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/specials"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"redirect"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/deals"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"statusCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">301</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"navigationFallback"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"rewrite"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"index.html"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"exclude"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"/images/*.{png,jpg,gif}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/css/*"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"responseOverrides"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"400"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"rewrite"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/invalid-invitation-error.html"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"401"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"redirect"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/login"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"statusCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">302</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"403"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"rewrite"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/custom-forbidden-page.html"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"404"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"rewrite"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/404.html"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"globalHeaders"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"content-security-policy"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"mimeTypes"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">".json"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"text/json"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="config-build">Config: Build<a href="#config-build" class="hash-link" aria-label="Direct link to Config: Build" title="Direct link to Config: Build">​</a></h2><p>Azure Static Web Apps build workflows are powered either by GitHub Actions (in a file named something like <code>.github/workflows/azure-static-web-apps-xxx.yml</code>) or by Azure Pipelines (using the <code>azure-pipelines.yml</code> file). </p><p>The main settings you need to be familiar with are:</p><ul><li><code>app_location</code> - folder for application source code</li><li><code>api_location</code> - folder with API functions source code</li><li><code>output_location</code> - where are build files generated</li><li><code>app_build_command</code> - custom app build command (for Node.js apps)</li><li><code>api_build_command</code> - custom api build command (for Node.js apps)</li><li><code>skip_app_build</code> - flag to skip app build step (if true)</li><li><code>skip_api_build</code> - flag to skip api build step (if true)</li><li><code>build_timeout_in_minutes</code> - defaults to 15 (customize to extend)</li></ul><p>Read <a href="https://docs.microsoft.com/azure/static-web-apps/build-configuration?tabs=azure-devops#environment-variables" target="_blank" rel="noopener noreferrer"><strong>this document</strong></a> to learn how each of those properties can be customized and used effectively.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="config-environment">Config: Environment<a href="#config-environment" class="hash-link" aria-label="Direct link to Config: Environment" title="Direct link to Config: Environment">​</a></h2><p>Your application behavior configuration values may change based on the runtime context. By setting values in <em>environment variables</em>, you can decouple definition of values from their usage within application code. We refer to these environment variables as <a href="https://docs.microsoft.com/azure/static-web-apps/application-settings" target="_blank" rel="noopener noreferrer"><strong>application settings</strong></a> which are copied to both staging and production environments. </p><p>But where are they <em>defined?</em> That depends on the development stage:</p><ul><li><strong><a href="https://docs.microsoft.com/azure/static-web-apps/application-settings#configure-api-application-settings-for-local-development" target="_blank" rel="noopener noreferrer">Local Development:</a></strong> When developing your app, you can use a local settings file that is not tracked by GitHub so sensitive information is not leaked. <strong>Azure Functions</strong> uses the <code>api/local.settings.json</code> file to store relevant app settings - and watch out for a special 2-part series of posts in Week 3 where we cover the local settings file used by the <a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer"><strong>Static Web Apps CLI</strong></a> for a simpler, unified local development experience.</li><li><a href="https://docs.microsoft.com/azure/static-web-apps/application-settings#configure-application-settings" target="_blank" rel="noopener noreferrer"><strong>Staging/Production:</strong></a> You can define and configure these application settings in the <a href="https://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure Portal</a> via the browser, or by using the <a href="https://docs.microsoft.com/cli/azure/" target="_blank" rel="noopener noreferrer">Azure CLI</a> (see the <a href="https://docs.microsoft.com/cli/azure/staticwebapp/appsettings?view=azure-cli-latest" target="_blank" rel="noopener noreferrer"><code>az staticwebapp appsettings</code></a> documentation), to create and manage your application settings. These will be encrypted, and copied to staging and production environments.</li></ul><p>Learn more about how you can configure application settings in <a href="https://docs.microsoft.com/azure/static-web-apps/application-settings#configure-application-settings" target="_blank" rel="noopener noreferrer">the documentation</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-tos-watch-it">How-Tos: Watch It!<a href="#how-tos-watch-it" class="hash-link" aria-label="Direct link to How-Tos: Watch It!" title="Direct link to How-Tos: Watch It!">​</a></h2><p>Want to see how application behavior configuration in action? Check out these two videos from the <a href="https://docs.microsoft.com/shows/azure-tips-and-tricks-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Static Web Apps: Tips &amp; Tricks</a> series.</p><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-configure-routing-in-azure-static-web-apps-6-of-16--azure-tips-and-tricks-static-web-apps"></iframe><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-configure-authorization-in-azure-static-web-apps-9-of-16--azure-tips-and-tricks-static-web-ap"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-explore-it">Exercise: Explore It!<a href="#exercise-explore-it" class="hash-link" aria-label="Direct link to Exercise: Explore It!" title="Direct link to Exercise: Explore It!">​</a></h2><p>The <a href="https://github.com/sinedied/swa-bank" target="_blank" rel="noopener noreferrer">SWA Bank</a> is a Static Web App application developed as a solution for one of the projects in the <a href="https://github.com/microsoft/Web-Dev-For-Beginners" target="_blank" rel="noopener noreferrer">Web Dev For Beginners</a> curriculum. </p><p>It was recently updated to reflect best practices. Explore the configuration files in the project - and see if you understand how they customize the application behavior and build process. <strong>Then revisit it in week 3 when we discuss developer tools</strong> to understand how local settings are configured and used with the Static Web Apps CLI (<code>swa</code>) tool for local development </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="useful-resources">Useful Resources<a href="#useful-resources" class="hash-link" aria-label="Direct link to Useful Resources" title="Direct link to Useful Resources">​</a></h2><ol><li><a href="https://docs.microsoft.com/azure/static-web-apps/configuration-overview" target="_blank" rel="noopener noreferrer">Configuration Overview</a></li><li><a href="https://docs.microsoft.com/azure/static-web-apps/configuration" target="_blank" rel="noopener noreferrer">Application Configuration: staticwebapp.config.json</a></li><li><a href="https://docs.microsoft.com/azure/static-web-apps/build-configuration?tabs=github-actions" target="_blank" rel="noopener noreferrer">Build Configuration: Actions or Pipelines YAML</a></li><li><a href="https://docs.microsoft.com//azure/static-web-apps/application-settings" target="_blank" rel="noopener noreferrer">Environment Configurations: For Backends</a></li><li><a href="https://docs.microsoft.com/azure/static-web-apps/application-settings" target="_blank" rel="noopener noreferrer">Configure Application Settings</a></li><li><a href="https://github.com/sinedied/swa-bank" target="_blank" rel="noopener noreferrer">SWA Bank Repo</a> - a Static Web Apps project to explore and learn from.</li></ol>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>core-concepts</category>
        </item>
        <item>
            <title><![CDATA[#05: Securing SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/securing-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/securing-swa</guid>
            <pubDate>Fri, 06 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 1, Day 5 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 1, Day 5</code> of <strong>#30DaysOfSWA</strong>!! </p><p>So far, we've learnt to build/deploy a basic web app, add a serverless API endpoint and customize the configuration settings for both application behaviors and build workflows. But we forgot one thing - the <strong>user</strong>! To create <em>differentiated</em> experiences for users, we need ways to <strong>identify them</strong> and <strong>understand their role</strong> in the application context. We can then use that information to <strong>manage user access to application features</strong> (role-based authorization) as well as <strong>application access to user information</strong> (once authenticated).</p><p>Thankfully, Azure Static Web Apps makes this fairly painless. Let's see how.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>How do we secure a SWA?</li><li>Managed authentication</li><li>Custom authentication</li><li>Managing user roles</li><li>Role-based authorization</li><li>Accessing user information</li></ul><p><img loading="lazy" src="/assets/images/05-banner-58c09cd248a074a90780339236c54413.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="securing-swa">Securing SWA<a href="#securing-swa" class="hash-link" aria-label="Direct link to Securing SWA" title="Direct link to Securing SWA">​</a></h2><p>What does it mean to <em>secure</em> a Static Web App? It's three things:</p><ul><li><strong>Knowing User Identity</strong> - Having a way to determine the identity of the user using an authentication service or provider.</li><li><strong>Knowing User Roles</strong> - Understanding what persona the user is taking on when (using the application), and customizing the experience accordingly.</li><li><strong>Managing User Access</strong> - Making sure the authenticaton information is seamlessly accessible to all SWA components, allowing them to enforce rules that allow only authorized users or roles to access resources.</li></ul><p>Let's dive into the three concepts that tackle these needs: <strong>Authentication</strong>, <strong>Role Assignment</strong> and <strong>Role-Based Authorization</strong>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="managed-auth">Managed Auth<a href="#managed-auth" class="hash-link" aria-label="Direct link to Managed Auth" title="Direct link to Managed Auth">​</a></h2><p>Azure Static Web Apps comes with a default <strong>streamlined authentication experience</strong> that supports:</p><ul><li><em>pre-configured providers</em>: Twitter, GitHub, Azure Active Directory</li><li><em>pre-assigned roles</em>: anonymous (guest) or authenticated (on login)</li><li><em>customizable rules</em>: defined for routes, in <code>staticwebapps.config.json</code></li></ul><p>All pre-configured providers are active by default, with their own pre-defined API endpoints for <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=invitations#login" target="_blank" rel="noopener noreferrer">Login</a>, and a shared API endpoint for <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=invitations#logout" target="_blank" rel="noopener noreferrer">Logout</a>. </p><ul><li>Want to block a specific pre-configured provider? Just <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=invitations#block-an-authentication-provider" target="_blank" rel="noopener noreferrer">add a blocking rule</a> to their login route to ensure no user is allowed access to it.</li><li>Want to send users to custom pages after successful or failed login attempts? Use <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=invitations#post-login-redirect" target="_blank" rel="noopener noreferrer">query parameters and route rules</a> to make this work.</li></ul><p>This is the default <em>managed authentication</em> experience. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="custom-auth">Custom Auth<a href="#custom-auth" class="hash-link" aria-label="Direct link to Custom Auth" title="Direct link to Custom Auth">​</a></h2><p>But what if you want more flexibility with the registration process (used by a pre-configured provider) or want to add a new one (custom provider)?
This is where <em>custom authentication</em> options come in, allowing you to override the defaults.</p><p>You can <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=aad#configure-a-custom-identity-provider" target="_blank" rel="noopener noreferrer">configure one or more custom providers</a> for this purpose. Azure Static Web Apps has <strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=apple#configure-a-custom-identity-provider" target="_blank" rel="noopener noreferrer">built-in support</a> for custom authentication using: <em>Apple, Facebook, Google, Twitter, GitHub - and AAD</em>!</strong> You can also configure custom providers that support <a href="https://openid.net/connect/" target="_blank" rel="noopener noreferrer">OpenID Connect</a> standard. </p><p>By configuring at least one custom provider, you are effectively disabling pre-configured provider options. To configure custom providers, add config information to the <code>auth</code> section of the <code>staticwebapps.config.json</code> file. This is also a good place to use <em>Application Settings</em> (environment variables) to store potentially sensitive configuration data in a privacy-preserving way.</p><p>Azure Static Web Apps makes custom registrations easy by providing standard route patterns for <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=apple#authentication-callbacks" target="_blank" rel="noopener noreferrer"><em>Login</em>, <em>Logout</em> and <em>User Profile</em></a> requests, as well as <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=apple#authentication-callbacks" target="_blank" rel="noopener noreferrer">redirect URLs</a> for authentication callbacks (from the custom provider) on login/logout.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="user-roles">User Roles<a href="#user-roles" class="hash-link" aria-label="Direct link to User Roles" title="Direct link to User Roles">​</a></h2><p>There are three key concepts you need to know in this context:</p><ul><li>Every Static Web Apps user has one or more roles assigned to them.</li><li>There are 2 built-in roles ("anonymous" and "authenticated")</li><li>Define custom roles &amp; assign users <strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=invitations#add-a-user-to-a-role" target="_blank" rel="noopener noreferrer">by invitation</a></strong> or <strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=function#add-a-user-to-a-role" target="_blank" rel="noopener noreferrer">by-function</a></strong>.</li></ul><p>Let's review these quickly. </p><ul><li>All users accessing a Static Web App are in an <em>anonymous</em> role (guest) until authenticated by a pre-configured or custom provider.</li><li>Once authenticated, they have an <em>authenticated</em> role but can now be <em>assigned custom roles</em> by invitation (proactive) or by function (reactive)</li><li><strong>Proactive invitations</strong> can be configured and sent from the Azure Portal, using provider-specific email addresses for the user. Users now click on the invite link to login with that custom role assigned automatically.</li><li><strong>Reactive functions</strong> defer assignment to post-login, using an Azure Function that dynamically returns an assigned role (or roles) to the user on being given the authenticated user details.</li></ul><p>The latter approach offers more flexibility, allowing you to use the function handler to invoke another service (like <a href="https://developer.microsoft.com/graph" target="_blank" rel="noopener noreferrer">Microsoft Graph</a>) to make the role-assignment decision for you. Read <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=function#role-management" target="_blank" rel="noopener noreferrer"><strong>Role Management</strong></a> for more details - including steps to update role assignments or remove users from a role.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="role-based-auth">Role-Based Auth<a href="#role-based-auth" class="hash-link" aria-label="Direct link to Role-Based Auth" title="Direct link to Role-Based Auth">​</a></h2><p>Once the user has been assigned a role, <em>managing user access</em> based on that assignment becomes easy using the built-in support for <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/configuration#routes" target="_blank" rel="noopener noreferrer">routing rules</a> based on the <strong>allowedRoles</strong> property attached to each <code>route</code>. For example, the following configuration setting (in <code>staticwebapps.config.json</code>) would restrict access to all routes that start with <code>/profile*</code> to <em>only authenticated users</em>.
)</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "route": "/profile*",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "allowedRoles": ["authenticated"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Read more about <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/configuration#securing-routes-with-roles" target="_blank" rel="noopener noreferrer">securing routes with rules</a> to understand various usage scenarios and configuration settings to enforce them.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="access-user-info">Access User Info<a href="#access-user-info" class="hash-link" aria-label="Direct link to Access User Info" title="Direct link to Access User Info">​</a></h2><p>One of the benefits of Azure Static Web Apps' seamless integration of application and API capabilities is that <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/user-information?tabs=javascript" target="_blank" rel="noopener noreferrer">authenticated user information can be accessed transparently</a> in two ways:</p><ul><li>Using a <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/user-information?tabs=javascript#direct-access-endpoint" target="_blank" rel="noopener noreferrer">direct access endpoint</a> at <code>/.auth/me</code> that is automatically provisioned with the user's information when authenticated.</li><li>Using <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/user-information?tabs=javascript#api-functions" target="_blank" rel="noopener noreferrer">API functions</a> with a <code>fetch</code> call to the <code>/api/xxx</code> endpoint, where <code>xxx</code> is a named function you implement to return user information. </li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-tos-watch-it">How-Tos: Watch It!<a href="#how-tos-watch-it" class="hash-link" aria-label="Direct link to How-Tos: Watch It!" title="Direct link to How-Tos: Watch It!">​</a></h2><p>Prefer a Video Walkthrough to understand the process? We have you covered with the <a href="https://docs.microsoft.com/en-us/shows/azure-tips-and-tricks-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Tips And Tricks: Static Web Apps</a> series. Check out the following videos:</p><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-integrate-authentication-in-azure-static-web-apps-8-of-16--azure-tips-and-tricks-static-web-a"></iframe><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-configure-authorization-in-azure-static-web-apps-9-of-16--azure-tips-and-tricks-static-web-ap"></iframe><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-try-it">Exercise: Try it!<a href="#exercise-try-it" class="hash-link" aria-label="Direct link to Exercise: Try it!" title="Direct link to Exercise: Try it!">​</a></h2><p>One popular feature that modern web apps often support is the ability to assign a custom role to an authenticated user (based on some identifiable context) and then regulate their access to various routes or features in the application based on that assigned role. <strong>How can we make that happen in Static Web Apps?</strong></p><p>There's a <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/assign-roles-microsoft-graph" target="_blank" rel="noopener noreferrer"><strong>tutorial</strong></a> that teaches you how! </p><ul><li>Authenticate the user using the managed <a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-whatis" target="_blank" rel="noopener noreferrer">Azure Active Directory</a> API endpoint.</li><li>Query <a href="https://developer.microsoft.com/graph" target="_blank" rel="noopener noreferrer">Microsoft Graph</a> to determine their Active Directory group membership.</li><li>Use that membership to assign them a custom role.</li></ul><p><strong>Challenge Yourself!</strong> </p><p>Update the application behavior in the <code>staticwebapp.config.json</code> file to restrict user access to specific routes by specifying <code>allowedRoles</code> for those routes. Test what happens when the custom role above is added, and then removed, from the collection of allowedRoles.</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="useful-resources">Useful Resources<a href="#useful-resources" class="hash-link" aria-label="Direct link to Useful Resources" title="Direct link to Useful Resources">​</a></h2><ol><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=invitations" target="_blank" rel="noopener noreferrer">Authentication and Authorization in SWA</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/user-information?tabs=javascript" target="_blank" rel="noopener noreferrer">Accessing authenticated user information in SWA</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=aad" target="_blank" rel="noopener noreferrer">Implement custom authentication in SWA</a></li><li>Tutorial: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/assign-roles-microsoft-graph" target="_blank" rel="noopener noreferrer">Assign custom roles using Microsoft Graph and AAD</a></li><li>Video Series: <a href="https://docs.microsoft.com/en-us/shows/azure-tips-and-tricks-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Tips And Tricks - Static Web Apps</a></li></ol>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>core-concepts</category>
        </item>
        <item>
            <title><![CDATA[#06: Previewing SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/previewing-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/previewing-swa</guid>
            <pubDate>Sat, 07 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 1, Day 6 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 1, Day 6</code> of <strong>#30DaysOfSWA</strong>!! </p><p>We're almost at the end of week 1!! 🎉 </p><p>So far, we've learned how we can use the <em>static assets hosting</em> (Azure Static Web Apps) and <em>serverless API</em> (Azure Functions) capabilities to build and deploy a web application in a scalable and cost-effective way. And we learned to <em>configure</em> and <em>secure</em> our Static Web App to suit our needs. So what else do we need to talk about?</p><p><strong>Deployment</strong> options? Let's do it!! We've talked about the default experience so far: deploy from a <em>production</em> branch, using <em>GitHub</em> Actions for CI/CD. But how do we handle <strong>previewing</strong> the Static Web App before production deploys? Let's talk about previewing SWA in pull requests, on non-production branches, and in pre-configured named environments that make our staging workflows more productive.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What types of deployment does SWA support?</li><li><em>Previewing</em>: in Pull Requests</li><li><em>Previewing</em>: in Non-Production Branches</li><li><em>Previewing</em>: in Named Environments</li><li><em>Deploying</em>: to Custom Domains</li><li><strong>Exercise:</strong> <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests" target="_blank" rel="noopener noreferrer">Review PR using SWA Preview Capability</a></li></ul><p><img loading="lazy" src="/assets/images/06-banner-94bc0f608367c239030f3ab3a9fa79cc.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deployment-types">Deployment Types<a href="#deployment-types" class="hash-link" aria-label="Direct link to Deployment Types" title="Direct link to Deployment Types">​</a></h2><p>When we think about deployment, we are typically thinking of two kinds of environments: <em>production</em> which serve as the primary endpoint for real world use, and <em>staging</em>  that can be used for internal testing, early validation of preview releases.</p><p>Azure Static Web Apps has built-in support for four types of environments:</p><ul><li><em>Production</em>: This is the real world deployment endpoint that is <strong>indexed by search engines</strong>, and associated with the custom domain (if configured).</li><li><em>Pull Request (PR)</em>: This is a <strong>temporary</strong> environment setup for a Pull Request, and torn down when that PR is closed.</li><li><em>Branch</em>: This is a environment you can set up for non-production branches, at a <strong>stable</strong> URL for the lifetime of the branch.</li><li><em>Named</em>: The above environments have URLs that reflect their PR (number) or branch (name). You can also configure a <strong>stable</strong> preview environment with a fixed name, associated with some deployment context (e.g., an interim release)</li></ul><p>Production deploys have URLs like <code>&lt;DEFAULT-HOSTNAME&gt;-&lt;NUMBER&gt;.azurestaticapps.net</code> where the <code>DEFAULT-HOSTNAME</code> is unique for each application. </p><p>With <em>preview</em> environments, the URL looks like: <code>&lt;DEFAULT_HOSTNAME&gt;-&lt;BRANCH_OR_ENVIRONMENT_NAME&gt;.&lt;LOCATION&gt;.azurestaticapps.net</code> where the <code>LOCATION</code> reflects the deployment region, and the <code>BRANCH_OR_ENVIRONMENT_NAME</code> can also take the form of a branch name, a named environment, or a number in the case of pull requests.</p><p>Let's take a brief look at each of these.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="pull-requests">Pull Requests<a href="#pull-requests" class="hash-link" aria-label="Direct link to Pull Requests" title="Direct link to Pull Requests">​</a></h2><p>Currently Pull Request <em>preview environments</em> are available for projects hosted in GitHub, and configured to use GitHub Actions by Azure Static Web Apps:</p><ul><li>Every PR to a <em>watched branch</em> gets a dedicated but <strong>temporary</strong> pre-production staging environment that is torn down when the PR is closed.</li><li>Use it to validate changes, perform sanity checks, etc.</li><li>The environment is automatically rebuilt and deployed if new commits are made to the branch associated with an active PR.</li><li>The staged environment is <em>publicly visible</em> event if your GitHub repo is private - though the URL is not easily discoverable (i.e., not indexed by search engines) by default.</li></ul><p>Learn how to <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests" target="_blank" rel="noopener noreferrer">preview Pull Requests in Azure Static Web Apps</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="branches">Branches<a href="#branches" class="hash-link" aria-label="Direct link to Branches" title="Direct link to Branches">​</a></h2><p>Preview environments for branches will have <strong>stable</strong> URLs. Configure them in the relevant <em>GitHub Actions</em> or <em>Azure Pipelines</em> workflow files as <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/branch-environments?tabs=github-actions#example" target="_blank" rel="noopener noreferrer">shown in this example</a>. </p><p>For example, in a GitHub Actions context, this involves two steps:</p><ul><li>set the <code>production_branch</code> property to the branch you want to use as the source for that production deployment.</li><li>list all other branches that you want preview environments for under <code>trigger</code> (Azure Pipelines) or <code>push: branches</code> (in GitHub Actions).</li></ul><p>You can use a wildcare (<code>**</code> for GitHub Actions, <code>*</code> for Azure Pipelines) if you want to track <em>all</em> branches for preview environment support. </p><p>Here's an example GitHub Actions config file - the <strong>production</strong> environment is built from the <em>main</em> branch, and separate <strong>preview</strong> environments are built for the other listed branches (<em>dev</em> and <em>staging</em>).</p><p>Learn how to <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/branch-environments?tabs=github-actions" target="_blank" rel="noopener noreferrer">create branch preview environments in Azure Static Web Apps</a>.</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">name: Azure Static Web Apps CI/CD</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">on:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  push:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    branches:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - dev</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - staging</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  pull_request:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    types: [opened, synchronize, reopened, closed]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    branches:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">jobs:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  build_and_deploy_job:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name: Build and Deploy Job</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    steps:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - uses: actions/checkout@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        with:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          submodules: true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - name: Build And Deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        id: builddeploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        uses: Azure/static-web-apps-deploy@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        with:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          production_branch: "main"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="named-envs">Named Envs<a href="#named-envs" class="hash-link" aria-label="Direct link to Named Envs" title="Direct link to Named Envs">​</a></h2><p>Sometimes, you want to have a non-production preview environment that is at <em>stable</em> URL (not tied to a specific PR number or branch name), and that gets rebuilt on commits to <em>all tracked branches</em> in the configuration file. </p><p>Just like with branches, this requires a manual change to your default configuration file (GitHub Actions or Azure Pipelines) as <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/named-environments?tabs=github-actions#configuration" target="_blank" rel="noopener noreferrer">shown in this example</a>.</p><p>In the GitHub Actions case, the steps are:</p><ul><li>Set the <code>deployment_environment</code> property (in the relevant build job) to be the <strong>name</strong> you want to use for this preview environment</li><li>List the branches you want associated with this named environment under <code>push: branches</code> - commits to those will result in rebuild/deploy to this environment.</li></ul><p>Here's an example GitHub Actions configuration file - this sets up a named environment called <strong>release</strong> which gets updated when changes are made to <strong>any</strong> branch (reflected by the <code>**</code> wildcard), and deployed to a site with a URL like <code>&lt;DEFAULT_HOST_NAME&gt;-release.&lt;LOCATION&gt;.azurestaticapps.net</code>.</p><p>Learn about <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/named-environments?tabs=github-actions" target="_blank" rel="noopener noreferrer">named preview environments in Azure Static Web Apps</a></p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">name: Azure Static Web Apps CI/CD</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">on:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  push:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    branches:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - "**"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  pull_request:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    types: [opened, synchronize, reopened, closed]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    branches:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">jobs:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  build_and_deploy_job:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name: Build and Deploy Job</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    steps:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - uses: actions/checkout@v2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        with:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          submodules: true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      - name: Build And Deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        id: builddeploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        uses: Azure/static-web-apps-deploy@v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        with:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          deployment_environment: "release"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="custom-domains">Custom Domains<a href="#custom-domains" class="hash-link" aria-label="Direct link to Custom Domains" title="Direct link to Custom Domains">​</a></h2><p>You may have noticed that default deployment URLs - in the form <code>XXX.azurestaticapps.net</code> for production environments or <code>XXX.&lt;LOCATION&gt;.azurestaticapps.net</code> for preview environments - are not exactly user friendly for use and recall. </p><p>Adding a custom domain helps. Azure Static Apps makes that easy with options to also configure <strong>subdomains</strong> and an <strong>apex domain</strong>! Here, given a domain like <code>www.azure.com</code>, <code>azure.com</code> is the apex domain and <code>www</code> is the relevant subdomain.</p><p>So how do you configure these? You have two options:</p><ul><li>Use an <strong>external DNS Provider</strong> (if your domain registrar supports it)</li><li>Use <strong>Azure DNS</strong> (to manage your DNS domain, even if purchased elsewhere)</li></ul><p>To keep this post short, we won't go into details for each of these options. Instead check out these links based on the direction you want to go in:</p><ul><li>Setup Apex Domain - with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/apex-domain-azure-dns" target="_blank" rel="noopener noreferrer">Azure DNS</a> | with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/apex-domain-external" target="_blank" rel="noopener noreferrer">External Provider</a></li><li>Setup Subdomain - with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/custom-domain-azure-dns" target="_blank" rel="noopener noreferrer">Azure DNS</a> | with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/custom-domain-external" target="_blank" rel="noopener noreferrer">External Provider</a></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-tos-watch-it">How-Tos: Watch It!<a href="#how-tos-watch-it" class="hash-link" aria-label="Direct link to How-Tos: Watch It!" title="Direct link to How-Tos: Watch It!">​</a></h2><p>Prefer a Video Walkthrough to understand the process? We have you covered with the <a href="https://docs.microsoft.com/en-us/shows/azure-tips-and-tricks-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Tips And Tricks: Static Web Apps</a> series. Check out this video to understand how you can setup a custom domain for your Static Web App!</p><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-set-up-a-custom-domain-name-in-azure-static-web-apps-10-of-16--azure-tips-and-tricks-static-w"></iframe><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-try-it">Exercise: Try it!<a href="#exercise-try-it" class="hash-link" aria-label="Direct link to Exercise: Try it!" title="Direct link to Exercise: Try it!">​</a></h2><p><strong>Pull Requests</strong> are critical to having a productive open source or multi-contributor project, so it's important to know how Azure Static Apps works in setting up <strong>pre-production</strong> environments for validating the changes proposed in a pull-request, before merging it for production deployment.</p><p>Get hands-on experience with the process by completing <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests" target="_blank" rel="noopener noreferrer">this tutorial</a> on an existing Azure Static Web Apps project. </p><p><em>At present, the staged pre-production environment for Pull Requests is available only for GitHub Actions deployments - so make sure you pick a GitHub-hosted SWA project that already had the default workflows set up</em>.</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="useful-resources">Useful Resources<a href="#useful-resources" class="hash-link" aria-label="Direct link to Useful Resources" title="Direct link to Useful Resources">​</a></h2><ol><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/preview-environments" target="_blank" rel="noopener noreferrer">Preview environments in Azure Static Web Apps</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests" target="_blank" rel="noopener noreferrer">Pull-Request Preview Environments</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/branch-environments" target="_blank" rel="noopener noreferrer">Branch Preview Environments</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/named-environments" target="_blank" rel="noopener noreferrer">Named Preview Environments</a></li><li>Video Series: <a href="https://docs.microsoft.com/en-us/shows/azure-tips-and-tricks-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Tips And Tricks - Static Web Apps</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/custom-domain" target="_blank" rel="noopener noreferrer">About Custom Domains</a></li></ol>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>core-concepts</category>
        </item>
        <item>
            <title><![CDATA[#07: Deploying SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/deploying-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/deploying-swa</guid>
            <pubDate>Sun, 08 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 1, Day 7 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 1, Day 7</code> of <strong>#30DaysOfSWA</strong>!! </p><p>You made it this far! Give yourself a pat on your back already! 😊  </p><p>By now, we have learnt what Static Web Apps is, and how to build, add APIs and configure the application. We’ve also deployed a couple of fun apps as a tribute to Star Wars! But we’ve so far explored deploying using the Github Actions path. </p><ul><li>What if we want some other CI/CD tool? </li><li>What if our project resides safely in an Azure DevOps repository? </li><li>What if we don’t want a CI/CD solution AT ALL? </li></ul><p>Fear not! Because today we’re gonna explore other ways of deploying a Static Web App on Azure 😊 </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Deploy With Azure DevOps  </li><li>Deploy From GitLab and BitBucket </li><li>Deploy Using ARM Template </li><li><strong>Exercise</strong>: Explore the <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/quickstart-create-templates-use-visual-studio-code?tabs=CLI" target="_blank" rel="noopener noreferrer">ARM Tools VS Code Extension</a></li></ul><p><img loading="lazy" src="/assets/images/07-banner-fe3a45087af0648a5f8ce9b650b522e9.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-with-azure-devops">Deploy with Azure DevOps<a href="#deploy-with-azure-devops" class="hash-link" aria-label="Direct link to Deploy with Azure DevOps" title="Direct link to Deploy with Azure DevOps">​</a></h2><p>Deploying using Azure pipelines CI/CD has never been easier! </p><p>Static Web Apps supports projects which are stored in Azure repos and helps in creating a smooth CI/CD pipeline to automatically trigger the changes on every commit to the main branch. What more? With the latest changes checked in for Azure DevOps, we can now <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=vanilla-javascript&amp;pivots=azure-devops" target="_blank" rel="noopener noreferrer">set up the azure pipeline via Portal with a single click</a>! Here’s a quick video demonstrating how to use DevOps as a pipeline, as well as touching on the numerous other enhancements brought in off-late, such as stable staging environments, password protected websites, build and deploy split, and lots more! 😊 </p><iframe width="560" height="315" frameborder="0" src="https://www.youtube.com/embed/4JkfeZp7aDk" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-via-gitlab-and-bitbucket">Deploy via GitLab and BitBucket<a href="#deploy-via-gitlab-and-bitbucket" class="hash-link" aria-label="Direct link to Deploy via GitLab and BitBucket" title="Direct link to Deploy via GitLab and BitBucket">​</a></h2><p>But what if we wanted a third-party Provider? Static Web Apps as of today <a href="https://azure.microsoft.com/en-us/updates/public-preview-static-web-apps-now-supports-gitlab-and-bitbucket-for-cicd/" target="_blank" rel="noopener noreferrer">officially supports</a> CI/CD pipelines from GitLab and BitBucket! We just have to follow a few simple steps as discussed in the documentation for both <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/gitlab?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">GitLab</a> and <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/bitbucket?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">BitBucket</a>, and voila! We’ll have a beautifully configured pipeline which takes care of the automatic trigger on commits for us. Isn’t this beautiful? 😊 </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-using-arm-template">Deploy using ARM Template<a href="#deploy-using-arm-template" class="hash-link" aria-label="Direct link to Deploy using ARM Template" title="Direct link to Deploy using ARM Template">​</a></h2><p>For the CLI lovers out there, we can also deploy in Static Web Apps <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli" target="_blank" rel="noopener noreferrer">using ARM Templates</a>! The ARM - or <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview" target="_blank" rel="noopener noreferrer">Azure Resource Manager Template</a> - is used in preparing the workflow template. On deploying the ARM Template to Azure Static Web Apps, it triggers the Github Actions, which further takes care of our CI/CD needs. Do check out the exercise later in the blog for a quick hands-on using ARM Templates!  </p><p>But what about .. <strong>deploying without a CI/CD??</strong> </p><p>Suppose we want a one-time deployment solution? Or we don’t want to depend on a CI/CD tool at all! No worries! We have you covered! Wonder how that is supported? Stay tuned to the #30DaysOfSWA series and <strong>discover the new upcoming features</strong> to enable this! 😉 &lt;3&lt;3  </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Now that we’ve explored the alternatives we have, let’s go have some fun with it!! Here are a few quickstarts you can try out!</p><ol><li><a href="https://aka.ms/swabitbucketsupport" target="_blank" rel="noopener noreferrer">Deploy using BitBucket</a> </li><li><a href="https://aka.ms/swagitlabsupport" target="_blank" rel="noopener noreferrer">Deploy using GitLab</a> </li><li><a href="https://aka.ms/static-web-apps-publish-devops" target="_blank" rel="noopener noreferrer">Deploy using Azure DevOps and Portal Quickstart</a>  </li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-azure-resource-manager?tabs=azure-cli" target="_blank" rel="noopener noreferrer">Use an ARM template quickstart</a></li></ol>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>core-concepts</category>
        </item>
        <item>
            <title><![CDATA[#08: Build A Blog - with Astro]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/build-with-astro</link>
            <guid>https://www.azurestaticwebapps.dev/blog/build-with-astro</guid>
            <pubDate>Mon, 09 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 2, Day 1 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 2, Day 1</code> of <strong>#30DaysOfSWA</strong>!! </p><p>In Week 1 we covered core concepts for Azure Static Web Apps - from development to API-enablement, security, configuraton and deployment.</p><p>Today, we kick off Week 2 with a focus on seeing SWA in action - using popular web development frameworks and static site generators to build and deploy different kinds of applications. We kick things off with a look at <a href="https://astro.build" target="_blank" rel="noopener noreferrer">Astro</a> - a modern static site generator with a BYOF ("Bring your own framework") approach.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What is a static site generator?</li><li>What is Astro?</li><li>Build &amp; Deploy a Personal Blog with Astro</li><li><strong>Exercise:</strong> Try the tutorial to deploy <strong>your</strong> personal blog!</li></ul><p><img loading="lazy" alt="Build a Blog with Astro + SWA" src="/assets/images/08-banner-d7850c9ddfc28d46cb657d7cecd62a98.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="static-site-generators">Static Site Generators<a href="#static-site-generators" class="hash-link" aria-label="Direct link to Static Site Generators" title="Direct link to Static Site Generators">​</a></h2><p>The term "static site generators" (SSG) refers to tools that automatically build static webpages for you, populating a chosen template with your custom content or data. The code generation is transparent to you, making it possible for even non-developers to setup custom static websites quickly. </p><p>Static site generation is a growing trend for fast, flexible website creation. But it requires an external service to handle hosting and build/deploy workflows. <strong>This is where Azure Static Web Apps comes in!</strong> Check out the <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-gatsby" target="_blank" rel="noopener noreferrer">SWA documentation</a> for tutorials featuring popular SSGs like Hugo, Jekyll and Gatsby. We'll explore some other examples later this week.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="hello-astro">Hello, Astro!<a href="#hello-astro" class="hash-link" aria-label="Direct link to Hello, Astro!" title="Direct link to Hello, Astro!">​</a></h2><p>Today's post will however focus on <a href="https://astro.build/blog/introducing-astro" target="_blank" rel="noopener noreferrer">Astro</a>, one of the <a href="https://risingstars.js.org/2021/en#section-ssg" target="_blank" rel="noopener noreferrer">rising stars of JavaScript</a> in the <em>Static Sites</em> category. Astro is a static site builder that works <em>like an SSG</em> but with some <a href="https://astro.build/blog/introducing-astro" target="_blank" rel="noopener noreferrer">novel features</a> that set it apart. </p><ul><li>Bring your own framework (React, Vue, Svelte, web components)</li><li>Compose your website using that framework's UI components</li><li>Astro now renders a fully-static (all HTML, no JavaScript) website</li></ul><p>Astro emphasizes <strong>fast performance</strong> with <strong>less JavaScript</strong> - and takes a <a href="https://www.patterns.dev/posts/progressive-hydration/" target="_blank" rel="noopener noreferrer">partial hydration</a> approach that allows it to load the minimal required amount of JavaScript, if and when absolutely necessary. Here's a quick overview of Astro.</p><iframe width="560" height="315" frameborder="0" src="https://www.youtube.com/embed/dsTXcSeAZq8" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="astro--swa">Astro + SWA<a href="#astro--swa" class="hash-link" aria-label="Direct link to Astro + SWA" title="Direct link to Astro + SWA">​</a></h2><p>In <strong><a href="https://dev.to/azure/building-applications-with-astro-build-azure-static-web-apps-cli-a20" target="_blank" rel="noopener noreferrer">today's tutorial</a></strong>, we walk through the steps required to:</p><ul><li>create an astro-powered blog (using <a href="https://github.com/glaucia86/astro-swa-demo" target="_blank" rel="noopener noreferrer">this template</a></li><li>test it locally using the Azure Static Web Apps CLI (<code>swa</code>)</li><li>deploy it using the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">Visual Studio Code Extenstion for SWA</a> </li></ul><p>The end result will look like this.
<img loading="lazy" alt="Personal Blog with Astro" src="/assets/images/08-astro-c5c53e6fc34418cb8f77b158c61b8488.jpeg" width="880" height="527" class="img_ev3q"></p><p>Here are the key links to know:</p><ul><li>Visit <strong><a href="https://dev.to/azure/building-applications-with-astro-build-azure-static-web-apps-cli-a20" target="_blank" rel="noopener noreferrer">this page</a></strong> for the step-by-step tutorial.</li><li>Check <strong><a href="tttps://github.com/glaucia86/astro-swa-demo" target="_blank" rel="noopener noreferrer">this repository</a></strong> for the source code (demo app template)</li><li><strong><a href="https://yellow-grass-008f2c710.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">See this site</a></strong> for the deployed version of the app.</li></ul><p>Then check back tomorrow for a new usage example and tutorial - this time, with a focus on React - as we continue to explore Azure Static Web Apps in action!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>Here are a couple of options to try, to get more hands-on experience:</p><ul><li>Clone the <a href="https://github.com/glaucia86/astro-swa-demo.git" target="_blank" rel="noopener noreferrer">template project</a> and follow the <a href="https://dev.to/azure/building-applications-with-astro-build-azure-static-web-apps-cli-a20" target="_blank" rel="noopener noreferrer">tutorial</a> to build and deploy <strong>your</strong> personal blog.</li><li>Visit the <a href="https://astro.build/themes/" target="_blank" rel="noopener noreferrer">Astro Themes</a> page and try using a different starter project, then deploying it to Azure Static Web Apps.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Check out these other tutorials using more traditional static site generators:</p><ul><li>Publish a <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-gatsby" target="_blank" rel="noopener noreferrer">Gatsby site</a> to Azure Static Web Apps</li><li>Publish a <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-hugo" target="_blank" rel="noopener noreferrer">Hugo site</a> to Azure Static Web Apps</li><li>Publish a <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-jekyll" target="_blank" rel="noopener noreferrer">Jekyll site</a> to Azure Static Web Apps</li><li>Publish a <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-vuepress" target="_blank" rel="noopener noreferrer">VuePress site</a> to Azure Static Web Apps</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>usage-examples</category>
            <category>astro</category>
        </item>
        <item>
            <title><![CDATA[#09: Manage Inventory - with React]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/build-with-react</link>
            <guid>https://www.azurestaticwebapps.dev/blog/build-with-react</guid>
            <pubDate>Tue, 10 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 2, Day 2 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 2, Day 2</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Yesterday we looked at using a static site builder (namely <a href="https://astro.build" target="_blank" rel="noopener noreferrer">Astro</a>) to create a personal blog and host it with Azure Static Web Apps. Over the next two days, we switch gears and look at using Azure Static Web Apps with some popular <em>front-end frameworks</em> - starting today with <a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">React</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Why Learn React?</li><li>React + SWA: Quickstart</li><li>Build: Inventory Management App</li><li><strong>Exercise:</strong> Build &amp; Deploy a basic React SWA.</li></ul><p><img loading="lazy" src="/assets/images/09-banner-591c45c368672751da7cfb9f1468f043.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-learn-react">Why Learn React?<a href="#why-learn-react" class="hash-link" aria-label="Direct link to Why Learn React?" title="Direct link to Why Learn React?">​</a></h2><p>React describes itself as <a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">a JavaScript library for building user interfaces</a> that targets single-page application (SPA) development with a declarative and component-based approach. Today, it's one of the most popular technologies used for web development, leading the <a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">2021 rising stars of JavaScript</a> section for front-end frameworks. Whether you're new to web development, or an experienced developer, it's a technology worth learning.</p><p>New to React? Here are a couple of resources:</p><ul><li><a href="https://reactjs.org/tutorial/tutorial.html" target="_blank" rel="noopener noreferrer">Official Tutorial: Intro to React</a></li><li><a href="https://docs.microsoft.com/en-us/learn/paths/react/" target="_blank" rel="noopener noreferrer">Creating your first web apps with React</a> - on Microsoft Learn</li><li><a href="https://github.com/microsoft/Web-Dev-For-Beginners" target="_blank" rel="noopener noreferrer">Web Dev For Beginners</a> - project-based curriculum</li></ul><p>`</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="swa-quickstart">SWA Quickstart<a href="#swa-quickstart" class="hash-link" aria-label="Direct link to SWA Quickstart" title="Direct link to SWA Quickstart">​</a></h2><p>Once you have a simple React application scaffolded, configuring it to use Azure Static Web Apps is easy. In week 1, we covered the three different approaches (using Visual Studio Code, using Azure Portal, using Azure CLI) to build and deploy a vanillaJS app.</p><p>Want to try building and deploying a basic React starter app? The Azure Static Web Apps documentation has <strong>Quickstarts</strong> to help! </p><p>The following tutorials use the <a href="https://github.com/staticwebdev/react-basic" target="_blank" rel="noopener noreferrer">react-basic</a> starter template bootstrapped using <a href="https://github.com/facebook/create-react-app" target="_blank" rel="noopener noreferrer">create-react-app</a>. Pick an option based on your preferred development environment:</p><ul><li>SWA Quickstart: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=react" target="_blank" rel="noopener noreferrer">Using Visual Studio Code</a></li><li>SWA Quickstart: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=react" target="_blank" rel="noopener noreferrer">Using Azure CLI</a></li><li>SWA Quickstart: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=react&amp;pivots=azure-devops" target="_blank" rel="noopener noreferrer">Using Azure Portal</a></li></ul><p>This should help you setup and validate the basic tooling required for developing Azure Static Web Apps. Now, let's think about building something a little more functional!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="inventory-mgmt">Inventory Mgmt<a href="#inventory-mgmt" class="hash-link" aria-label="Direct link to Inventory Mgmt" title="Direct link to Inventory Mgmt">​</a></h2><p>Today, I'm publishing the first of a <em>multi-part tutorial</em> on how you can build an inventory management app with Azure Static Web Apps and React.</p><p><a href="https://dev.to/azure/build-an-inventory-management-app-with-azure-static-web-apps-with-react-part-1-2l2e" target="_blank" rel="noopener noreferrer"><strong>Read Part 1 of the Tutorial Here</strong></a>:</p><blockquote><p>In this series, I'll take you from the very beginning on generating a React app and deploying it within 5 minutes. In the upcoming parts, I'll keep building on the same app, and add things like backend and other things.</p></blockquote><p><img loading="lazy" alt="Banner image from dev.to article" src="/assets/images/09-snowpack-d2ba42180bf38be57dfacb90e2b44f27.png" width="864" height="359" class="img_ev3q"></p><p>In this tutorial you'll learn about:</p><ul><li>Options to scaffold your React App</li><li>Use the <code>Snowpack</code> option to scaffold your project</li><li>Use VS Code to configure &amp; deploy the app to SWA.</li></ul><p>Check out the <a href="https://happy-wave-036ec970f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">deployed SWA</a> at this stage of the tutorial. In the next part of the series, we'll improve UI and add routing support.</p><p><a href="https://dev.to/azure/build-an-inventory-management-app-with-azure-static-web-apps-with-react-part-1-2l2e" target="_blank" rel="noopener noreferrer"><strong>Revisit this series page tomorrow</strong></a> to continue with the tutorial.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-try-it">Exercise: Try It!<a href="#exercise-try-it" class="hash-link" aria-label="Direct link to Exercise: Try It!" title="Direct link to Exercise: Try It!">​</a></h2><p>This is the perfect time to make sure you have your development environment setup and ready to follow along. Try the quickstart option, then follow along with the tutorial series.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Here are the key resources we shared in this article:</p><ul><li>SWA Quickstart: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=react" target="_blank" rel="noopener noreferrer">Using Visual Studio Code</a></li><li>SWA Quickstart: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=react" target="_blank" rel="noopener noreferrer">Using Azure CLI</a></li><li>SWA Quickstart: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=react&amp;pivots=azure-devops" target="_blank" rel="noopener noreferrer">Using Azure Portal</a></li><li><a href="https://reactjs.org/tutorial/tutorial.html" target="_blank" rel="noopener noreferrer">Official Tutorial: Intro to React</a></li><li><a href="https://docs.microsoft.com/en-us/learn/paths/react/" target="_blank" rel="noopener noreferrer">Creating your first web apps with React</a> - on Microsoft Learn</li><li><a href="https://github.com/microsoft/Web-Dev-For-Beginners" target="_blank" rel="noopener noreferrer">Web Dev For Beginners</a> - project-based curriculum</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>usage-examples</category>
            <category>react</category>
        </item>
        <item>
            <title><![CDATA[#10: Get Creative - with Vue.js]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/build-with-vuejs</link>
            <guid>https://www.azurestaticwebapps.dev/blog/build-with-vuejs</guid>
            <pubDate>Wed, 11 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 2, Day 3 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 2, Day 3</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Vuelievers, rejoice! Today we'll explore several examples of how you can build a Static Web App with <a href="https://vuejs.org/" target="_blank" rel="noopener noreferrer">the Vue.js framework</a> </p><p>In this article, I'll give several examples of sites I've created using Vue and <a href="https://vuepress.vuejs.org/" target="_blank" rel="noopener noreferrer">VuePress</a>, a popular way to build static sites with Vue. I'll also walk through a game engine we created in VuePress that you can deploy as a SWA, and touch on the use of <a href="https://vitejs.dev/" target="_blank" rel="noopener noreferrer">Vite.js</a>, a lightning-fast toolkit you can use to build all types of applications, built by the masterminds behind the Vue.js projects.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><p>Let's explore some creative application usage examples:</p><ul><li><strong>PoseDance:</strong> with PlayFab</li><li><strong>Ombromanie:</strong> with TensorFlow.js</li><li><strong>Olympic App</strong>:  with Vite.js</li><li><strong>Azure Mysteries</strong>: a static Game Engine</li><li><strong>Exercise</strong>: Build a game with VuePress, deploy to SWA!</li></ul><p><img loading="lazy" src="/assets/images/10-banner-70b147909a3b21540f9028f38fb6ebbc.png" width="1000" height="420" class="img_ev3q"></p><p>In this article, I'll describe the following projects, which are more fully explained on their README files in their respective repositories.
The first apps I'd like to showcase are PoseDance and Ombromanie. Both were developed as conference talks and have become interesting case studies in how to use TensorFlow.js in web apps, specifically focusing on body poses and hand poses for innovative user experiences.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-posedance">1. PoseDance<a href="#1-posedance" class="hash-link" aria-label="Direct link to 1. PoseDance" title="Direct link to 1. PoseDance">​</a></h2><p><img loading="lazy" alt="PoseDance" src="/assets/images/10-posedance-98fa2e6ce4abcdbd57a1c9b0e10f8146.png" width="2090" height="1184" class="img_ev3q"></p><p>PoseDance is your friendly TikTok trainer: watch a TikTok dance video, learn the dance, then enter a side-by-side view of the original dance with a 'skeleton' imposed on it to the left, with your own video on the right. Try to make your body poses match that of the dancer, and win a high score!</p><p>PoseDance offers a full view of SWA capabilities, including an API buildout so that the user can login and save their high scores. To save scores, it also uses <a href="https://playfab.com/" target="_blank" rel="noopener noreferrer">PlayFab</a> in the backend. In addition this repo has a Code Tour! </p><p><a href="https://marketplace.visualstudio.com/items?itemName=vsls-contrib.codetour" target="_blank" rel="noopener noreferrer">Code Tour</a> is a neat little Visual Studio Code extension that, if installed locally, will allow you to walk through the codebase in a guided manner, to learn the rationale behind code architecture. Install that extension in VS Code and give it a try! </p><p><strong>Explore: PoseDance</strong></p><ul><li>Watch the <a href="https://www.dropbox.com/s/ccog8uz0tzk10mv/posedance.mp4?dl=0" target="_blank" rel="noopener noreferrer">video</a> about the making of PoseDance. </li><li>Walk through the conference <a href="https://github.com/jlooper/posedance/blob/master/posedance.pptx" target="_blank" rel="noopener noreferrer">slides</a>. </li><li>Explore the <a href="https://github.com/jlooper/posedance" target="_blank" rel="noopener noreferrer">codebase</a></li><li>Visit the <a href="https://wonderful-ocean-007be220f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">deployed site</a> and <em>Dance with us!</em></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-ombromanie">2. Ombromanie<a href="#2-ombromanie" class="hash-link" aria-label="Direct link to 2. Ombromanie" title="Direct link to 2. Ombromanie">​</a></h2><p><img loading="lazy" alt="Ombromanie" src="/assets/images/10-ombromanie-e71ae212bced1294250928e9077c3d40.png" width="1582" height="1054" class="img_ev3q"></p><p>Ombromanie is a demo I built for a different conference talk that was described as <em>"un peu OVNI"</em> ("a little UFO-like"). In this demo, mimic the hand shadows that you used to make using just a candle and a dark room, to freak out and entertain your siblings. </p><p>Like PoseDance, this app is also built using Vue.js, and leverages TensorFlow.js and bodyposing - this time focusing on hand poses, which are actually more complex than body poses, as there are more bendable joints in play. </p><p>Use the Ombromanie app to record a video of your special hand shadow story, coupled with voice-to-text transcription of your story, and then share it. </p><p><strong>Explore: Ombromanie</strong></p><ul><li>Read the <a href="https://dev.to/azure/ombromanie-creating-hand-shadow-stories-with-azure-speech-and-tensorflow-js-handposes-3cln" target="_blank" rel="noopener noreferrer">blogpost</a></li><li>Watch the conference <a href="https://www.youtube.com/watch?v=8Aow0rkp1Lw&amp;ab_channel=MTGFrance" target="_blank" rel="noopener noreferrer">talk</a></li><li>Walkthrough the conference <a href="https://github.com/jlooper/ombromanie/blob/main/ombromanie.pptx" target="_blank" rel="noopener noreferrer">slides</a></li><li>Visit the <a href="https://brave-river-00627910f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">deployed SWA</a> and <em>Create Hand Shadow Stories!</em></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-2021-olympics">3. 2021 Olympics<a href="#3-2021-olympics" class="hash-link" aria-label="Direct link to 3. 2021 Olympics" title="Direct link to 3. 2021 Olympics">​</a></h2><p><img loading="lazy" alt="Olympic App" src="/assets/images/10-olympic-ffc626996c58694d292b8db546bd7969.png" width="3052" height="1680" class="img_ev3q"></p><p>For the <a href="https://mybuild.microsoft.com/" target="_blank" rel="noopener noreferrer">Microsoft Build</a> conference in 2021, I wanted to demonstrate how to use Vite.js to build a simple 'card flipping' app. Since it was close to the Summer Olympics, I featured all the Olympic sports in this interesting interface. Building with Vite is similar to building with Vue, although the location of the files is different. <em>But deployment as a SWA is just as straightforward.</em></p><p><strong>Explore: Olympics App</strong></p><ul><li>Visit the <a href="https://kind-mushroom-0f7f4200f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">deployed SWA</a> to see it in action.</li><li>Watch this <a href="https://www.youtube.com/watch?v=Xpl-KukvEmM&amp;ab_channel=MicrosoftDeveloper" target="_blank" rel="noopener noreferrer">video</a> and build the app with me!</li><li>Explore the <a href="https://github.com/jlooper/olympic-app" target="_blank" rel="noopener noreferrer">source</a> and build it yourself!</li></ul><p>To build it, start on the student branch and build up the app following the video instructions, or just look at the entire complete codebase.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="4-azure-mysteries">4. Azure Mysteries<a href="#4-azure-mysteries" class="hash-link" aria-label="Direct link to 4. Azure Mysteries" title="Direct link to 4. Azure Mysteries">​</a></h2><p>Finally, and something really different, I'd like you to meet <strong>SpaceQuest</strong>, a game engine that I developed with inspiration and help from my colleague <a href="https://github.com/softchris" target="_blank" rel="noopener noreferrer">Chris Noring</a>. SpaceQuest is a game engine you can use to build your own games, and deploy as a SWA, in the tradition of text-based point and click adventure games.</p><p><img loading="lazy" alt="SpaceQuest" src="/assets/images/10-spacequest-7e0a3b8f9b90b1b9259bcee493bc13f2.png" width="1390" height="1153" class="img_ev3q"></p><p> We used this engine as the core to build the <strong>Azure Maya Mystery</strong> and the <strong>Azure Space Mystery</strong> experiences, all deployed as SWAs to great acclaim. Learn more about these adventures here:</p><p><strong>Explore: Azure Maya Mystery</strong></p><ul><li><a href="https://dev.to/azure/unraveling-the-azure-maya-mystery-and-building-a-world-4pp2" target="_blank" rel="noopener noreferrer">Introducing Azure Maya Mystery</a></li><li><a href="https://dev.to/azure/azure-maya-mystery-the-inner-workings-of-a-static-web-app-hkp" target="_blank" rel="noopener noreferrer">The Making of Azure Maya Mystery</a></li><li><a href="https://dev.to/azure/azure-maya-mystery-part-ii-the-mysterious-cenote-3j57" target="_blank" rel="noopener noreferrer">The Mysterious Cenote</a></li><li><a href="https://dev.to/azure/azure-maya-mystery-part-iii-ascent-to-the-summit-41hi" target="_blank" rel="noopener noreferrer">Ascent to the Summit</a></li></ul><p><strong>Explore: Azure Space Mystery</strong></p><ul><li><a href="https://dev.to/azure/blast-off-with-azure-advocates-presenting-the-azure-space-mystery-mdd" target="_blank" rel="noopener noreferrer">Introducing Azure Space Mystery</a></li></ul><p>SpaceQuest had a very special purpose, other than being the seed code of the mysteries, however. We used it in a series of workshops with Autistic students to teach them how to build their own games, in partnership with the National Museum of Computing at Bletchley Park. </p><ul><li>Learn about <a href="https://dev.to/azure/making-games-with-autistic-students-a-partnership-between-the-national-museum-of-computing-track-org-and-azure-advocates-3c1e" target="_blank" rel="noopener noreferrer">this work</a>. It was a tremendous honor to work with these talented students!</li><li>Try the <a href="https://zealous-mushroom-04674420f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">deployed SWA</a></li><li>Explore the <a href="https://github.com/jlooper/static-game-engine" target="_blank" rel="noopener noreferrer">source</a></li></ul><p>Then build a mystery of your own by forking the codebase and building up your storyline - and share it with us!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><ol><li><a href="https://vuejs.org/" target="_blank" rel="noopener noreferrer">Vue.js</a> - The Progressive JavaScript Framework</li><li><a href="https://vitejs.dev/" target="_blank" rel="noopener noreferrer">Vite</a> - Next Generation Frontend Tooling</li><li><a href="https://vuepress.vuejs.org" target="_blank" rel="noopener noreferrer">VuePress</a> - Vue-powered Static Site Generator</li><li><a href="https://docs.microsoft.com/en-us/learn/modules/vue-get-started/" target="_blank" rel="noopener noreferrer">Get Started with Vue</a> - on Microsoft Learn</li><li><a href="https://docs.microsoft.com/en-us/learn/modules/publish-app-service-static-web-app-api/" target="_blank" rel="noopener noreferrer">Publish a Vue App with Azure Static Web Apps</a> - on Microsoft Learn</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-vuepress" target="_blank" rel="noopener noreferrer">Tutorial: Publish a VuePress Site to SWA</a></li></ol>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>usage-examples</category>
        </item>
        <item>
            <title><![CDATA[#11: Share Content - with Docusaurus]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/build-with-docusaurus</link>
            <guid>https://www.azurestaticwebapps.dev/blog/build-with-docusaurus</guid>
            <pubDate>Thu, 12 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 2, Day 4 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 2, Day 4</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Today's a special day - the <a href="https://azure.microsoft.com/en-us/updates/azure-static-web-apps-is-now-generally-available/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">1 year anniversary of Azure Static Web Apps</a>! <br> <strong>Happy Birthday SWA! 🎂</strong> </p><p>I wanted to do something special to celebrate - and I thought of just the thing! Let's create a content-focused static website <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer">with Docusaurus</a> and deploy it <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">using Azure Static Web Apps</a>. Want to get a sense of what kinds of static sites you can build with Docusaurus? <a href="https://docusaurus.io/showcase" target="_blank" rel="noopener noreferrer">Check out their showcase</a>!</p><p>Why <strong>this</strong> demo today? Well, it's very <em>Meta</em> (pun intended). You may have noticed that the <a href="https://aka.ms/30DaysOfSWA" target="_blank" rel="noopener noreferrer">#30DaysOfSWA</a> website is built on Docusaurus. 🦖</p><p>By sharing this tutorial, I'm hoping it inspires more of you to build/deploy sites that showcase your own tech journeys - whether its with #30Days of learning, or to feature your #100Devs portfolios. #LetsGetStarted! 🎉</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li><strong>Intro</strong>: What is Docusaurus?</li><li><strong>Quickstart:</strong> setup classic site</li><li><strong>Configure</strong>: <code>docusaurus.config.js</code></li><li><strong>Deploy</strong>: Azure Static Web Apps</li><li><strong>Customize</strong>: Themes &amp; Plugins</li><li><strong>Exercise</strong>: Try extending the demo further </li></ul><p><img loading="lazy" src="/assets/images/11-banner-a8fc4654511dc43a15deedffc1437a7f.png" width="1000" height="420" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="about-the-demo">About the Demo<a href="#about-the-demo" class="hash-link" aria-label="Direct link to About the Demo" title="Direct link to About the Demo">​</a></h2><p>In today's tutorial, we'll create a <em>classic</em> Docusaurus site, deploy it to Azure Static Web Apps, then make some changes to the site content to validate that it rebuilds and deploys the site without any further manual effort from us. I hope to also contribute this back to the Docusaurus docs as an example for Deploying to Azure - feedback to improve this is very welcome!</p><ul><li>🌟 <strong>The tutorial source is <a href="https://github.com/fearlessly-dev/swa-demo-docusaurus" target="_blank" rel="noopener noreferrer">here on GitHub</a></strong> - I'll update <strong>that version</strong> over time.</li><li>🎉  <strong>See the site live <a href="https://zealous-bay-0062c640f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">on Azure Static Web Apps</a></strong> - for demo purposes only.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-docusaurus">What is Docusaurus?<a href="#what-is-docusaurus" class="hash-link" aria-label="Direct link to What is Docusaurus?" title="Direct link to What is Docusaurus?">​</a></h2><p>Docusaurus is an open-source project from Meta that helps you build, deploy, and maintain, open source project websites. It was rated one of the top 3 <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer">rising stars of JavaScript</a> in 2021, under the <em>static site generators</em> category. It has a number of features that made it attractive:</p><ul><li>It has built-in support for search, localization and versioning</li><li>It support MDX (JSX-flavored Markdown) for richer content options</li><li>It has built-in support for themes and plugins to enhance default behaviors</li><li>It is built with React, making it extensible with custom components</li></ul><p>Read their <a href="https://docusaurus.io/docs" target="_blank" rel="noopener noreferrer">documentation</a> &amp; visit their <a href="https://docusaurus.io/showcase" target="_blank" rel="noopener noreferrer">showcase</a> to see real-world examples. Now, let's dive into our tutorial for building the demo.</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-setup-site">1. Setup Site<a href="#1-setup-site" class="hash-link" aria-label="Direct link to 1. Setup Site" title="Direct link to 1. Setup Site">​</a></h2><ol><li>Setup a Docusaurus site (<code>classic</code> theme) in a dedicated folder (<code>www</code>) in repo. The command automatically installs the required packages and their dependencies.</li></ol><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> npx create-docusaurus@latest www classic</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ol start="2"><li>Let's see what was created for us. The output has been cleaned up for clarity.</li></ol><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ls -l www/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">README.md   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">babel.config.js </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">blog/              </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">docs/    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">docusaurus.config.js               </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">node_modules/        </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">package-lock.json    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">package.json           </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">sidebars.js                 </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">src/                  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">static/    </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ol start="3"><li>Let's preview the site locally, to validate this worked.</li></ol><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token builtin class-name">cd</span><span class="token plain"> www</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">npx docusaurus start</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">INFO</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> Starting the development server</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">SUCCESS</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> Docusaurus website is running at http://localhost:3000/.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>You should see something like this - this is the default landing page for the scaffolded Docusaurus site.</p><p><img loading="lazy" alt="Landing Page" src="/assets/images/11-landing-d8ebc8da5a467aeb258b6ff21c4f5022.png" width="2190" height="2026" class="img_ev3q"></p><ol start="4"><li>The dev server supports hot reloading. Try making a minor change to the site source - for example edit <code>docusaurus.config.js</code> and change the <code>title</code> to <strong>"My Static Web Apps Site"</strong>. You should see this in your site preview, instantly:</li></ol><p><img loading="lazy" alt="Landing Page Reloaded" src="/assets/images/11-reload-5e921244396d1bfeb1635ca0cbdacb66.png" width="1870" height="2016" class="img_ev3q"></p><ol start="5"><li>You can now build a <strong>production-ready</strong> version of that site as follows. Note that the static files are generated in the <strong>build/</strong> directory.</li></ol><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token builtin class-name">cd</span><span class="token plain"> www/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> run build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">SUCCESS</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> Generated static files </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"build"</span><span class="token builtin class-name">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">INFO</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> Use </span><span class="token variable" style="color:#36acaa">`</span><span class="token variable function" style="color:#d73a49">npm</span><span class="token variable" style="color:#36acaa"> run serve</span><span class="token variable" style="color:#36acaa">`</span><span class="token plain"> </span><span class="token builtin class-name">command</span><span class="token plain"> to </span><span class="token builtin class-name">test</span><span class="token plain"> your build locally.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-deploy-to-azure">2. Deploy To Azure<a href="#2-deploy-to-azure" class="hash-link" aria-label="Direct link to 2. Deploy To Azure" title="Direct link to 2. Deploy To Azure">​</a></h2><p>Docusaurus is built using React - so you can use <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/front-end-frameworks" target="_blank" rel="noopener noreferrer">the same configuration settings</a> for Docusaurus, when deploying to Azure Static Web Apps. </p><p>You have three options to  get started:</p><ul><li>via browser with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=react" target="_blank" rel="noopener noreferrer">the Azure Portal quickstart</a></li><li>via terminal with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">the Azure CLI quickstart</a></li><li>via IDE with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">the VS Code Extension quickstart</a> </li></ul><p>If you prefer the first approach, click the button to go to the Azure portal, then follow the <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=react" target="_blank" rel="noopener noreferrer">quickstart</a> guidance, but using <em>this</em> project's details instead.</p><p><a href="https://portal.azure.com/?feature.customportal=false&amp;WT.mc_id=30daysofswa-61155-cxall#create/Microsoft.StaticApp" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://aka.ms/deploytoazurebutton" alt="Deploy to Azure button" class="img_ev3q"></a></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-using-vs-code">3... using VS Code<a href="#3-using-vs-code" class="hash-link" aria-label="Direct link to 3... using VS Code" title="Direct link to 3... using VS Code">​</a></h2><p>I'll use the <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Visual Studio Code extension</a> to make this happen with just a few clicks. </p><p>The whole process happens within the VS Code window, and takes just a few minutes from start to finish - <em>with guided prompts to help all the way</em>. For convenience, I've documented it step-by-step with screenshots (images valid for <em>VS Code ver 1.66.2</em>).</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="31-install-extension">3.1 Install Extension<a href="#31-install-extension" class="hash-link" aria-label="Direct link to 3.1 Install Extension" title="Direct link to 3.1 Install Extension">​</a></h2><p>Open Visual Studio Code (IDE) in the project folder for your repo. Install the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">Azure Static Web Apps extension</a> by visiting this page and clicking "Install".</p><p><img loading="lazy" alt="VS Code Extension for SWA" src="/assets/images/11-extension-c840c2a0accf37e9736192e1958f12e5.png" width="1682" height="636" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="32-find-swa-panel">3.2. Find SWA Panel<a href="#32-find-swa-panel" class="hash-link" aria-label="Direct link to 3.2. Find SWA Panel" title="Direct link to 3.2. Find SWA Panel">​</a></h2><p>When extension is installed, you should see this window in your VS Code editor, confirming readiness for use.</p><p><img loading="lazy" alt="VS Code Extension Installed" src="/assets/images/11-vscode-025c5fed556e79b72afe7ec0dbc49c41.png" width="1178" height="278" class="img_ev3q"></p><p>You'll find the Azure Static Web Apps options listed in a  section under "Azure".</p><p>The extension's <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">documentation page</a> and its <a href="https://github.com/microsoft/vscode-azurestaticwebapps/wiki/Creating-a-Static-Web-App" target="_blank" rel="noopener noreferrer">GitHub</a> page both provide detailed walkthroughs - check those for the most current process for this. We'll start by clicking the <em>Azure</em> icon in the VS Code sidebar, then scrolling down till we see this <code>Static Web Apps</code> section.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="33-create-swa">3.3 Create SWA<a href="#33-create-swa" class="hash-link" aria-label="Direct link to 3.3 Create SWA" title="Direct link to 3.3 Create SWA">​</a></h2><p>Click the "+" button to start the <strong>Create Static Web App</strong> workflow.</p><p><img loading="lazy" alt="Activate SWA Extension" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZoAAAAhCAYAAADgfG1hAAAMDUlEQVR4Ae2dW48UxxXH+RjJYxQ5zoOJoyy2tZESxZEccDD4Ag6XBIQ3AW+EwSj2BiTCEjD3NzBBBkFABAEGFAMSu9zviBde8hnyCfwJKvq19Z+cPVvd0zM7s7Oze1ZqVVfVqXNOVZ/+/7uqenrnDQwMJI6XXvpRHDEGEQMRAxEDEQMdj4F5QTRBsPGQETEQMRAx0M0YCKKJp5eOP710M2BD9/QCYpo3L/XyiOs9vde7W+PdIJqFCxemOGIMIgYiBmwM9JJksG19ifP+jc0G0bzyyvwUR4xBxEDEgI0BEY0tm47zXtmdjr7NRRsNounWlCn0zo6pb1zHuXkdBfi56z9//k/SzwYWpNdefyO9/kZrB21oi46c7iq7Ofkom9nxGUQTezTZGz1u3Jl9407X9ckB/ssv/7ggiVbJpUwewkGn7VPOrq2P8/6KzyCaIJoJN3jcwP11A3f7euUAH2IoI412y9Fp+5Kza+vjvL/iNIgmiGbCDR43cH/dwN2+Xh7wWeqqQyaffrolXb16Na3+/R9qyaPTLqN5u76fizf8Nm05v7k4fN2KFSvTqVP/zB4ffTQU8d4DzAui6cGg+xsj8gHuMzUGPODXnc18/vlIunnzZlqzdm1torGzGm/Xj8+K7b9LB/+ztzh83bVr19OzZ88mHYcOHWqbZGh77ty5xnH48OE04GZhCxa8NqnM+1YnzzLivn37GrasXc6pW7hwUfrqq+NZmbNnz6bh4T+33Vf52MwPfDlz5kxat25dU1tBNEE0TYNEgRfp3CNED/h1N/7bIRp0K8a8XZUzk1mx/cNiJiOiIc/xy/d+kZixdJpksG2J5s6dO+nRo0dp48aNDX+RAfgfPHiQvvhiz6Q9J/lfJ33//Q/S7du305UrVyYRyYULF9LDhw/TkydP0q1btybVA/5jY2Pp/PnzE3yrY9fL0Gf88ERn8xcvXkw3btxIy5d/WGkviCaIpjJAfPBFfm6RjQf8OstmyLRDNLRTfHm7Kt9yflNjJiOiUcosZ2Tkr5OIZiozGdklZQYDmQDygL0nGl5b3rNnT0E2yPkZj9VVdQ7RQBZev9qMjIwUJFMG7keP/qMjRFNHTzNf5fO0Es3x4yfSixcvGsfjx4/Txx8Pp/Hxm40yW885bXB22bLlCXnKkH/zzV8X5V6nbY8c+mnHgQ513OpTG9mSDDbkm62TTatz8+bN6fnz5w3feBqRXqWUoTtXZ/sk+z6VXfTt2rWr0RfkbJ3s5fxTnVKrR31QHamt9/5EfvaTjgf8fiOaTpEMsb5///50//79NDq6s5IIPvlkUyGHfDv3SDPwhoAgIuRy+usQRK6dL6ujp5mv0llJNKzRwdISrkpZn/SvKFr5y5cvTwJegLAu0QB4AkAAHVBEfw5gJVdGNDlApQ26rM9Wv0iCMhGF9UP+SYdk5AupdOTqbL33gbwlvZxs2TiIwMr6rD7If+sv50E0s59McvGmsplGNPKrbI/Gzmg6STLvvvtesecEedQBV+TYo6KdfK6bWv0sgWkpkCU76izR7Nixo1GPHPk6BJHzBfz+8suj6enTpxN0yr7S8fHxtHLlqqJf1tecTpVVEs22bdvSjRtjac2atZWDNTT0x0KubKqHMdY0PXCdPn16wixDYChwlJOkgDOgeP369UKPAF0yAmIBp8o1c9HTveTwxdpB7uDBg5P6KQCWrPQJkAXEIo+yvPxRX+xYeBtWVud2bOiL+qN6EY3GRfIaD+XVDzsOtJH/pNKJX+qPyiKdW8TTL0SjN82uXbtWgGQnSYaYHx0dLfYi2ITn4Xvx4ncql8aQY++Cdq3eMxa833rrNwW5ULZ06dLCtiWawcHBRj0y5NslGvRCIsPDwxN0otcely5dKmzQL8qrlvnU90qigeGOHDlSrAeWkQ0kw6bUgQMHKmc0Y2PjBUFYIJMTSj0YqlzgDrgCfICnAFMyAk4Bq8ptW84F6h6oJe9T314+3rt3r9GfnG0Bdw6ofZ1IompsJGNJweq29fRBfms85LcdN/lBW7WvOy5+nCI/Owmoimh27vx7unv3bvZgiYm9DO6TnMzNW7cSr0D7pTjFkbercqVs/DOr4aDs1KlTjadwnvzZx8gdEJJ0tJIeO3as5X0PZiO0a8UOsha8eRinPxw8ZEM2lmi2bt3aqEeG/FSIpmpJTv2gX9jwvqo+l1YSDQ2qyKYuyaBHQKaZQA5Uc2BIW5EDbXKgjkxZuQBXACo/cvbR4w+vl/aANz6hE+AeGhpqnCOPDoG4+mtnMLk69Hrbynsf7HhIRv2SHo1lGdFIJ37RRvLyV+Ml/ZFOjo25MCYe8C0x/OWzz9KFCxezx7+/+aZYxWDJPCfzr3Pn0p/Wb2ibaOzYL1myJGkmo+WdXMobUq+++tPS+8zq9OcWXH1dWb5dwLdEw8xMb3mdPHkyMcOxRMNrzKonJd+uXau3rE+U27Gwvla1aUo0NM6RTSskIwc8mNmna2RU78sFzHqCV16gSlsBp4BVNqdKNOixII5tQBhywU/O8Qu7/MmufBRwNyMa6mmj9jb146K8JQP5aO1ZnWrj660OjaFk/Fhan+J8bhBPFdFY0vHn3XrrLBd3gDEzGh0QiieaqZAMNns1o9m0aXPavXt3cWzf/rc0OPjzCUQDvqmelHwniMbalX5egli06O3uEQ0DbcmGdcc6y2W5oKDMgp7Iw5ZbohFRCPxsauUEkh4c1V6AqtmA8mU+2nK1EbGIEATuIhXbl1yZdPo6+eh9l7zs2L7rXDZzMvITPXbM1bZsDDSWyFkd8ifSuUEyXOd+IBofjxCPJZqpkgz67R6Nt5fLd2qPpldLZ9aulu7Yv1m/fkNBNCdOnCiW+NjPoZzZUG4cVFZrRiNhkQ0A1WxPRm2U4jgARt4CmYCScoGhJRCBvMDRphaYpdOWoVMgLlBV3oMo5bmXAbwO9APqlFvfvF1PJsjr8HXqt9eBvPpl+23PRQQiGvkmW0plw46t6kj5pTMyKpM+6Vd5pP+/jnNhLPqNaHji7zTJcJ3tW2d1rnun3jrL2WIfhh9SsmyVq+/EjCanV2UsnWmMeUONN9XgBtXn0paIJqegbpleBrAgKfCXjhwYCpQtgFrwFVGpzIO1iMXaEohaXzi3NuQTqXQjY/XLX8o9gMtva0MyuTrkrI+yLxu+TiQnnepTWR+kR/LSr1Ttrb+ca3wlF2kQjV8my+Wnc+nMxqSdzXRiJmN1Qx685MDvZGy5P+/272h4hZlZRi+JBjLz/a7KTxvR+N/ReODESQ+GIokc4AkY9cQtMrBEgE7p8PYE1BZYq0BV5GD1yCY65IcGW/JWv0A+V2f1Sgep+qm2qlO/1F/JkUrGpn5sbR3nrY6Hbx/52UlA/TSjYaMfAOZpu9MkQ3zrywB8ZoYvAPjfGJLfu3dv8dWAqXwZgNkTMxZITctWNmWpip+LkNpynfPVAmYdrd6T7bwMUNfGtBFNXYdCbnYCVlzX/ryu/UQ0+rFmN0hG8csSEd8yg2w4vv76UvHWFw+PAHwnvnWGLfZCtAlv0/37D6Tbt78jUx7ebZ3O2bTndz7yuW7KJ2347Q/jZ99k8+eQIDPHunqRC6IxeyetDFzI9idwxnVr7bp5oqn7UU1eXeZ13A+WLZ/0CnNuqY2yOh/VLLt+ms10k2SsbWY3EBv/jgAgJiXf7vfNrO5m5yyZ8Rsh9qOaybZav2rV6sR+uicXm+fr0c32ZLzdIJogmo4Hqw+yyLcG7jNpvDzR1P03AWVkUlXeyr8J8GMEyE8XyXjbkW8e30E0QTRBNBEDpTHgiabuPz6rIpSyulb+8VmAe3Nwn0ljFEQTIFMKMjMpUMOX3gCLJxquQzdmNXY2g42c3YiB3sRAJ8Y9iCaIJogmYqA0BnKAz/p8J8kGXX7NP2e3E4AXOnpDVkE0ATKlIBM3ZW9uypk07lWAz1IXJFH3BQG7ZEYb2trlMtvvKrtWLs77I0aDaIJogmgiBkpjoFeA3yu7QVzdIa4gmgCZUpCJm647N10/jasAv1dpP41V+Fp+vwTRBNEE0UQMlMZArwhGdgO8y8G7n8am74lm6a9+mP579vvp20vfS1tX/6D0humnixK+zo6bK65jXMeIge9i4H81XonuVn62dgAAAABJRU5ErkJggg==" width="410" height="33" class="img_ev3q"></p><p>The <em>"Create Static Web Apps"</em> process will create (and commit) a GitHub actions workflow for you that will automate the build/deploy process for your site directly from your source on all future codebase changes.</p><p>So if you have <em>current pending codebase changes</em> it will first prompt you to commit them before it does its magic! Let's get that done!</p><p><img loading="lazy" alt="Commit changes" src="/assets/images/11-commit-e4ebcc5c88eab1fec6fb83a0440f8932.png" width="516" height="392" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="34-configure-swa">3.4 Configure SWA<a href="#34-configure-swa" class="hash-link" aria-label="Direct link to 3.4 Configure SWA" title="Direct link to 3.4 Configure SWA">​</a></h2><p>The extension walks you through the five steps shown below, each with defaults already filled in for you. Customize them as shown, for this project:</p><table><thead><tr><th align="left">Screenshot</th><th align="left">Step</th></tr></thead><tbody><tr><td align="left"><img loading="lazy" alt="Step 1" src="/assets/images/11-swa-1-8cb3405b5fc4e11a4e3d383918af64e8.png" width="998" height="148" class="img_ev3q"><br></td><td align="left">Specify project name</td></tr><tr><td align="left"><img loading="lazy" alt="Step 2" src="/assets/images/11-swa-2-655a8fad3066c3bbf9cd2bbf83d3b786.png" width="998" height="290" class="img_ev3q"> <br></td><td align="left">Pick Azure region to deploy it in</td></tr><tr><td align="left"><img loading="lazy" alt="Step 3" src="/assets/images/11-swa-3-817208d7936e610e563ae813343b9920.png" width="1004" height="620" class="img_ev3q"><br></td><td align="left">Pick framework used by app</td></tr><tr><td align="left"><img loading="lazy" alt="Step 4" src="/assets/images/11-swa-4-999a4b92b119f60873a0c11665a42e52.png" width="998" height="178" class="img_ev3q"><br></td><td align="left">Specify folder contaning site source</td></tr><tr><td align="left"><img loading="lazy" alt="Step 5" src="/assets/images/11-swa-5-5175ad2d0baa4f50eb9cdd16a0a3757e.png" width="998" height="210" class="img_ev3q"><br></td><td align="left">Specify folder where site gets built by default</td></tr><tr><td align="left"></td><td align="left"></td></tr></tbody></table><h2 class="anchor anchorWithStickyNavbar_LWe7" id="35-track-progress">3.5 Track Progress<a href="#35-track-progress" class="hash-link" aria-label="Direct link to 3.5 Track Progress" title="Direct link to 3.5 Track Progress">​</a></h2><p>In a few seconds, you'll see this alert - this indicates that the workflow is <strong>creating and committing the GitHub Actions build/deploy workflow YAML</strong> for you. 🎉</p><p><img loading="lazy" alt="Created" src="/assets/images/11-swa-created-e773df9ebd39489f9a193f29b8b11f45.png" width="760" height="260" class="img_ev3q"></p><p>If you check your repository right now, you'll find the <a href="https://github.com/fearlessly-dev/swa-demo-docusaurus/commit/1005a16c10bbbce51c8526a3c14253d1aec1a59c" target="_blank" rel="noopener noreferrer">relevant commit</a> and the <a href="https://github.com/fearlessly-dev/swa-demo-docusaurus/actions/runs/2313039968" target="_blank" rel="noopener noreferrer">activated Actions flow</a> (labeled <code>ci: add Azure Static Web Apps worfklow</code>) in progress.</p><p>You can also track the progress and configuration settings of your app right there in the VS Code Sidebar, under the <code>Static Web Apps</code> section. <em>Look for the project name, and unroll contents..</em></p><p><img loading="lazy" alt="Sidebar" src="/assets/images/11-swa-sidebar-a5431359ccd9a9680923b809465aad7a.png" width="864" height="450" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="36-browse-site">3.6 Browse Site!<a href="#36-browse-site" class="hash-link" aria-label="Direct link to 3.6 Browse Site!" title="Direct link to 3.6 Browse Site!">​</a></h2><p>In a few second more, you'll get this alert:</p><p><img loading="lazy" alt="Deployed" src="/assets/images/11-swa-deployed-8ad55a927b2f4270a5223c8c03cda7ab.png" width="766" height="224" class="img_ev3q"></p><p>Now, go to the sidebar section for your project, right-click the name to see the available menu options:</p><p><img loading="lazy" alt="Browse" src="/assets/images/11-swa-browse-af691ca869bdb57a2aedf4d6b8781761.png" width="882" height="410" class="img_ev3q"></p><p>Click "Browse Site" to be taken to your live deployed Docusaurus website! That's it! A few clicks, customizing defaults - and you're done!</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="4-customize-it">4. Customize It!<a href="#4-customize-it" class="hash-link" aria-label="Direct link to 4. Customize It!" title="Direct link to 4. Customize It!">​</a></h2><p>At this point, you can make any changes to the site source, commit them - and watch the site get rebuilt and deployed without any further action from you!</p><p>Here are some things to try:</p><ul><li>Customize <a href="https://docusaurus.io/docs/styling-layout" target="_blank" rel="noopener noreferrer">styles or layout</a></li><li>Explore <a href="https://docusaurus.io/docs/api/plugins" target="_blank" rel="noopener noreferrer">plugins</a> for SEO, Search etc.</li><li>Try <a href="https://docusaurus.io/docs/markdown-features/react#using-jsx-in-markdown" target="_blank" rel="noopener noreferrer">create/use MDX</a> in content</li></ul><p>I made a few example changes to the <code>docusaurus.config.js</code> file to personalize the landing page content to reflect my needs. </p><p>And I updated the <code>src/css/custom.css</code> file to reflect new theme colors for dark/light mode - and replaced the <code>logo.svg</code> file.</p><p>Committing these changes should automatically rebuild and update the deployed site. Here is what they looked like in my local preview, before I committed the changes.</p><table><thead><tr><th align="left">Light Mode</th><th align="left">Dark Mode</th></tr></thead><tbody><tr><td align="left"><img loading="lazy" alt="Light Mode" src="/assets/images/11-swa-light-d5adbe4e5651b33b64e27e41ac3cbced.png" width="2294" height="2012" class="img_ev3q"></td><td align="left"><img loading="lazy" alt="Dark Mode" src="/assets/images/11-swa-dark-9ddedb1c4320bbdcd7108c1a171cba0c.png" width="2294" height="2028" class="img_ev3q"></td></tr></tbody></table><hr><p>🎉  <strong>Check it out: The site is <a href="https://zealous-bay-0062c640f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">live on Azure Static Web Apps</a></strong></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>You saw a few things I did to customize the site. Now it's your turn! Here are a few challenges you can try out:</p><ul><li>Complete the tutorial to deploy your own site!</li><li>Try Docusaurus customization: <strong>add an MDX component!</strong></li><li>Try SWA customization: <strong>add an API to fetch content!</strong></li><li>Try SWA customization: <strong>add auth using Twitter - use it!</strong></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources:<a href="#resources" class="hash-link" aria-label="Direct link to Resources:" title="Direct link to Resources:">​</a></h2><ul><li><a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer">Docusaurus</a> - documentation</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Static Web Apps (SWA)</a> - documentation</li><li><a href="https://aka.ms/30DaysOfSWA" target="_blank" rel="noopener noreferrer">#30DaysOfSWA</a> - guide tour to SWA.</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>usage-examples</category>
            <category>react</category>
            <category>docusaurus</category>
        </item>
        <item>
            <title><![CDATA[#12: Headless CMS & Blazor SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/build-with-blazor</link>
            <guid>https://www.azurestaticwebapps.dev/blog/build-with-blazor</guid>
            <pubDate>Fri, 13 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 2, Day 5 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 2, Day 5</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Over the last few days we've been exploring JavaScript-based frameworks for building web apps. Today, we switch our attention to our amazing .NET community and talk about building Static Web Apps with <a href="http://blazor.net" target="_blank" rel="noopener noreferrer">Blazor</a></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Introduction: Blazor WebAssembly</li><li>Quickstart: Simple Blazor SWA</li><li>Advanced: Blazor SWA + Wordpress CMS</li><li><strong>Exercise</strong>: Remix Fritz's Hat Collection!</li></ul><p><img loading="lazy" src="/assets/images/12-banner-0e1cc759de036171a1ccffbc455f93c6.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="blazor-webassembly">Blazor WebAssembly<a href="#blazor-webassembly" class="hash-link" aria-label="Direct link to Blazor WebAssembly" title="Direct link to Blazor WebAssembly">​</a></h2><p>When we think about web applications, we typically think of developing with JavaScript, HTML, and CSS. In fact, many of you reading this series may identify yourselves as JavaScript developers when discussing modern web apps.</p><p>What if I told you that was not always the case? What if you could <strong>write web applications in C#</strong>, running in a .NET runtime inside the browser! Turns out you can - thanks to <a href="https://blazor.net" target="_blank" rel="noopener noreferrer">Blazor</a>.</p><p><strong>What is Blazor?</strong></p><p>Blazor is a <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor" target="_blank" rel="noopener noreferrer">framework for building interactive client-side web UI with .NET</a>. Developers can build interactive web applications using C# (instead of JavaScript) - and extend experiences to hybrid desktop and mobile apps with .NET capabilities.</p><p><strong>What is Web Assembly?</strong> </p><p>Running .NET code inside web browsers is made possible by <a href="https://webassembly.org/" target="_blank" rel="noopener noreferrer">WebAssembly</a>(<code>wasm</code>) - a binary instruction format and open web standard that is designed as a <em>portable compilation target</em> for programming languages. It provides a sandboxed runtime that can be implemented <em>inside</em> JavaScript virtual machines (like those in modern web browsers) to support web apps.</p><p><strong>How does Blazor WebAssembly Work?</strong></p><p><a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/" target="_blank" rel="noopener noreferrer">Blazor WebAssembly</a> is a framework for building single page app (SPA) that works with all modern web browsers, including mobile versions. Blazor apps are written using <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/components/?view=aspnetcore-6.0" target="_blank" rel="noopener noreferrer">Razor</a> components in a .NET runtime. The .NET code is then executed via WebAssembly in the browser's JavaScript sandbox. WebAssembly uses JavaScript interoperability to get full access to browser features. Learn how <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/" target="_blank" rel="noopener noreferrer">Blazor web apps work</a>.</p><p><img loading="lazy" src="https://docs.microsoft.com/en-us/aspnet/core/blazor/index/_static/blazor-webassembly.png?view=aspnetcore-6.0" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="simple-blazor-swa">Simple Blazor SWA<a href="#simple-blazor-swa" class="hash-link" aria-label="Direct link to Simple Blazor SWA" title="Direct link to Simple Blazor SWA">​</a></h2><p>Want to learn how you can deploy a simple Blazor application to Azure Static Web Apps? We have you covered! Follow <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/deploy-blazor" target="_blank" rel="noopener noreferrer">this tutorial</a> to learn how to deploy an <strong>existing Blazor app</strong> to Azure Static Web Apps.</p><p>The end result will look something like this - a single page Blazor web application that displays weather data <em>returned from a serverless API</em> - beginning with <a href="https://github.com/login?return_to=/staticwebdev/blazor-starter/generate" target="_blank" rel="noopener noreferrer">this starter app</a>,</p><p><img loading="lazy" alt="Quickstart demo" src="/assets/images/12-swa-quickstart-9919d8ff0549027ce8688b19f78216a1.png" width="843" height="576" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="blazor-swa-and-wordpress">Blazor SWA and Wordpress<a href="#blazor-swa-and-wordpress" class="hash-link" aria-label="Direct link to Blazor SWA and Wordpress" title="Direct link to Blazor SWA and Wordpress">​</a></h2><p>Want to try a more complex example? Check out <a href="https://dev.to/azure/blazor-webassembly-for-headless-cms-on-azure-static-web-apps-412c" target="_blank" rel="noopener noreferrer">this advanced tutorial</a> (from Justin Yoo). Here's a brief introduction:</p><blockquote><p>One of the most popular scenarios to build a static website is to run a blog site for myself or my organisation. WordPress is the most popular service for this purpose. Now, you want to migrate your WordPress blog site to a static website, but it doesn't look easy.</p></blockquote><blockquote><p>What if you still want to use the WordPress site to write content but only want to refresh the UI outside the site? What if you can even use C# for it through Blazor WebAssembly? You are now able to use the existing WordPress site as the data source of truth and build a UI in a separate instance with your preferred method. Does that sound attractive?</p></blockquote><p>Join Justin as he walks through the steps required to: </p><ul><li>use the serviced Wordpress instance as a headless CMS</li><li>build the Blazor WebAssembly app using Wordpress</li><li>host the completed app on Azure Static Web Apps</li></ul><p>The end result issomething like this.
<strong><a href="https://dev.to/azure/blazor-webassembly-for-headless-cms-on-azure-static-web-apps-412c" target="_blank" rel="noopener noreferrer">Read the blog post behind this!!</a></strong>.</p><p><img loading="lazy" alt="Final demo" src="/assets/images/12-swa-wordpress-189f65c4868c2c87abd477359d30e3ca.png" width="880" height="495" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-remix-fritzs-hats">Exercise: Remix Fritz's Hats!<a href="#exercise-remix-fritzs-hats" class="hash-link" aria-label="Direct link to Exercise: Remix Fritz's Hats!" title="Direct link to Exercise: Remix Fritz's Hats!">​</a></h2><p>Hopefully you're ready to try something fun that will reinforce what you learned today. </p><p><strong>Say Hello to (Jeff) Fritz's Really Cool Hats</strong></p><p><a href="https://hats.csharpfritz.com/" target="_blank" rel="noopener noreferrer">Fritz's Really Cool Hats</a> is an open-source static web site built with Blazor WebAssembly, incorporating C# Azure Functions and Azure Storage, and deployed using Azure Static Web Apps. The project was created by <strong>Jeff Fritz</strong> - the face behind many Twitch livestreams and the popular <a href="https://docs.microsoft.com/en-us/shows/beginners-series-to-blazor/" target="_blank" rel="noopener noreferrer">Beginners Series To Blazor</a>.</p><p><a href="https://hats.csharpfritz.com/" target="_blank" rel="noopener noreferrer"><strong>Visit The Deployed Site</strong></a></p><p><img loading="lazy" alt="Hats demo" src="/assets/images/12-swa-fritz-57e835792b535bf928fb95462f8dcc52.png" width="990" height="965" class="img_ev3q"></p><p>For this exercise:</p><ul><li><a href="https://github.com/csharpfritz/Fritz.HatCollection" target="_blank" rel="noopener noreferrer">Fork the repository</a> and clone it locally.</li><li>Open project in Visual Studio - press F5 to launch (app and api).</li><li>Configure <a href="https://github.com/csharpfritz/Fritz.HatCollection#data-storage" target="_blank" rel="noopener noreferrer">your Azure Storage account</a> to add your own images</li><li>Use the <a href="https://aka.ms/blazor-swa/quickstart" target="_blank" rel="noopener noreferrer">quickstart</a> to deploy to Azure Static Web Apps.</li></ul><p>Explore the source and the GitHub Actions files in the original repository to understand how the app is structured. Then share your deployed project with us by tagging a tweet with #30DaysOfSWA.</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Here are some resources to get you started with your Blazor journey into </p><ul><li><a href="https://blazor.net" target="_blank" rel="noopener noreferrer">Blazor: Build Client Web Apps With C#</a></li><li><a href="https://docs.microsoft.com/en-us/shows/beginners-series-to-blazor/" target="_blank" rel="noopener noreferrer">Beginner's Series to: Blazor</a></li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/deploy-blazor" target="_blank" rel="noopener noreferrer">Tutorial: Build a Static Web App with Blazor</a></li><li><a href="https://github.com/csharpfritz/Fritz.HatCollection" target="_blank" rel="noopener noreferrer">Fritz.HatCollection - Source</a>, Jeff Fritz</li><li><a href="https://github.com/justinyoo/blazor-wasm-azfunc-aswa" target="_blank" rel="noopener noreferrer">Headless CMS Example - Source</a>, Justin Yoo</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>usage-examples</category>
            <category>blazor</category>
        </item>
        <item>
            <title><![CDATA[#13: Hosting PWA on Static Web Apps]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/pwa-on-swa</link>
            <guid>https://www.azurestaticwebapps.dev/blog/pwa-on-swa</guid>
            <pubDate>Sat, 14 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 2, Day 6 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 2, Day 6</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Yesterday we talked about deploying Blazor apps on Static Web Apps. Let's continue today with one more type of the projects you can successfully host on SWA - Progressive Web Apps (PWAs).</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>How do I start with building a PWA?</li><li>Optimized PWA-on-SWA configuration</li><li>Advanced techniques for better user experience</li><li><strong>Exercise:</strong> <a href="https://github.com/webmaxru/pwa-on-swa" target="_blank" rel="noopener noreferrer">Deploy your PWA on SWA, run offline, and install it</a></li></ul><p><img loading="lazy" src="/assets/images/13-banner-3cf47c138a827b17cf3cafad0071cc35.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="progressive-web-applications">Progressive Web Applications<a href="#progressive-web-applications" class="hash-link" aria-label="Direct link to Progressive Web Applications" title="Direct link to Progressive Web Applications">​</a></h2><p>A <strong>Progressive Web App (PWA)</strong> is a web frontend application that is progressively enhanced using open web technologies, to make sure it delivers the best possible experience on every device, based on available capabilities. The "baseline" for your app to have a title "progressive" is its installability and offline-readiness. We skip the "served with https" requirement because it became a baseline for any web app these days.</p><p><img loading="lazy" alt="#30DaysOfPWA - Core Concepts" src="/assets/images/13-pwa-30days-49b1548a61b0171a30f832e32d493c75.jpg" width="880" height="495" class="img_ev3q"></p><p>This chapter of #30DaysOfSWA assumes that you are familiar with the basic concepts of a Service Worker API and automating your service worker with the Workbox library. If you wish to learn about these technologies, you are welcome to go through the Core Concepts part of the <strong><a href="https://aka.ms/30DaysOfPWA" target="_blank" rel="noopener noreferrer">#30DaysOfPWA</a></strong> project (see roadmap above) to learn about PWA fundamentals and to watch <strong><a href="https://www.youtube.com/watch?v=LILGt_pHk9M&amp;ab_channel=NDCConferences" target="_blank" rel="noopener noreferrer">Automating a service worker with the Workbox 6</a></strong> video for quickstart with Workbox.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="is-hosting-a-pwa-on-azure-static-web-apps-different-from-classic-apps">Is hosting a PWA on Azure Static Web Apps different from "classic" apps?<a href="#is-hosting-a-pwa-on-azure-static-web-apps-different-from-classic-apps" class="hash-link" aria-label="Direct link to Is hosting a PWA on Azure Static Web Apps different from &quot;classic&quot; apps?" title="Direct link to Is hosting a PWA on Azure Static Web Apps different from &quot;classic&quot; apps?">​</a></h2><p>A Progressive Web Application is still a web frontend app so the initial scaffolding of your SWA resource is the same - you have learned how to deploy and configure various types of web apps from the previous chapters of the #30DaysOfSWA. But to make sure that your "PWA on SWA" works as intended both online &amp; offline to provide the best possible user &amp; developer experiences, you might need to pay special attention to some implementation details and fine-tune some configuration options. We'll go through the following points in this chapter:</p><ul><li>Building your service worker as a part of the overall app build</li><li>Setting up HTML5 routing - for the Single-Page Application (SPA) use-case</li><li>Applying caching strategies for SWA-hosted APIs</li><li>Showing custom error pages</li><li>How to deal with authentication in PWA</li></ul><p><strong>Sample project</strong></p><p>I created a <strong><a href="https://github.com/webmaxru/pwa-on-swa" target="_blank" rel="noopener noreferrer">PWA on SWA Starter</a></strong> project with all the best practices implemented. The app is <a href="https://aka.ms/pwa-on-swa" target="_blank" rel="noopener noreferrer">hosted on SWA</a> as shown below. Let's explore it!</p><p><img loading="lazy" alt="PWA Starter on SWA" src="/assets/images/13-pwa-starter-a1635fd2b9c0d9f831010de9313f729e.png" width="1123" height="889" class="img_ev3q"></p><p><strong>Technical stack:</strong></p><ul><li>A React application scaffolded by the <a href="https://reactjs.org/docs/create-a-new-react-app.html" target="_blank" rel="noopener noreferrer">create-react-app</a> tool. A simple SPA with a few routes and the possibility to call API endpoints. Note that the approaches described are applicable for any web frontend application: <strong>framework-based</strong> (including your custom frameworks) or <strong>"vanilla" JavaScript</strong>. We use React only for getting closer to the real-world scenario of the modern frontend app development when you have to perform some operations with your source code ("build the app") before the deployment.</li><li>A <a href="https://github.com/webmaxru/pwa-on-swa/blob/main/src/sw/service-worker.js" target="_blank" rel="noopener noreferrer">service worker</a> powered by the <a href="https://workboxjs.org" target="_blank" rel="noopener noreferrer">Workbox</a> library.</li><li>Two API endpoints created within SWA resource - to emulate "dynamic" (<code>/api/news</code>) and "conservative" (<code>/api/archives</code>) data sources.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="building-your-service-worker-as-a-part-of-the-overall-app-build">Building your service worker as a part of the overall app build<a href="#building-your-service-worker-as-a-part-of-the-overall-app-build" class="hash-link" aria-label="Direct link to Building your service worker as a part of the overall app build" title="Direct link to Building your service worker as a part of the overall app build">​</a></h2><p>The service worker file we have in the <code>src/sw</code> folder of the application is not ready for the deployment. We have to</p><ol><li><strong><a href="https://github.com/webmaxru/pwa-on-swa/blob/main/scripts/sw-build.js" target="_blank" rel="noopener noreferrer">Process it</a></strong> by the <code>workbox-build</code> module to populate with the resources to precache (to provide offline-readiness)</li><li><strong>Bundle it</strong></li><li><strong>Choose</strong> production or development mode</li><li><strong>Minify</strong> for deployment</li></ol><p>This is why in <code>package.json</code>'s <code>scripts</code> we have <code>"build-sw": "node scripts/sw-build.js &amp;&amp; npx rollup -c"</code> command that is building a service worker file and copies it into the app distribution folder.</p><p>By default, Azure Static Web Apps runs <code>npm run build</code> command to build your application. So do not forget to add a service worker build command there. The resulting  command will be:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">"build": "react-scripts build &amp;&amp; npm run build-sw"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Instead of <code>react-scripts build</code>, there might be a command to build an application using a framework/bundler of your choice. <strong>Important</strong>: Keep this order - you always build a service worker <em>after</em> the main application because the distribution folder will be scanned to list the files to precache based on the <a href="https://github.com/webmaxru/pwa-on-swa/blob/main/scripts/sw-build.js#L5" target="_blank" rel="noopener noreferrer">pattern</a> you provided.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="setting-up-html5-routing---for-the-single-page-application-spa">Setting up HTML5 routing - for the Single-Page Application (SPA)<a href="#setting-up-html5-routing---for-the-single-page-application-spa" class="hash-link" aria-label="Direct link to Setting up HTML5 routing - for the Single-Page Application (SPA)" title="Direct link to Setting up HTML5 routing - for the Single-Page Application (SPA)">​</a></h2><p>For having correct navigation in your single-page application, you have to "ask" the webserver to redirect all navigation requests to <code>index.html</code> - to run the application and let it do the routing. In SWA, you have to have something like this in the <a href="https://github.com/webmaxru/pwa-on-swa/blob/main/staticwebapp.config.json" target="_blank" rel="noopener noreferrer">configuration file</a>:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">"navigationFallback": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "rewrite": "index.html",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "exclude": ["/images/*.{png,jpg,gif}", "/static/*"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>Best practices</strong>:</p><ul><li>Always "exclude" as much as possible in <code>navigationFallback</code> - it will help you to identify and fix "resource not found" errors.</li><li>Do not copy <code>staticwebapp.config.json</code> to the app distribution folder - SWA will find it in any location within the app source code.</li></ul><p>In case of PWA, there is an extra layer of this fallback: the first in a row to handle navigation requests is a service worker. In the <a href="https://github.com/webmaxru/pwa-on-swa/blob/main/src/sw/service-worker.js" target="_blank" rel="noopener noreferrer">service-worker.js</a> we have to have the following block for correct routing in SPAs:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">const navHandler = createHandlerBoundToURL('/index.html');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const navigationRoute = new NavigationRoute(navHandler, {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  denylist: [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    new RegExp('^/images/'),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    new RegExp('^/static/'),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">registerRoute(navigationRoute);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>The above configuration will work fine for opening both root url and "deep links" like <code>/about</code> both in online and offline modes. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="showing-custom-error-pages">Showing custom error pages<a href="#showing-custom-error-pages" class="hash-link" aria-label="Direct link to Showing custom error pages" title="Direct link to Showing custom error pages">​</a></h2><p>It's a best practice to create and show custom error pages (for example for 404 Not Found) instead of the ones built-in in the browsers. And it makes sense to keep these pages as simple as possible - without running a SPA itself. To set up custom error pages, you add the following block to the <a href="https://github.com/webmaxru/pwa-on-swa/blob/main/staticwebapp.config.json" target="_blank" rel="noopener noreferrer">SWA config</a></p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">"responseOverrides": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "400": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "rewrite": "/400.html"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "404": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "rewrite": "/404.html"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>These pages will be excluded from SWA's navigation fallback automatically because these two html are in the app distribution folder. But for the Workbox and explicit directive needed - just add these addresses to the same <code>denylist</code> we met with the HTML5 navigation section.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="applying-caching-strategies-for-swa-hosted-apis">Applying caching strategies for SWA-hosted APIs<a href="#applying-caching-strategies-for-swa-hosted-apis" class="hash-link" aria-label="Direct link to Applying caching strategies for SWA-hosted APIs" title="Direct link to Applying caching strategies for SWA-hosted APIs">​</a></h2><p>With Workbox, runtime caching is simple: you specify a url pattern to "listen" and intercept, and a caching strategy to apply. There are <a href="https://developer.chrome.com/docs/workbox/modules/workbox-strategies/" target="_blank" rel="noopener noreferrer">5 strategies</a> available and you can always create a custom one. By default, all API urls start with <code>/api</code>. Then in a <a href="https://github.com/webmaxru/pwa-on-swa/blob/main/src/sw/service-worker.js" target="_blank" rel="noopener noreferrer">service worker</a>, we'll add this block for caching responses from our two API endpoints using different strategies:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">registerRoute(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ({ url }) =&gt; url.pathname.startsWith('/api/news'),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  new NetworkFirst()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">registerRoute(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ({ url }) =&gt; url.pathname.startsWith('/api/archives'),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  new CacheFirst()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Now, the data from APIs, once fetched, is also available offline!</p><p><strong>Mini-exercise</strong>: Open the <a href="https://aka.ms/pwa-on-swa" target="_blank" rel="noopener noreferrer">hosted PWA on SWA Starter</a>, open the Network tab of DevTools, and click on two buttons in the "API caching" demo area. What difference do you see in the network request/response patterns for these two strategies?</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-to-deal-with-authentication-in-pwa">How to deal with authentication in PWA<a href="#how-to-deal-with-authentication-in-pwa" class="hash-link" aria-label="Direct link to How to deal with authentication in PWA" title="Direct link to How to deal with authentication in PWA">​</a></h2><p>A couple of <strong>important</strong> rules here:</p><ol><li>Explicitly exclude the <code>.auth</code> system folder of SWA from Workbox's navigation fallback (use <code>denylist</code>) and never set up runtime caching for it</li><li>Never runtime-cache all data users fetch from restricted API endpoints (served by SWA or external)</li></ol><p>And it's a <strong>best practice</strong> to never precache and always exclude from the service worker's navigation fallback all urls related to the user authentication and restricted parts of your application. <a href="https://github.com/webmaxru/pwa-on-swa/blob/main/src/sw/service-worker.js#L27" target="_blank" rel="noopener noreferrer">Have a look</a> at the resulting <code>denylist</code> of our sample application.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-deploy-your-pwa-on-swa-run-offline-and-install-it">Exercise: Deploy your PWA on SWA, run offline, and install it!<a href="#exercise-deploy-your-pwa-on-swa-run-offline-and-install-it" class="hash-link" aria-label="Direct link to Exercise: Deploy your PWA on SWA, run offline, and install it!" title="Direct link to Exercise: Deploy your PWA on SWA, run offline, and install it!">​</a></h2><p>Hopefully, you're ready to try something fun that will reinforce what you learned today. </p><p>For this exercise:</p><ul><li><a href="https://github.com/webmaxru/pwa-on-swa" target="_blank" rel="noopener noreferrer">Fork the PWA on SWA Starter repository</a> and deploy it to Azure Static Web Apps using the skills you gained in the previous chapters of the #30DaysOfSWA</li><li>Open the url you received after the SWA resource was created</li><li>Now, go offline (disconnect from the Internet or emulate offline mode in the DevTools) and reload the page - it still works!</li><li>Using the "App available" icon on the right-hand side of the desktop browser's address bar, install the application on your laptop - now it behaves like a native one!</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Here are some resources to get you started with your Progressive Web App journey into </p><ul><li><a href="https://aka.ms/learn-pwa" target="_blank" rel="noopener noreferrer">PWA on Microsoft Docs</a></li><li><a href="https://aka.ms/30DaysOfPWA" target="_blank" rel="noopener noreferrer">#30DaysOfPWA</a></li><li><a href="https://workboxjs.org" target="_blank" rel="noopener noreferrer">Workbox library</a></li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>usage-examples</category>
        </item>
        <item>
            <title><![CDATA[#14: Show & Tell: A SWArm Of Apps]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/show-and-tell</link>
            <guid>https://www.azurestaticwebapps.dev/blog/show-and-tell</guid>
            <pubDate>Sun, 15 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 2, Day 7 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 2, Day 7</code> of <strong>#30DaysOfSWA</strong>!! </p><p>We made it to the end of Week 2!! <strong>Let's give ourselves a round of applause!</strong></p><p>In the last week we walked through a subset of usage examples featuring diverse applications, static site generators and front-end frameworks. And that's still just a small slice of what is possible. So how do you make this journey more actionable and <em>learn by doing</em>?</p><p>That's what I'll try to answer in today's post. Also <strong>bookmark this one</strong> because we will revisit it at the end of next week ("Dev Tools") and try to replicate some of these tutorials using the more streamlined experience provided by the <a href="https://aka.ms/swa-cli" target="_blank" rel="noopener noreferrer"><strong>Azure Static Web Apps CLI</strong></a> (a command-line tool for local development).</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li><strong>Recap</strong>: Usage Examples Week</li><li><strong>Build</strong>: How to Get Project Ideas</li><li><strong>Share</strong>: Contribute to the Gallery</li><li><strong>Simplify</strong>: Using Static Web Apps CLI!</li><li><strong>Exercise</strong>: Build, Deploy, and Customize, some starter app.x</li></ul><p><img loading="lazy" src="/assets/images/14-banner-827cfc4b4aa735771c9a0615208d75ca.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="week-2-recap">Week 2 Recap<a href="#week-2-recap" class="hash-link" aria-label="Direct link to Week 2 Recap" title="Direct link to Week 2 Recap">​</a></h2><p>This week was packed with different usage scenarios and front-end technologies. Let's take a quick look at what was covered:</p><ul><li><strong>Monday:</strong> We built a <a href="https://dev.to/azure/08-build-a-blog-with-astro-1lb2" target="_blank" rel="noopener noreferrer">personal blog</a> using <a href="https://astro.build/" target="_blank" rel="noopener noreferrer">Astro</a>.</li><li><strong>Tuesday:</strong> We built an <a href="https://dev.to/azure/09-manage-inventory-with-react-39lc" target="_blank" rel="noopener noreferrer">inventory management</a> app using <a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">React</a></li><li><strong>Wednesday:</strong> We <a href="https://dev.to/azure/10-get-creative-with-vuejs-33k1" target="_blank" rel="noopener noreferrer">got creative</a> with <a href="https://vuejs.org/" target="_blank" rel="noopener noreferrer">Vue</a>, ML and Game Engines!</li><li><strong>Thursday:</strong> We <a href="https://dev.to/azure/11-share-content-with-docusaurus-azure-static-web-apps-30hc" target="_blank" rel="noopener noreferrer">published content</a> using <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer">Docusaurus</a></li><li><strong>Friday:</strong> We explore <a href="https://dev.to/azure/12-headless-cms-swa-built-with-blazor-1e2d" target="_blank" rel="noopener noreferrer">headless CMS</a> examples using <a href="http://blazor.net/" target="_blank" rel="noopener noreferrer">Blazor WebAssembly</a></li><li><strong>Saturday:</strong> We learned to make SWA a more <a href="https://dev.to/azure/13-hosting-pwa-on-static-web-apps-16la" target="_blank" rel="noopener noreferrer">progressive web app</a></li></ul><p>The visual roadmap gives you a sense of what was covered each day. But this is just the tip of the iceberg. JavaScript developers have a wide variety of front-end frameworks and static site generators to work with. And, as we saw with Blazor WebAssembly, non-JavaScript developers have other frameworks they use to develop modern web applications. So, how can you continue the learn-by-doing journey? Read on for some ideas.</p><p><img loading="lazy" alt="Week 2 Roadmap" src="/assets/images/week2-roadmap-aa8766edf791b4ed83fa999f74497b9b.png" width="1000" height="563" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="project-ideas">Project Ideas<a href="#project-ideas" class="hash-link" aria-label="Direct link to Project Ideas" title="Direct link to Project Ideas">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-static-sites">1. Static Sites<a href="#1-static-sites" class="hash-link" aria-label="Direct link to 1. Static Sites" title="Direct link to 1. Static Sites">​</a></h3><p>The easiest way to get started is to use one of many <a href="https://jamstack.org" target="_blank" rel="noopener noreferrer">static site generators</a> available today. Most of these provide templates you can start with, and customize just by bringing your own content (data, media assets etc.). Need some inspiration? Take a look at the recently released <a href="https://risingstars.js.org/2021/en#section-ssg" target="_blank" rel="noopener noreferrer">Rising Stars Of JavaScript: Static Sites</a> list and see if any of those projects have starters you can repurpose.</p><p><strong>Example: My "Recipe Me" Project</strong>. </p><p>Earlier this week, we covered examples with Astro (#2), Docusarus (#3) and VuePress (#9) in our usage examples. Today we look at <a href="https://www.11ty.dev/" target="_blank" rel="noopener noreferrer">Eleventy</a> (#7).</p><p>Earlier this year I ran <a href="https://dev.to/azure/07-developing-progressive-web-apps-hfb" target="_blank" rel="noopener noreferrer">#30DaysOfPWA</a>, a similar series focused on Progressive Web Apps. And I wanted a demo! I've always wanted to have a recipe blog, and I found <a href="https://github.com/maeligg/my-online-cookbook" target="_blank" rel="noopener noreferrer">this Eleventy starter</a> that was perfect. I customized it to add the features and code required to make it PWA-compliant. And I configured it for hosting on Azure Static Web Apps. <strong>Bonus:</strong> I learned a lot in the process about the framework, and the configuration changes for SWA!</p><p><img loading="lazy" alt="Recipe Me" src="/assets/images/14-recipeme-87656adb575f75143bbce90bd447318a.png" width="2050" height="2014" class="img_ev3q"> </p><p><strong>Related Resources:</strong></p><ul><li><a href="https://dev.to/azure/07-developing-progressive-web-apps-hfb" target="_blank" rel="noopener noreferrer">Read the Tutorial</a></li><li><a href="https://github.com/fearlessly-dev/recipe-me" target="_blank" rel="noopener noreferrer">Browse the Source</a></li><li><a href="https://white-rock-036691f0f.1.azurestaticapps.net/" target="_blank" rel="noopener noreferrer">Visit the Website</a></li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-frameworks">2. Frameworks<a href="#2-frameworks" class="hash-link" aria-label="Direct link to 2. Frameworks" title="Direct link to 2. Frameworks">​</a></h3><p>The next step up from this is to look at existing application starter-kits or tutorials that target popular front-end and full-stack frameworks. Unlike static site generators (which are content-centric) these apps let you explore advanced user interactions that can benefit from SWA concepts like serverless API and authentication support. Need some inspiration? Take a look at the recently released <a href="https://risingstars.js.org/2021/en#section-framework" target="_blank" rel="noopener noreferrer">Rising Stars Of JavaScript: Front-end Frameworks</a> list and see if any of those projects have starters you can repurpose.</p><p><strong>Example:  Simona's "Sticker Shop" Project</strong>. </p><p>Check out this example from Simona Cotin (currently a Principal PM on the Static Web Apps team) which forked the <a href="https://strapi.io/blog/strapi-starter-nuxt-js-e-commerce" target="_blank" rel="noopener noreferrer">Strapi e-commerce starter</a> and adapted it for deployment on Azure Static Web Apps. The Strapi <a href="https://strapi.io/blog/strapi-starter-nuxt-js-e-commerce" target="_blank" rel="noopener noreferrer">tutorial</a> talks you through the setup and structure of the application - making it a perfect place to explore just adding SWA integrations. <strong>Bonus:</strong> Simona's deployment also takes advantage of SWA's <em>custom domain</em> support, making the app accessible at the <a href="https://aswa.cloud" target="_blank" rel="noopener noreferrer">https://aswa.cloud</a> domain.</p><p><img loading="lazy" alt="Sticker Shop" src="/assets/images/14-simona-stickers-55034595b7442f9908c438afb1d89192.png" width="2040" height="1856" class="img_ev3q"> </p><p><strong>Related Resources:</strong></p><ul><li><a href="https://strapi.io/blog/strapi-starter-nuxt-js-e-commerce" target="_blank" rel="noopener noreferrer">Read the Tutorial</a></li><li><a href="https://github.com/simonaco/sticker-shop" target="_blank" rel="noopener noreferrer">Browse the Source</a></li><li><a href="https://www.aswa.cloud/" target="_blank" rel="noopener noreferrer">Visit the Website</a></li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-oss-apps">3. OSS Apps<a href="#3-oss-apps" class="hash-link" aria-label="Direct link to 3. OSS Apps" title="Direct link to 3. OSS Apps">​</a></h3><p>Sometimes, you find the right application not because of the framework - but because its a use case that really resonates with you - even if you are not necessarily familiar with the underlying technology. These projects are great because your interest in the end result makes you more curious to dig under the hood, improving your understanding of new applicaton architectures and tooling. Need some inspiration? My favorite starting point is the <a href="https://github.com/sindresorhus/awesome" target="_blank" rel="noopener noreferrer">awesome</a> repo which is a directory of <code>awesome-XYZ</code> lists for a given technology <code>XYZ</code>. Many of these lists identify tutorials, open-source projects and starter template repos that can be the basis for your experiments!</p><p><strong>Example:  My "Google Codelabs" Project</strong>. </p><p>If you've attended any Google Developer events or community conferences, chances are you'll have encountered their <a href="https://codelabs.developers.google.com/" target="_blank" rel="noopener noreferrer">Codelabs</a> site - a repository of step-by-step tutorials that cover a wide range of technologies. But did you know that they <a href="https://github.com/googlecodelabs/tools" target="_blank" rel="noopener noreferrer">open-sourced the codelabs management and hosting tools</a>? </p><p>The underlying tooling uses Golang but the actual content is written in Markdown, and converted into the required static files by <a href="https://github.com/googlecodelabs/tools/tree/main/claat" target="_blank" rel="noopener noreferrer"><code>claat</code></a>, the "Code Labs As A Tool" utility. Follow along to create your own codelabs - and host them on Azure Static Web Apps. <strong>Bonus:</strong> The hosted app <em>is</em> the tutorial for how it was created. Isn't that meta?</p><p><img loading="lazy" alt="Google Codelabs" src="/assets/images/14-codelabs-f00e9249a556bf973fe7df3da6af2ad0.png" width="2044" height="1998" class="img_ev3q"> </p><p><strong>Related Resources:</strong></p><ul><li><a href="https://medium.com/@zarinlo/publish-technical-tutorials-in-google-codelab-format-b07ef76972cd" target="_blank" rel="noopener noreferrer">Read the Tutorial</a></li><li><a href="https://github.com/nitya/swa-googlecodelabs" target="_blank" rel="noopener noreferrer">Browse the Source</a></li><li><a href="https://agreeable-bush-016b49e0f.1.azurestaticapps.net/#0" target="_blank" rel="noopener noreferrer">Visit the Website</a></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="share-gallery">Share: Gallery<a href="#share-gallery" class="hash-link" aria-label="Direct link to Share: Gallery" title="Direct link to Share: Gallery">​</a></h2><p>We've talked about Project ideas that help <strong>you</strong> learn by repurposing the open-source projects, tutorials or templates generated by others. Now let's talk about paying it forward by <strong>sharing</strong> your project to inspire others.</p><p>That is the purpose of the <a href="/showcase">Static Web Apps Showcase</a> that we will be debuting before the end of May. You can see a sneak preview of what the app gallery looks like, allowing developers to search for projects that have <em>live</em> deployments and <em>open source</em> codebases, and use one of the listed front-end technologies. <strong>Bookmark this post or track the <em>Showcase</em> link on this site, to know when the Showcase feature goes live!</strong> Be the first to submit a project for some of the more recent technologies added to that list!</p><p><img loading="lazy" alt="SWA Gallery" src="/assets/images/swa-showcase-5214e0f3f6ea04a71fc5e8c82a94545a.png" width="936" height="826" class="img_ev3q"> </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="simplify-swa-cli">Simplify: SWA CLI<a href="#simplify-swa-cli" class="hash-link" aria-label="Direct link to Simplify: SWA CLI" title="Direct link to Simplify: SWA CLI">​</a></h2><p>One last thing. In all the usage examples and tutorial so far, we've typically emphasized either the <strong>IDE</strong> option (using the Visual Studio Code SWA extension) or the <strong>Azure Portal</strong> option (activated by the <code>Deploy to Azure</code> button configured on repo README). </p><p>But what if you could do everything from the command-line - from initializing your project configuration, to building and testing your application locally, to deploying it to the cloud in a production or preview environment? That's the promise behind the <a href="https://aka.ms/swa-cli" target="_blank" rel="noopener noreferrer">Azure Static Web Apps CLI</a>. <strong>Join us May 19 for a special #SWAanniversary event</strong> for some exciting announcements in this context.</p><p>Then bookmark and revisit this page later in May for an updated section where we discuss how we can further simplify and streamline our "learn by doing" projects with this tool!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>We've looked at various resources you can start with, to scaffold a real-world application that you can then configure for SWA deployment and further customization. Go ahead and pick something and expand on the app to create something new. Then contribute it to <a href="/showcase">our upcoming Showcase</a> project!</p><p>Need more inspiration? I'm a fan of React, but I've wanted to explore <a href="https://preactjs.com/" target="_blank" rel="noopener noreferrer">Preact</a> as a performant alternative with a comparable API. The <a href="https://preactjs.com/about/demos-examples/" target="_blank" rel="noopener noreferrer">Preact Demos</a> page has a rich set of examples - including this <a href="https://thomaswood.me/" target="_blank" rel="noopener noreferrer">Homepage Generator</a> which is a perfect 1-page resume template you can customize for <strong>your</strong> profile. <em>Try it out!</em></p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>usage-examples</category>
        </item>
        <item>
            <title><![CDATA[#15: Develop with Azure Tools]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/devtools-azure</link>
            <guid>https://www.azurestaticwebapps.dev/blog/devtools-azure</guid>
            <pubDate>Mon, 16 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 3, Day 1 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 3, Day 1</code> of <strong>#30DaysOfSWA</strong>!! </p><p>We just crossed the halfway mark on #30DaysOfSWA! We covered core concepts in Week 1, and explored usage examples in Week 2. Today we kick off week 3 with a focus on <strong><em>Developer Tools</em>!</strong> Let's dive in!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What does the Developer Experience look like?</li><li>Explore: Azure CLI</li><li>Explore: Azure Portal</li><li>Explore: Azure Core Functions Tools</li><li><strong>Exercise:</strong> Explore Azure Portal &amp; CLI docs for SWA.</li></ul><p><img loading="lazy" src="/assets/images/15-banner-c7b1865240e4a1582235f3859f025ac5.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="dev-experience">Dev Experience<a href="#dev-experience" class="hash-link" aria-label="Direct link to Dev Experience" title="Direct link to Dev Experience">​</a></h2><p>When we think about building a modern web application, we're also thinking about our <em>developer experience</em>. By <a href="https://microsoft.github.io/code-with-engineering-playbook/developer-experience/#defining-end-to-end" target="_blank" rel="noopener noreferrer">one definition</a>, developer experience refers to how easy or difficult it is for us, as developers, to perform the required tasks to implement the desired outcome. </p><p>In the case of application development, the tasks often involve:</p><ul><li><strong>Building</strong> the project from source (after creating the codebase)</li><li><strong>Testing</strong> project behaviors (to validate compliance with requirements)</li><li><strong>Deploying</strong> the project (to staging or production environments)</li><li><strong>Debugging</strong> the project (to fix issues, audit performance etc.)</li></ul><p>Having the right <strong>developer tools</strong> can make all the difference between a productive developer workflow and a painful one. This week, we'll look at the many tools and services available, that make the Azure Static Web Apps Developer Experience more seamless.</p><ul><li><strong>Azure Dev Tools |</strong> What are the core tools for working with Azure?</li><li><strong>Playwright |</strong> How can we implement end-to-end testing for our app?</li><li><strong>CI/CD|</strong> How can we automate build/deploy workflows?</li><li><strong>Edge DevTools</strong> How can we debug and profile apps in the browser?</li><li><strong>SWA CLI</strong> How can we simplify local development for static web apps?</li><li><strong>Visual Studio Code</strong> How can we supercharge our IDE-driven experience?</li></ul><p>In today's post we'll look at the main tools that make it easy for modern web application developers to build static web apps on Azure:</p><ul><li><a href="https://docs.microsoft.com/en-us/cli/azure/" target="_blank" rel="noopener noreferrer">Azure CLI</a> - a command-line interface to create and manage Azure resources</li><li><a href="https://docs.microsoft.com/en-us/azure/azure-portal/" target="_blank" rel="noopener noreferrer">Azure Portal</a> - a web-based unified console alternative to the Azure CLI.</li><li><a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer">Azure SWA CLI</a> - a <em>local development tool</em> for Azure Static Web Apps</li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local" target="_blank" rel="noopener noreferrer">Azure Functions Core Tools</a> - a <em>local development tool</em> for Azure Functions.</li><li><a href="https://code.visualstudio.com/docs/azure/extensions" target="_blank" rel="noopener noreferrer">Azure Extensions for Visual Studio Code</a> for seamless access from IDE.</li></ul><p>We'll coverAzure SWA CLI and VS Code extensions in greater detail later this week. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-to-azure">New to Azure?<a href="#new-to-azure" class="hash-link" aria-label="Direct link to New to Azure?" title="Direct link to New to Azure?">​</a></h2><p>We assume you are familiar with cloud computing concepts like resources, resource groups, subscriptions and services. If not, that's okay. Now's a good time to take a detour and explore <strong><a href="https://docs.microsoft.com/en-us/learn/paths/az-900-describe-cloud-concepts/" target="_blank" rel="noopener noreferrer">Azure Fundamentals</a></strong> - a 6-part learning series that will take you through the core concepts, services, solutions, security features, identity &amp; governance aspects, and cost management features available on Azure. </p><p>If you're a JavaScript or Node.js developer new to Azure, bookmark these links:</p><ul><li><a href="https://azure.github.io/azure-sdk/releases/latest/js.html" target="_blank" rel="noopener noreferrer">Azure SDKs</a> for service integrations in your preferred programming language.</li><li><a href="https://docs.microsoft.com/en-us/azure/developer/javascript/" target="_blank" rel="noopener noreferrer">Azure for JavaScript Developers</a> for guides and samples</li><li><a href="https://docs.microsoft.com/en-us/azure/developer/javascript/node-azure-tools" target="_blank" rel="noopener noreferrer">Tools for JS Developers on Azure</a> with <a href="https://docs.microsoft.com/en-us/azure/developer/javascript/core/configure-local-development-environment?tabs=bash" target="_blank" rel="noopener noreferrer">configuration tips</a></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="azure-cli">Azure CLI<a href="#azure-cli" class="hash-link" aria-label="Direct link to Azure CLI" title="Direct link to Azure CLI">​</a></h2><p>Now that you're familiar with core Azure concepts, let's talk about how you can <em>create and manage</em> your cloud resources on Azure. The <strong><a href="https://docs.microsoft.com/en-us/cli/azure/what-is-azure-cli" target="_blank" rel="noopener noreferrer">Azure CLI</a></strong> is a <em>cross-platform</em> command-line tool that connects you securely to Azure, to execute commands on Azure resources interactively (or via scripts) from a terminal.</p><p>The easiest way to familiarize yourself with the Azure CLI commands is to <a href="https://docs.microsoft.com/en-us/cli/azure/get-started-with-azure-cli#install-or-run-in-azure-cloud-shell" target="_blank" rel="noopener noreferrer">install and run it in Azure Cloud Shell</a> <strong>in your browser</strong> - no local installation needed. Follow <a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" target="_blank" rel="noopener noreferrer">these instructions</a> to then install it locally in your development environment. Validate your install by testing out the core <code>az</code> command.</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az --version</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>There Azure CLI can manage most Azure Services out of the box. Here is <strong><a href="https://docs.microsoft.com/en-us/cli/azure/azure-services-the-azure-cli-can-manage" target="_blank" rel="noopener noreferrer">list of supportred services</a></strong> along with links to quickstart documentation for each. As web developers, you may find the <strong><a href="https://docs.microsoft.com/en-us/cli/azure/azure-services-the-azure-cli-can-manage#web" target="_blank" rel="noopener noreferrer">web-related subset of services</a></strong> worth exploring - everything from App Service and API Management, to Azure Static Web Apps.</p><p>Use the following command to get interactive help with supported commands and options in this context.</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az staticwebapp --help</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>With the CLI you can manage app settings, create and delete static apps, manage the static app's environment and associated functions, oversee information related to identity, users and secrets associated with the app, and more.</p><ul><li>Explore the <strong><a href="https://docs.microsoft.com/en-us/cli/azure/staticwebapp?view=azure-cli-latest" target="_blank" rel="noopener noreferrer">az staticwebapp</a></strong> reference to learn relevant commands and options.</li><li>Then <strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">build your first static web app</a></strong> using the Azure CLI.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="azure-portal">Azure Portal<a href="#azure-portal" class="hash-link" aria-label="Direct link to Azure Portal" title="Direct link to Azure Portal">​</a></h2><p>If you prefer a unified web-based console for managing your Azure resource interactions, the <a href="https://docs.microsoft.com/en-us/azure/azure-portal/" target="_blank" rel="noopener noreferrer">Azure Portal</a> provides a <strong>graphical user interface alternative to the Azure CLI</strong>. The portal is designed for <em>continuous availability</em>. Here's a snapshot of what the Azure Portal layout looks like. Browse the following documents to get a deeper dive into its capabilities:</p><ul><li>Understand the <a href="https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-overview#getting-around-the-portal" target="_blank" rel="noopener noreferrer">components of the Azure Portal</a> in this document.</li><li>Then learn to <a href="https://docs.microsoft.com/en-us/learn/modules/tour-azure-portal/3-navigate-the-portal" target="_blank" rel="noopener noreferrer">navigate the portal</a> in this tutorial.</li><li>Or follow the <a href="https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-quickstart-center" target="_blank" rel="noopener noreferrer">Azure Quickstart Center</a> guided tour.</li></ul><p>Then, try to  <strong><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">build your first static web app</a></strong> using the Azure Portal to get hands-on experience with the developer workflow from creation to deployment.</p><p><img loading="lazy" src="https://docs.microsoft.com/en-us/learn/modules/tour-azure-portal/media/3-portal.png" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="functions-core-tools">Functions Core Tools<a href="#functions-core-tools" class="hash-link" aria-label="Direct link to Functions Core Tools" title="Direct link to Functions Core Tools">​</a></h2><p>Azure Static Web Apps uses <a href="https://docs.microsoft.com/en-us/azure/azure-functions/" target="_blank" rel="noopener noreferrer">Azure Functions</a> to support serverless API capability for the app. Learn more about this in our earlier post on <a href="/blog/api-enabling-swa">API-enabling SWA</a> where we talked about  <em>Managed Functions</em> (created and managed by Azure Static Web Apps) and <em>Bring Your Own Functions</em> (independently created and managed) options for adding serverless API support to your static web application.</p><p>The <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cmacos%2Ccsharp%2Cportal%2Cbash#install-the-azure-functions-core-tools" target="_blank" rel="noopener noreferrer">Azure Functions Core Tools</a> - aka <code>func</code> - supports <strong>local development</strong> with a command-line tool to create, test, and even deploy, your functions to Azure. Once installed, use the following to get interactive help with the supported commands and options for this tool:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">func --help</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>You should see something like this <strong>(some output abbreviated for clarity)</strong> giving you a sense of the main operations you can perform from this CLI.</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Azure Functions Core Tools</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Core Tools Version:       4.0.3971 ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Function Runtime Version: 4.0.1.16815</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Usage: func [context] [context] &lt;action&gt; [-/--options]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Contexts:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">azure       Commands to log in to Azure and manage resources</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">durable     Commands for working with Durable Functions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">extensions  Commands for installing extensions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">function    Commands for creating and running functions locally</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">host        Commands for running the Functions host locally</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">kubernetes  Commands for working with Kubernetes and Azure Functions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">settings    Commands for managing environment settings for the local Functions host</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">templates   Commands for listing available function templates</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Actions: </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">start   Launches the functions runtime host  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --port [-p]     Local port to listen on. </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    Default: 7071</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">..</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">..</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Explore the documentation to learn how you can:</p><ul><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local" target="_blank" rel="noopener noreferrer">Install the Azure Functions Core Tools</a></li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cmacos%2Ccsharp%2Cportal%2Cbash#create-a-local-functions-project" target="_blank" rel="noopener noreferrer">Create a local Functions project</a></li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cmacos%2Ccsharp%2Cportal%2Cbash#start" target="_blank" rel="noopener noreferrer">Run and test Functions locally</a></li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cmacos%2Ccsharp%2Cportal%2Cbash#publish" target="_blank" rel="noopener noreferrer">Publish Functions to Azure</a></li></ul><p>Later this week, we'll do a deep-dive into the <strong><a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer">Azure Static Web Apps CLI</a></strong> - a local development commandline tool for Azure Static Web Apps, that works seamlessly with the Azure Functions Core Tool, to deliver an unified developer experience for creating and testing your API-enabled Static Web Apps projects.</p><p>The combination of <strong>Azure CLI</strong> (to manage Azure resources from command line), <strong>Azure Functions Core Tools</strong> (to manage Azure Functions local development and deploy) and <strong>Azure Static Web Apps CLI</strong> (to manage SWA local development and deploy) provides a seamless command-line driven developer experience for web developers on Azure.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="azure-extensions">Azure Extensions<a href="#azure-extensions" class="hash-link" aria-label="Direct link to Azure Extensions" title="Direct link to Azure Extensions">​</a></h2><p>But what if you prefer an IDE-based approach? Visual Studio Code has you covered. In a post Later this week, we'll look in depth at the key Visual Studio Code Extensions you can use, to supercharge your developer experience from code to cloud, right inside the IDE. For now, I'll leave you with these resources:</p><ul><li>Read the <a href="https://code.visualstudio.com/docs/azure/extensions" target="_blank" rel="noopener noreferrer">Azure Extensions</a> documentation to learn how to find, and install, relevant extensions in VS Code.</li><li>Explore the <a href="https://code.visualstudio.com/docs/azure/deployment" target="_blank" rel="noopener noreferrer">Deploying Applications To Azure</a> page for hands-on tutorials for VS Code - including one for <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Azure Static Web Apps</a> and one for <a href="https://docs.microsoft.com/azure/javascript/tutorial-vscode-serverless-node-01" target="_blank" rel="noopener noreferrer">Azure Functions</a></li><li>Search the <a href="https://marketplace.visualstudio.com/search?term=Microsoft&amp;target=VSCode&amp;category=Azure&amp;sortBy=Relevance" target="_blank" rel="noopener noreferrer">VS Code Marketplace</a> for relevant extensions from both Microsoft and the broader developer community.</li></ul><p>Here is a snapshot of extensions currently published by <strong>Microsoft</strong> in the <strong>Azure</strong> category, sorted by <strong>Trending</strong> metrics. You can see the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">Azure Static Web Apps Extension</a> listed here -- we'll cover that in more detail in the final post of this week!</p><p><img loading="lazy" src="/assets/images/15-extensions-a89bcb9f9f2882e54a019d3219040785.png" width="1224" height="1014" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>Wow - we covered a lot today!! But don't worry about having to remember all of it. The goal was to raise awareness of <em>which</em> tool to use, <em>when</em>, and <em>why</em>. Your exercise today:</p><ul><li><p>pick either <strong>Azure Portal</strong> or <strong>Azure CLI</strong> documentation for Azure Static Web Apps, and familiarize yourself with the many commands, settings and options available. </p></li><li><p>Try the default quickstart for that option - then explore other commands with the deployed Static Web App to get a real sense of how this works.</p></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><ul><li><a href="https://docs.microsoft.com/en-us/cli/azure/" target="_blank" rel="noopener noreferrer">Azure CLI</a> documentation - with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Static Web Apps Quickstart</a></li><li><a href="https://docs.microsoft.com/en-us/azure/azure-portal/" target="_blank" rel="noopener noreferrer">Azure Portal</a> documentation - with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Static Web Apps Quickstart</a></li><li><a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer">Azure SWA CLI</a> documentation</li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local" target="_blank" rel="noopener noreferrer">Azure Functions Core Tools</a> documentation</li><li><a href="https://azure.github.io/azure-sdk/releases/latest/js.html" target="_blank" rel="noopener noreferrer">Azure SDKs</a> for JavaScript and other languages</li><li><a href="https://code.visualstudio.com/docs/azure/extensions" target="_blank" rel="noopener noreferrer">Azure Extensions for Visual Studio Code</a></li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>dev-tools</category>
        </item>
        <item>
            <title><![CDATA[#16: Test Automation with Playwright]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/devtools-playwright</link>
            <guid>https://www.azurestaticwebapps.dev/blog/devtools-playwright</guid>
            <pubDate>Tue, 17 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 3, Day 2 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 3, Day 2</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Yesterday we kicked off "Developer Tools" week by talking about the end-to-end developer experience associated with building modern web applications. Today we focus on a key segment - <strong>testing</strong>. Let's look at what test automation means for modern web applications, and how <a href="https://www.playwright.dev" target="_blank" rel="noopener noreferrer">Playwright</a> can help you automate end-to-end testing of your Azure Static Web App.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Test Automation for Modern Web Apps</li><li>What is Playwright?</li><li>Get Started With Playwright</li><li>Explore Playwright Tools</li><li>Use Playwright with SWA</li><li><strong>Exercise</strong>: Try the Tutorial with <strong>your</strong> deployed app.</li></ul><p><img loading="lazy" src="/assets/images/16-banner-4b5207bc5611f5472bf29b8cca5a60af.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="test-automation">Test Automation<a href="#test-automation" class="hash-link" aria-label="Direct link to Test Automation" title="Direct link to Test Automation">​</a></h2><p>Modern mobile web applications have to work correctly and consistently across all modern browsers (like Chromium, Firefox or WebKit) and the device platforms they run on (with varying screen sizes, orientations). Testing your application UI/UX <strong>manually</strong> becomes difficult when we think about the granularity of tests across these combinations. Testing manually becomes impossible when we factor in the frequency at which testing needs to be done to validate these on every code commit or pull request. This is where test automation shines!</p><p>Test Automation is about executing tests <strong>automatically</strong> to validate software specs, then using the reported insights to improve software quality iteratively. For web apps, this requires tools that can <em>automate test actions in the browser</em> (web automation) and support this consistently <em>across browsers</em>. <strong><a href="https://www.playwright.dev" target="_blank" rel="noopener noreferrer">This is where Playwright shines!</a></strong></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="playwright-overview">Playwright Overview<a href="#playwright-overview" class="hash-link" aria-label="Direct link to Playwright Overview" title="Direct link to Playwright Overview">​</a></h2><p>Playwright is an open-source framework for <strong>reliable</strong> end-to-end testing of modern web apps. It features a built-in <a href="https://playwright.dev/docs/1.21/intro" target="_blank" rel="noopener noreferrer">Playwright Test Runner</a> for automating test execution, and supports a <a href="https://playwright.dev/docs/1.21/library" target="_blank" rel="noopener noreferrer">Playwright Library</a> to simplify integration into third-party solutions.</p><p><img loading="lazy" alt="Visual Guide to Playwright" src="/assets/images/16-playwright-564feddda5d05dfe978b479e64bed2f2.jpg" width="3840" height="2160" class="img_ev3q"></p><p>This visual guide shows the key features of the framework (<a href="https://github.com/SketchTheDocs/cloud-skills/blob/main/gallery/Playwright-03-Overview.png" target="_blank" rel="noopener noreferrer">downloadable hi-res version here</a>) with these useful features:</p><ul><li><strong>Unified API</strong> - you write tests once, they run on all browsers and devices.</li><li><strong>Mobile Web Testing</strong> - rich set of device profiles, usable with native emulators.</li><li><strong>Multi-Language Support</strong> -  write tests in Java, JS/TS, Python or C#.</li><li><strong>Reliable Testing</strong> - no flaky tests thanks to auto-waiting and web-first assertions</li><li><strong>Powerful Tooling</strong> - get help authoring, debugging, profiling, and reporting, tests.</li><li><strong>Full Isolation</strong> - browser contexts (in just ms), options to parallelize tests</li></ul><p>Check out the Playwright <a href="https://playwright.dev/docs/1.21/intro" target="_blank" rel="noopener noreferrer">documentation</a> and <a href="https://playwright.dev/docs/1.21/api/class-playwright" target="_blank" rel="noopener noreferrer">API</a> for more details. </p><p><strong>What kinds of things can we test with Playwright?</strong> </p><ul><li>Test if UI component behaviors work as expected (events)</li><li>Test if UI workflows are correct (navigation, inputs)</li><li>Test UX behaviors in different contexts (with fixtures)</li><li>Modify network traffic (auth, proxy etc.) for testing</li><li>Validate behaviors under network conditions (modified)</li><li>Validate behaviors for device contexts (emulated profiles)</li><li>Automate capture of evidence (videos, screenshots) in tests</li></ul><p>Explore the <strong><a href="https://playwright.dev/docs/1.21/library" target="_blank" rel="noopener noreferrer">Guides</a></strong> and <strong><a href="https://github.com/MarcusFelling/Demo.Playwright#run-playwright-example-tests" target="_blank" rel="noopener noreferrer">Demo.Playwright</a></strong> for usage examples. And check out <strong><a href="https://dev.to/debs_obrien/series/17445" target="_blank" rel="noopener noreferrer">Debbie's playwright-testing</a></strong> series for more examples of Playwright in action.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="playwright-quickstart">Playwright Quickstart<a href="#playwright-quickstart" class="hash-link" aria-label="Direct link to Playwright Quickstart" title="Direct link to Playwright Quickstart">​</a></h2><p>It's time to get some hands-on experience with Playwright. Check out the <a href="https://playwright.dev/docs/1.21/intro" target="_blank" rel="noopener noreferrer">Getting Started</a> guide on their site for reference. </p><p>However, we'd like to walkthrough it with a real-world example in mind and figure out how to go from the boilerplate setup to the start of a basic script and configuration that sets us up to do more for testing our Azure Static App.</p><p><strong>#30DaysOfSWA Website Example: Step-by-Step Tutorial</strong>: </p><p>Check out <a href="https://github.com/fearlessly-dev/30daysofSWA-testing" target="_blank" rel="noopener noreferrer">this repository</a> that I setup today, to use the quickstart guide as a basis for setting up end-to-end testing for the <a href="https://aka.ms/30DaysOfSWA" target="_blank" rel="noopener noreferrer">#30DaysOfSWA</a> website! The <a href="https://github.com/fearlessly-dev/30daysofSWA-testing" target="_blank" rel="noopener noreferrer">README</a> documents the following steps in detail:</p><ul><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing#2-where-should-my-tests-be" target="_blank" rel="noopener noreferrer">Setup Testing Repo</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing#3-how-do-i-install-playwright" target="_blank" rel="noopener noreferrer">Install Playwright</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing#4-what-did-the-installation-do" target="_blank" rel="noopener noreferrer">Explore Boilerplate (setup)</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing#5-what-can-i-do-with-this" target="_blank" rel="noopener noreferrer">Run Default Test</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing#6-what-does-the-report-show" target="_blank" rel="noopener noreferrer">View Generated Test Report</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing#7-what-about-those-github-actions" target="_blank" rel="noopener noreferrer">Automate Tests with GitHub Actions</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing#8-viewing-actions-generated-reports" target="_blank" rel="noopener noreferrer">View Actions-Generated Report Assets</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing/blob/main/README.md#9-lets-customize-the-script" target="_blank" rel="noopener noreferrer">Customize Default Script/Config for <em>My</em> App</a></li><li><a href="https://github.com/fearlessly-dev/30daysofSWA-testing/blob/main/README.md#the-joys-of-trace-logs" target="_blank" rel="noopener noreferrer">The Joy Of Trace Logs!!</a></li><li><strong>You Did It!</strong></li></ul><p>By the end of this tutorial you should have:</p><ul><li>A starter test script customized for <strong>your</strong> application</li><li>A test configuration file <strong>with tracing on</strong> to capture detailed profiling data</li><li>A GitHub Actions workflow that <strong>automates test runs</strong> with each codebase change.</li></ul><p><img loading="lazy" src="https://github.com/fearlessly-dev/30daysofSWA-testing/raw/main/my-report-detail.png" alt="Test Run Report" class="img_ev3q"></p><p>At this point, you are now ready to build on this:</p><ul><li>add more tests to your <code>example.spec.js</code> file =&gt; <strong>see: <a href="https://playwright.dev/docs/test-annotations" target="_blank" rel="noopener noreferrer">Playwright Test API</a></strong></li><li>configure your test run in <code>playwright.config.js</code>. =&gt; <strong>see:<a href="https://playwright.dev/docs/test-configuration" target="_blank" rel="noopener noreferrer">Configuration Object</a></strong></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="playwright-tooling">Playwright Tooling<a href="#playwright-tooling" class="hash-link" aria-label="Direct link to Playwright Tooling" title="Direct link to Playwright Tooling">​</a></h2><p>In the tutorial above, we mentioned some Playwright tools (CLI, TraceViewer, HTML Reporter, Codegen) in passing. Playwright has a really powerful set of tools that can streamline your end-to-end testing experience from <em>authoring</em> to <em>reporting</em>. </p><p><strong>Start by familiarizing yourself with the <a href="https://playwright.dev/docs/cli" target="_blank" rel="noopener noreferrer">Playwright CLI</a></strong>. </p><p>It's the main launching pad for all other command-line utilities. Using the CLI you can navigate to pages (<em>"open"</em>), install browser dependencies (<em>"install"</em>), take screenshots (<em> "screenshot"</em>), launch the test runner (<em>"test"</em>), author tests (<em>"codegen"</em>), view traces (<em>"show-trace"</em>) and more. </p><p>Launch the CLI as follows:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npx playwright &lt;command&gt; [options]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Use <code>npx playwright --help</code> for details on commands and options supported in your installed CLI version. Want a deeper dive?</p><ul><li>Check out Nitya's <strong><a href="https://dev.to/azure/005-tool-talk-hello-command-line-faj" target="_blank" rel="noopener noreferrer">Tool Talk Post</a></strong> for detailed coverage.</li><li>Download this handy <strong><a href="https://cloud-skills.dev/gallery/Playwright-01-CommandLine.png" target="_blank" rel="noopener noreferrer">hi-res visual guide</a></strong> as a cheatsheet</li></ul><p><strong>Usage Example</strong>: </p><p>Let's use the <code>screenshot</code> command to capture an image of the kickoff post from the #30DaysOfSWA website for an "iPhone 6" device profile. You can see the <a href="https://github.com/microsoft/playwright/blob/f1307f4a4d92490d7d0e7ee5a6a7fe9a22804e86/packages/playwright-core/src/server/deviceDescriptorsSource.json" target="_blank" rel="noopener noreferrer">named device profiles</a> currently supported for reference.</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npx playwright screenshot --device "iPhone 6" https://www.azurestaticwebapps.dev/blog/kickoff 30Days.png</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Navigating to https://www.azurestaticwebapps.dev/blog/kickoff</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Capturing screenshot into 30Days.png</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><table><thead><tr><th align="left"><strong>Result:</strong> This is what the saved image looks like.</th></tr></thead><tbody><tr><td align="left"><img loading="lazy" alt="Screenshot" src="/assets/images/30Days-35c58c6fb6d68f4828961abf4865a1b9.png" width="750" height="1334" class="img_ev3q"></td></tr></tbody></table><p><strong>Then start exploring these tools</strong>: </p><ul><li><a href="https://playwright.dev/docs/inspector" target="_blank" rel="noopener noreferrer">Inspector</a> - a GUI-based tool for debugging test execution</li><li><a href="https://playwright.dev/docs/trace-viewer" target="_blank" rel="noopener noreferrer">TraceViewer</a> - a GUI-based tool to explore recorded test traces</li><li><a href="https://playwright.dev/docs/codegen" target="_blank" rel="noopener noreferrer">Codegen</a> - an authoring tool to generate tests based on user interactions</li><li><a href="https://playwright.dev/docs/debug" target="_blank" rel="noopener noreferrer">Debugging</a> - additional tools to support runtime debugging</li><li><a href="https://playwright.dev/docs/test-reporters" target="_blank" rel="noopener noreferrer">Reporters</a> - built-in reporters of different types</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="whats-next">What's Next<a href="#whats-next" class="hash-link" aria-label="Direct link to What's Next" title="Direct link to What's Next">​</a></h2><p>We covered a lot today. </p><p>At this point, you should know what Playwright its, and why it's useful for automating tests for  modern web applications. You should have a sense of the powerful developer tools it has, and understand how to setup and configure it for use with your Azure Static Web App. And you should have a clean basis for building up your test suite.</p><p>So where can we go next to skill up? We have you covered:</p><ul><li><p><strong><a href="https://github.com/fearlessly-dev/30daysofSWA-testing" target="_blank" rel="noopener noreferrer">Watch this repository</a></strong> I setup today. I hope to continue adding more tests that can walk through various Playwright features with a deployed SWA,, and use that to explore both the Playwright capabilities and SWA-specific features or usage.</p></li><li><p><strong>Join us tomorrow</strong> when we explore a "Multi-Stage Deployment with Azure DevOps" demo that shows you a full-stack application with Playwright tests integrated. Learn interesting aspects - like using SWA environment variables to define test parameters - that highlight best practices for test setup in SWA.</p></li><li><p><strong>Last but not least</strong>, check out this talk from last year for more insights into End-to-End Testing for Playwright from the Azure Static Web Apps Team.</p><iframe width="560" height="315" frameborder="0" src="https://aka.ms/docs/player?ev=learn-tv-static-web-apps-code-to-scale&amp;session=end-to-end-testing-with-playwright"></iframe></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>Pick one of the apps you've built (or use) - preferably one that is currently deployed to Azure Static Web Apps so you can explore other scenarios later.</p><p><a href="https://github.com/fearlessly-dev/30daysofSWA-testing" target="_blank" rel="noopener noreferrer">Walk through the same steps</a> with <strong>your</strong> deployed app - then try adding one new test script that goes beyond the starter test case. Look at the <a href="https://github.com/MarcusFelling/Demo.Playwright" target="_blank" rel="noopener noreferrer">demo</a> project for inspiration!</p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>dev-tools</category>
            <category>playwright</category>
        </item>
        <item>
            <title><![CDATA[#17: Multi-Stage Deploy with ADO]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/devtools-ado</link>
            <guid>https://www.azurestaticwebapps.dev/blog/devtools-ado</guid>
            <pubDate>Wed, 18 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 3, Day 3 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 3, Day 3</code> of <strong>#30DaysOfSWA</strong>!! </p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>From Microsoft Tech Community</div><div class="admonitionContent_S0QG"><p>Check out the canonical version of this post on the <strong><a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/multi-stage-azure-static-web-apps-deployments-with-azure-devops/ba-p/3390625" target="_blank" rel="noopener noreferrer">Apps On Azure</a></strong> Tech Community Blog along with other articles on the topic of <strong><a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/bg-p/AppsonAzureBlog/label-name/Web%20Apps" target="_blank" rel="noopener noreferrer">Web Apps</a></strong></p></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Build SWA with Azure Functions API + Playwright Tests</li><li>Deploy SWA to staging environment</li><li>Automate validation of staged app with Playwright</li><li>Wait for manual approval</li><li>Deploy to production</li><li><strong>Exercise.</strong> Explore the <a href="https://github.com/anthonychu/swa-devops-pipeline-demo" target="_blank" rel="noopener noreferrer">Demo Application Source</a> and try it out!</li></ul><p><img loading="lazy" src="/assets/images/17-banner-2d8ecefdc1683370295255b3fa8a0df3.png" width="1000" height="420" class="img_ev3q"></p><p>Azure Static Web Apps recently introduced the ability to automatically configure an Azure DevOps pipeline to build and deploy your app. It's a great way to get your app up and running quickly.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/4JkfeZp7aDk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe><p>For production applications, it's common to first deploy an app to staging environment(s) prior to deploying to production. In this article, we'll walk through how to configure a robust Azure DevOps pipeline that will:</p><ul><li>Build an app, Azure Functions API, and Playwright tests</li><li>Deploy the app to a staging environment</li><li>Automatically validate the staging app with the Playwright tests</li><li>Wait for a manual approval</li><li>Deploy your app to production</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="sample-application">Sample application<a href="#sample-application" class="hash-link" aria-label="Direct link to Sample application" title="Direct link to Sample application">​</a></h2><p>We'll use a .NET 6 full-stack application. </p><ul><li>Frontend: Blazor WebAssembly</li><li>Backend: Azure Functions</li><li>Tests: Playwright</li></ul><p>To follow along, import the repository into your Azure DevOps project. You can use similar steps for a Node.js app.</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span><mdxadmonitiontitle><strong>Source Code Available</strong></mdxadmonitiontitle></div><div class="admonitionContent_S0QG"><p>Check out the code at: <strong><a href="https://github.com/anthonychu/swa-devops-pipeline-demo" target="_blank" rel="noopener noreferrer">@anthonychu/swa-devops-pipeline-demo</a></strong>.</p></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="create-a-static-web-app-and-deployment-pipeline">Create a static web app and deployment pipeline<a href="#create-a-static-web-app-and-deployment-pipeline" class="hash-link" aria-label="Direct link to Create a static web app and deployment pipeline" title="Direct link to Create a static web app and deployment pipeline">​</a></h2><p>Recently, Azure Static Web Apps added the ability to <a href="https://docs.microsoft.com/azure/static-web-apps/get-started-portal?pivots=azure-devops" target="_blank" rel="noopener noreferrer">generate an Azure DevOps pipeline</a> to deploy your app.</p><p>You can create a static web app and the deployment pipeline in a single step.</p><ol><li><p>In the Azure portal, search for and create a new static web app.</p></li><li><p>During the creation process, select "Azure DevOps" as the deployment source and select the DevOps repository and branch that contains the app.</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168908827-22dd512a-cec7-4e27-aca4-993428f2a03e.png" alt="Create an app with Azure DevOps" class="img_ev3q"></p></li><li><p>In the build presets, select "Blazor". The pre-populates the app and API folder locations.</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168909032-b817a631-6e74-4739-8c4a-1ff480f955a3.png" alt="Select Blazor preset" class="img_ev3q"></p></li></ol><p>When you create the app, a new pipeline YAML file will be created in the repository. It'll automatically run. It takes a few minutes to build and deploy the app.</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168909383-0d275e2f-15ae-40e8-aa2d-56a208f7a6f4.png" alt="Location of the generated build pipeline YAML file" class="img_ev3q"></p><p>Open the pipeline YAML file in your browser or locally in an editor to see its contents. It contains a single <code>AzureStaticWebApp</code> task that automatically builds and deploys the app.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="create-azure-pipelines-environments">Create Azure Pipelines environments<a href="#create-azure-pipelines-environments" class="hash-link" aria-label="Direct link to Create Azure Pipelines environments" title="Direct link to Create Azure Pipelines environments">​</a></h2><p>Azure Pipelines allows you to define environments. Environments are useful for adding manual approvals to your pipeline.</p><p>We'll create two environments — Staging and Production. They'll correspond to the two Azure Static Web Apps environments we'll deploy to.</p><p>To create a Pipelines environment, select "Environments" under Pipelines.</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168909775-61e3e243-c298-4fcf-a5ba-8af0a94a7a5d.png" alt="Open environments" class="img_ev3q"></p><p>Create one named "Staging". Because you don't need a manual approval for this stage, you don't to configure anything else.</p><p>Next, create a new environment named "Production". Because we want to require a manual approval before deploying to production, you can configure the environment to require a manual approval.</p><ol><li><p>In the environment's "Approvals and checks", select "Approvals".</p></li><li><p>Add yourself as an approver and create the approval policy.</p></li></ol><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168910157-d32f767f-c608-4047-b0f5-66b7e4beb2f2.png" alt="Create an approval policy" class="img_ev3q"></p><p>The pipeline you'll update later will reference these environments.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="protect-azure-static-web-apps-environments-with-a-password">Protect Azure Static Web Apps environments with a password<a href="#protect-azure-static-web-apps-environments-with-a-password" class="hash-link" aria-label="Direct link to Protect Azure Static Web Apps environments with a password" title="Direct link to Protect Azure Static Web Apps environments with a password">​</a></h2><p>Azure Static Web Apps provides preview environments to let you test out your app before deploying to production.</p><p>Preview environments were intially available for pull requests in GitHub. Recently, Static Web Apps introduced the ability to arbitrary define <a href="https://docs.microsoft.com/azure/static-web-apps/named-environments" target="_blank" rel="noopener noreferrer">named preview environments</a>. For instance, we can create an environment named "Staging".</p><p>Preview environments are public by default. This is great for open source projects, but sometimes we want to protect them from public access.</p><p>You can add password protection to your app's preview environments.</p><ol><li><p>In the Azure portal, open your static web app.</p></li><li><p>In "Configuration", select the "General settings" tab.</p></li><li><p>Select "Protect staging environments only" and enter a password.</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168910485-02aacade-3961-41fd-aa9c-54cd14df5aab.png" alt="Protect staging environments only" class="img_ev3q"></p></li></ol><p>You also have the option to protect all environments. But in this app, we want the production environment to be accessible to the public.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="configure-the-multi-stage-pipeline">Configure the multi-stage pipeline<a href="#configure-the-multi-stage-pipeline" class="hash-link" aria-label="Direct link to Configure the multi-stage pipeline" title="Direct link to Configure the multi-stage pipeline">​</a></h2><p>Now that we've configured the Azure Pipelines environments and password protection, we can configure the pipeline.</p><p>Open the pipeline YAML file in your browser or locally in an editor. Replace its contents the contents of <a href="https://github.com/anthonychu/swa-devops-pipeline-demo/blob/main/azure-pipelines.yml" target="_blank" rel="noopener noreferrer">this file</a>.</p><p>We'll walk through the different parts of the pipeline. It has 3 main stages: build, deploy to staging, and deploy to production.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="stage-1-build-the-app">Stage 1: build the app<a href="#stage-1-build-the-app" class="hash-link" aria-label="Direct link to Stage 1: build the app" title="Direct link to Stage 1: build the app">​</a></h3><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">trigger</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">pool</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">vmImage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">stages</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">jobs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">job</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> UseDotNet@2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Install .NET SDK</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">packageType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'sdk'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'6.0.x'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        dotnet publish -c Release -o "$(Build.ArtifactStagingDirectory)/frontend"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build Blazor frontend</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">workingDirectory</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(System.DefaultWorkingDirectory)/Client</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        dotnet publish -c Release -o "$(Build.ArtifactStagingDirectory)/api"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build Azure Functions API</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">workingDirectory</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(System.DefaultWorkingDirectory)/Api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        dotnet build -c Release -o "$(Build.ArtifactStagingDirectory)/tests"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Build Playwright tests</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">workingDirectory</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(System.DefaultWorkingDirectory)/PlaywrightTests</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> PublishBuildArtifacts@1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Publish artifacts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">PathtoPublish</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'$(Build.ArtifactStagingDirectory)'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">ArtifactName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'drop'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">publishLocation</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Container'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>The pipeline triggers on any changes to the <code>main</code> branch. If your app uses a different branch, you can change it.</p><p>The pipeline then builds the app, Azure Functions API, and Playwright tests. It then outputs the artifacts. The same build artifacts are deployed to all environments. This ensures that the app you tested in other environments is the same one you're deploying to production.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="stage-2-deploy-to-staging-and-run-playwright-tests">Stage 2: deploy to staging and run Playwright tests<a href="#stage-2-deploy-to-staging-and-run-playwright-tests" class="hash-link" aria-label="Direct link to Stage 2: deploy to staging and run Playwright tests" title="Direct link to Stage 2: deploy to staging and run Playwright tests">​</a></h3><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> deploy_staging</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy to staging</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">jobs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">deployment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy and test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">environment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Staging</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">variables</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic"># Change the variable group name to match the one in the generated pipeline</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">group</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Azure</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">Static</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">Web</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">Apps</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">calm</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">coast</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">0df39b910</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">variable</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">group</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">strategy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">runOnce</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">deploy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">download</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> none</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">checkout</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> none</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DownloadBuildArtifacts@1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Download artifacts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">buildType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> current</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">downloadType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> single</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">artifactName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> drop</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">downloadPath</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(System.ArtifactsDirectory)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> AzureStaticWebApp@0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy to staging environment</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">app_location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> frontend/wwwroot</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">api_location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">skip_app_build</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">skip_api_build</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">verbose</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">azure_static_web_apps_api_token</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(AZURE_STATIC_WEB_APPS_API_TOKEN_CALM_COAST_0DF39B910)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">deployment_environment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> staging</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">workingDirectory</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(System.ArtifactsDirectory)/drop</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> UseDotNet@2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Install .NET SDK</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">packageType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'sdk'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'6.0.x'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">                chmod -R a+x $(System.ArtifactsDirectory)/drop/tests</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">                sudo --preserve-env=PLAYWRIGHT_BROWSERS_PATH pwsh $(System.ArtifactsDirectory)/drop/tests/playwright.ps1 install --with-deps chromium</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">                dotnet test $(System.ArtifactsDirectory)/drop/tests/PlaywrightTests.dll --logger trx</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Run Playwright tests on staging app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">env</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">PLAYWRIGHT_BROWSERS_PATH</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(Build.SourcesDirectory)/browsers</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">LOGIN_PASSWORD</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(LOGIN_PASSWORD)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> PublishTestResults@2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">condition</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> succeededOrFailed()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">testRunner</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> VSTest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token key atrule" style="color:#00a4db">testResultsFiles</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'**/*.trx'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>This is the most complex stage. Note that it references the "Staging" environment we created in the Azure Pipeline. It also references the variable group that was automatically generated when the static web app was first created. Change its name to match the variable group in the generated pipeline.</p><p>This stage starts by downloading the artifacts from the build stage.</p><p>Next, it uses the <code>AzureStaticWebApp</code> task to deploy the app to the staging environment.</p><ul><li><code>skip_app_build</code> and <code>skip_api_build</code> are set to <code>true</code> because the app and API artifacts were already built and don't need to be built again.</li><li><code>deployment_environment</code> is set to <code>staging</code> because we want to deploy to the staging environment.</li></ul><p>After the app is deployed, the pipeline installs the .NET SDK and runs a script that installs the required dependencies for Playwright. Playwright is a testing framework that automates running tests in a browser.</p><p>After the dependencies are installed, the script runs the Playwright tests using the <code>dotnet test</code> command.</p><p>One thing to note is that we need to configure a secret variable named <code>LOGIN_PASSWORD</code>. This is the password that the user will enter when they log into the staging environment. The Playwright tests will use this password to log in when it runs tests on the staging environment.</p><p>The last step in the stage publishes the test results.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="stage-3-deploy-to-production">Stage 3: deploy to production<a href="#stage-3-deploy-to-production" class="hash-link" aria-label="Direct link to Stage 3: deploy to production" title="Direct link to Stage 3: deploy to production">​</a></h3><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> deploy_production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy to production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">jobs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">deployment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">environment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">variables</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Change the variable group name to match the one in the generated pipeline</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">group</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Azure</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">Static</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">Web</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">Apps</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">calm</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">coast</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">0df39b910</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">variable</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">group</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">strategy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">runOnce</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">deploy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">steps</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">download</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> none</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">checkout</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> none</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DownloadBuildArtifacts@1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Download artifacts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">buildType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> current</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">downloadType</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> single</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">artifactName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> drop</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">downloadPath</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(System.ArtifactsDirectory)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">task</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> AzureStaticWebApp@0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">displayName</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Deploy to production environment</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">inputs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">app_location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> frontend/wwwroot</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">api_location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">skip_app_build</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">skip_api_build</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">verbose</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">azure_static_web_apps_api_token</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(AZURE_STATIC_WEB_APPS_API_TOKEN_CALM_COAST_0DF39B910)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token key atrule" style="color:#00a4db">workingDirectory</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $(System.ArtifactsDirectory)/drop</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>This stage references the "Production" environment in the Azure Pipeline. Because we configured this environment to require approval, this will trigger a manual approval step before this stage is run.</p><p>Like the previous stage, this stage downloads the artifacts and deploys them with the <code>AzureStaticWebApp</code> task. This time, no <code>deployment_environment</code> is set because we want to deploy to the production environment of the static web app.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="run-the-multi-stage-pipeline">Run the multi-stage pipeline<a href="#run-the-multi-stage-pipeline" class="hash-link" aria-label="Direct link to Run the multi-stage pipeline" title="Direct link to Run the multi-stage pipeline">​</a></h2><p>Now that the pipeline is set up, you can run it by saving the file. If you edited it locally, don't forget to push it to your Azure DevOps repo.</p><p>After the "Deploy to staging" stage is run, you should see that the Playwright tests have been run to validate the staging environment and the results are published.</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168911185-3eea2e66-0aaf-4a86-af65-956618abc6d3.png" alt="Test results" class="img_ev3q"></p><p>The pipeline run is paused because the "Deploy to production" stage requires an approval. </p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168912243-6450a5fa-6e95-4ac8-8f65-b1a7bc8d3e6b.png" alt="Approval step" class="img_ev3q"></p><p>When you approve the pipeline, the pipeline will run again.</p><p>After approval, the app is deployed to production.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-closer-look">A closer look<a href="#a-closer-look" class="hash-link" aria-label="Direct link to A closer look" title="Direct link to A closer look">​</a></h2><p>Before we end this article, we want to dive a bit deeper into the Static Web Apps environments and the Playwright tests.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="azure-static-web-apps-environments">Azure Static Web Apps environments<a href="#azure-static-web-apps-environments" class="hash-link" aria-label="Direct link to Azure Static Web Apps environments" title="Direct link to Azure Static Web Apps environments">​</a></h3><p>To see the environments you've created, click your static web app's "Environments" tab in the Azure portal. You should see the production and staging environments.</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/3982077/168911293-571d1057-c36b-4ff2-88df-3cdf20154318.png" alt="Static Web Apps Environments" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="playwright-tests">Playwright tests<a href="#playwright-tests" class="hash-link" aria-label="Direct link to Playwright tests" title="Direct link to Playwright tests">​</a></h3><p>The Playwright tests are located in the <code>PlaywrightTests</code> project and they're written in C#.</p><p><a href="https://playwright.dev" target="_blank" rel="noopener noreferrer">Playwright</a> can be used to automate testing of web apps using real browsers. The tests in the example use Chrome (Chromium), but Playwright also supports Firefox, WebKit, and Microsoft Edge.</p><p>This is an example of a Playwright test in C#. It navigates the browser to the app's homepage, clicks on the "Fetch data" link, and confirms that the data is fetched from the backend API and it is rendered successfully.</p><div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[Test]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public async Task ShouldLoadWeather()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    await using var browser = await Playwright.Chromium.LaunchAsync();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var page = await browser.NewPageAsync();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    await GoToHomePage(page);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    await page.ClickAsync("a[href='fetchdata']");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var h1 = await page.QuerySelectorAsync("div#app main h1");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var h1Text = h1 == null ? "" : await h1.TextContentAsync();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Assert.AreEqual("Weather forecast", h1Text);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var rowsSelector = "div#app main table tbody tr";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // wait for table to have rows</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    await page.WaitForFunctionAsync($"document.querySelectorAll('{rowsSelector}').length");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var rows = await page.QuerySelectorAllAsync(rowsSelector);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Assert.AreEqual(5, rows.Count);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>The tests use the <code>AZURESTATICWEBAPP_STATIC_WEB_APP_URL</code> environment variable to determine the URL of the app to test. In an Azure Pipeline, this variable is set by the Azure Static Web Apps task after a successful deployment. Because the tests run in the pipeline after a deployment to the staging environment, the variable contains the URL of the staging Static Web Apps environment.</p><p>Another interesting aspect of the tests is the following code for navigating to the homepage:</p><div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">private async Task GoToHomePage(IPage page)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    await page.GotoAsync($"{siteBaseUrl}/");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var homePageLocatorTask = page.Locator("text=Hello, world!").WaitForAsync();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var passwordPageLocatorTask = page.Locator("text=Password protected").WaitForAsync();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    var isPasswordPage = (await Task.WhenAny(homePageLocatorTask, passwordPageLocatorTask)) == passwordPageLocatorTask;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if (isPasswordPage)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        System.Console.WriteLine("Found password page, logging in...");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        var passwordInput = await page.QuerySelectorAsync("input[type=password]");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (passwordInput == null)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            throw new Exception("Could not find password input");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        await passwordInput.TypeAsync(sitePassword);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        await page.ClickAsync("button");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        await page.Locator("text=Hello, world!").WaitForAsync();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>This code automatically logs in to the staging environment if the browser session is unauthenticated. At run-time, the <code>sitePassword</code> variable is set to the value of the <code>LOGIN_PASSWORD</code> secret variable.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2><p>With the addition of features like named preview environments and automatic pipeline generation, it's now possible to configure complex, robust pipelines for building and deploying to Azure Static Web Apps from Azure DevOps.</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>The demo uses a .NET 6 full-stack application with a Blazor WebAssembly frontend, an Azure Functions backend, and integrated Playwright tests. </p><ul><li>Explore <a href="https://github.com/anthonychu/swa-devops-pipeline-demo" target="_blank" rel="noopener noreferrer">the source code here</a>.</li><li>Import the repository into your Azure DevOps project and follow the tutorial.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><ul><li><a href="https://youtu.be/4JkfeZp7aDk" target="_blank" rel="noopener noreferrer">Video</a>: Multi-environment deployments with Azure DevOps &amp; SWA</li><li><a href="https://github.com/anthonychu/swa-devops-pipeline-demo" target="_blank" rel="noopener noreferrer">Repo</a> with source code for demo</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>dev-tools</category>
        </item>
        <item>
            <title><![CDATA[#18: Debug with Edge DevTools]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/devtools-msedge</link>
            <guid>https://www.azurestaticwebapps.dev/blog/devtools-msedge</guid>
            <pubDate>Thu, 19 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn to use Microsoft Edge DevTools and its VS Code Extension to debug you Azure Static Web App and improve performance and accessibility]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 3, Day 4</code> of <strong>#30DaysOfSWA</strong>!!</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>GLOBAL ACCESSIBILITY AWARENESS DAY</div><div class="admonitionContent_S0QG"><p>Did you know today is <a href="https://accessibility.day/" target="_blank" rel="noopener noreferrer">Global Accessibility Awareness Day</a> - a day where we think about <strong>digital accessibility</strong> and what it means to make the web experience inclusive and friendly to everyone! </p><p>Visit the <a href="https://docs.microsoft.com/en-us/microsoft-edge/accessibility/" target="_blank" rel="noopener noreferrer">Accessbility in Microsoft Edge</a> documentation to learn best practices around designing, building, and testing, your modern websites for accessibility.</p></div></div><p>As we'll learn in a post later this week (stay tuned!), using the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">Azure Static Web Apps extension for VS Code</a> makes it quick to create and manage your Web Apps directly from VS Code.
<em>But what about the other aspects of your developer experience - like debugging your web app or profiling its performance in the browser?</em></p><p><strong>As a web developer, it's important to minimize context switching.</strong> </p><p>The fewer tools you need to use to do your job, the better. This way you can stay focused on the tasks at hand more easily, without having to constantly deal with multiple tools and windows on your computer. You become more productive when the tools you rely on work better together.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Getting started with the <strong>Edge DevTools</strong> VS Code extension</li><li>Seamless <strong>debugging</strong> experiences for your front-end app.</li><li>Discovering some of the DevTools <strong>accessibility</strong> tools.</li><li>Discovering some of the DevTools <strong>performance improvement</strong> tools.</li><li><strong>Exercise:</strong> Install the Edge DevTools VSCode Extension and try these features out!</li></ul><p><img loading="lazy" src="/assets/images/18-banner-3c83eb95b9d1aabe5f27d4282c5423ad.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="debug-front-end-code-from-vs-code">Debug front-end code from VS Code<a href="#debug-front-end-code-from-vs-code" class="hash-link" aria-label="Direct link to Debug front-end code from VS Code" title="Direct link to Debug front-end code from VS Code">​</a></h2><p>After you've created your SWA and have started adding more functionality to it, there will come a time when debugging your front-end code may become useful. Maybe you've added some JavaScript front-end logic that needs debugging, or maybe you've added new CSS layout code that needs inspecting.</p><p>The DevTools built in to your favorite browser come in very handy at this point. But, having to switch between your source files in your editor and your browser window to do the debugging can quickly become frustrating. It's also prone to errors as there aren't great solutions to move the tweaks you do in DevTools back to your editor.</p><p>One tool that can help a lot here is the <strong><a href="https://marketplace.visualstudio.com/items?itemName=ms-edgedevtools.vscode-edge-devtools" target="_blank" rel="noopener noreferrer">Microsoft Edge Developer Tools extension for VS Code</a></strong>. This extension gives you DevTools in VS Code directly.</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Edge DevTools For Visual Studio Code v2 Just Released!</div><div class="admonitionContent_S0QG"><p><a href="https://dev.to/codepo8/edge-devtools-for-visual-studio-code-v2-1bp3" target="_blank" rel="noopener noreferrer"><strong>Read this post</strong></a> to learn about improvements and new features like <em>Screencast with emulation support</em>, <em>Sourcemap support for styles</em> and more!</p></div></div><p>With this extension, the <strong>Elements</strong> and <strong>Network</strong> are embedded directly within VS Code, your <strong>Console</strong> messages appear in the VS Code console, issues detected by the Edge <strong>Issues</strong> panel are highlighted in your source code directly, and you get a live preview of your web app's front-end right in VS Code!</p><p>Finally, as you tweak your CSS code from within the <strong>Styles</strong> panel, your changes are automatically applied to your source files, even if you use a CSS pre-processor.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="get-started-with-edge-devtools-vs-code-extension">Get started with Edge DevTools VS Code extension<a href="#get-started-with-edge-devtools-vs-code-extension" class="hash-link" aria-label="Direct link to Get started with Edge DevTools VS Code extension" title="Direct link to Get started with Edge DevTools VS Code extension">​</a></h3><p>First let's install the extension, right from VS Code.</p><ol><li>In VS Code, open the <strong>Extensions</strong> sidebar, and search for "Edge Tools".</li><li>The <strong>Microsoft Edge Tools for VS Code</strong> extension should be listed. Click the <strong>Install</strong> button and wait for the process to end.</li></ol><p><img loading="lazy" alt="Screenshot of VSCode showing the Extensions sidebar with the Edge Tools for VS Code extension displayed" src="/assets/images/install-eba204081ea1bd94c4a0ac2ba5b45e26.png" width="1300" height="654" class="img_ev3q"></p><p>Once installed, the extension appears as a new icon in the <strong>Activity bar</strong> which gives you access to useful features. Let's jump straight in and make use of the most useful feature: generating a <code>launch.json</code> configuration file for your project.</p><ol><li>Click the <strong>Microsoft Edge Tools</strong> extension icon in the <strong>Activity bar</strong>.</li><li>Click <strong>Generate launch.json</strong>. A file appears in VS Code with some useful configuration details we can tweak.</li></ol><p><img loading="lazy" alt="Screenshot of VSCode showing the Edge Tools sidebar with the button to generate a launch json file and the file created next to it" src="/assets/images/launchjson-7d85ad6f0d91eefcffc051f20c8f37fd.png" width="1400" height="640" class="img_ev3q"></p><p>The most important configuration you should change now is the <code>url</code> and perhaps add a <code>preLaunchTask</code> if you need to.</p><p>I'll use my blog to illustrate the changes here. In this project, I have a build task configured that generates the HTML code for my blog from markdown, watches for changes in files, and serves the resulting site from HTTP port 8080.</p><p>So, in my case, I'll update the <strong>Launch Microsoft Edge in headless mode</strong> configuration in <code>launch.json</code> to this:</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pwa-msedge"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Launch Microsoft Edge in headless mode"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"request"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"launch"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"runtimeArgs"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"--headless"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"--remote-debugging-port=9222"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"preLaunchTask"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm: serve"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"url"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://localhost:8080"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"presentation"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"hidden"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>When this launch configuration is used, it will build my blog from source code, serve it on a local server, open the browser directly within VS Code, and the DevTools panels alongside it. Let's test it! Click on <strong>Launch Project</strong> in the <strong>Microsoft Edge Tools</strong> extension to get everything running.</p><p><img loading="lazy" alt="Screenshot of VSCode showing 3 panels side by side: a CSS file, the DevTools, and the browser rendering of my site" src="/assets/images/firstrun-1ef935e8dc8d1c45a965bcb801f93311.png" width="1400" height="814" class="img_ev3q"></p><p>Now try to apply this to your own project, changing the configuration to match your needs. Next, we'll review the most useful features of the extension.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="mirror-css-changes-to-source-files">Mirror CSS changes to source files<a href="#mirror-css-changes-to-source-files" class="hash-link" aria-label="Direct link to Mirror CSS changes to source files" title="Direct link to Mirror CSS changes to source files">​</a></h3><p>Tweaking CSS properties in DevTools is great because you get a live preview of your changes on the web page, and with the <strong>Microsoft Edge Tools</strong> extension, you also get mirroring of your changes right back to the corresponding source file. This way, you don't need to remember all of the changes you made and manually apply them to your editor. The extension is able to figure out the mapping between the live CSS code and the source files in your project.</p><p>Changing CSS code in the <strong>Styles</strong> panel automatically opens the corresponding source file and applies the same change.</p><p>Note that the extension does not save the CSS source file for you. You can keep on tweaking CSS in DevTools and, only once you're ready, save the changes made by the extension in the source file on your behalf.</p><p>You can learn more about CSS mirroring in the <a href="https://docs.microsoft.com/microsoft-edge/visual-studio-code/microsoft-edge-devtools-extension#syncing-live-changes-from-the-styles-tool-by-using-css-mirror-editing" target="_blank" rel="noopener noreferrer">Microsoft Edge DevTools extension docs</a>.</p><p><img loading="lazy" alt="Screenshot of VSCode showing editing a CSS value in the DevTools pane and the value being reflected in the source file" src="/assets/images/mirror-e91333679aac60431888789d7e5faaeb.png" width="1600" height="834" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="find-issues-with-your-code">Find issues with your code<a href="#find-issues-with-your-code" class="hash-link" aria-label="Direct link to Find issues with your code" title="Direct link to Find issues with your code">​</a></h3><p>Edge DevTools comes with a built-in <strong>Issues</strong> tool that provides useful information about the inspected web page. For example, it can report on browser compatibility, accessibility, or security issues.</p><p>The <strong>Microsoft Edge Tools</strong> extension in VS Code provides the same feature, but integrated right into your source code. For example, browser compatibility warnings are highlighted in your CSS source code with squiggly lines, and hovering over the highlight reveals more information about the issue.</p><p><img loading="lazy" alt="Screenshot of part of a CSS file in the VSCode editor, with a CSS property underline and a tooltip showing the browser compatibility warning related to using this property" src="/assets/images/cssissue-8d6aab48a94d0cf499440627826f60c7.png" width="1400" height="281" class="img_ev3q"></p><p>You can also review all issues at once by opening the <strong>Problems</strong> panel in VS Code's bottom drawer.</p><p>You can learn about other ways to find issues with your code in the <a href="https://docs.microsoft.com/microsoft-edge/visual-studio-code/microsoft-edge-devtools-extension#inline-and-live-issue-analysis" target="_blank" rel="noopener noreferrer">Microsoft Edge DevTools extension docs</a>.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="get-your-console-messages">Get your console messages<a href="#get-your-console-messages" class="hash-link" aria-label="Direct link to Get your console messages" title="Direct link to Get your console messages">​</a></h3><p>The <strong>Microsoft Edge Tools</strong> extension in VS Code also integrates the very popular <strong>Console</strong> tool. People rely on the console all the time when debugging their code.</p><p>Because the extension also works with the built-in VS Code JavaScript debugger, that means you can debug your front-end JavaScript code in VS Code as normal, and see your console logs in DevTools right next to you.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="learn-about-other-devtools-features">Learn about other DevTools features<a href="#learn-about-other-devtools-features" class="hash-link" aria-label="Direct link to Learn about other DevTools features" title="Direct link to Learn about other DevTools features">​</a></h2><p>As we've just seen, the <strong>Microsoft Edge Tools</strong> extension is very helpful. It caters for most web development tooling needs, while ensuring you have a seamless experience without having to leave VS Code.</p><p>But there's more to the Edge DevTools available in the browser (the tools you get when you press <strong>F12</strong>) that's not yet available within the VS Code extension version.</p><p>Building a great SWA means building a great web app first and foremost and while learning the ins and outs of SWA is very important, learning about how to build a performant and accessible web experience for all your users is also crucial.</p><p>Let's discover a few tools and features of DevTools that can help you with this.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="fix-accessibility-issues">Fix accessibility issues<a href="#fix-accessibility-issues" class="hash-link" aria-label="Direct link to Fix accessibility issues" title="Direct link to Fix accessibility issues">​</a></h3><p>Every year the <a href="https://webaim.org/" target="_blank" rel="noopener noreferrer">WebAIM organization</a> publishes a report of the most common website issues that create accessibility problems for people. Sadly, every year the result is quite depressing. You can read the <a href="https://webaim.org/projects/million/" target="_blank" rel="noopener noreferrer">WebAIM Million 2022 report</a>.</p><p>On the bright side though, the most common accessibility issues can be detected and solved easily with DevTools! So let's learn about some of the features that can help create more accessible web experiences for all.</p><p>The most common accessibility problem out there is low contrast text. If the contrast ratio between the text color and the color of the background behind it is too low, then people might not be able to read the text at all. The color picker in DevTools is a great way to detect these problems.</p><ol><li>Right-click a piece of text on your web page and select <strong>Inspect</strong>.</li><li>In the <strong>Styles</strong> tab, find the <strong>color</strong> CSS property that defines which color the text is, and click the colored square next to it.</li><li>Review the <strong>Contrast ratio</strong> in the color picker. Your goal is to have 2 check marks next to it, meaning that the contrast ratio meets the recommendation.</li></ol><p><img loading="lazy" alt="Screenshot of the Elements tool in Edge, showing the color picker on one of the text color CSS properties in the Styles pane, with the contrast ratio report." src="/assets/images/colorpicker-f67cc1e986f2b7764fa70ebc077db417.png" width="1400" height="844" class="img_ev3q"></p><p>If the text doesn't have enough contrast, then you can fix the problem right here in DevTools.</p><ol><li>Click the <strong>show more</strong> arrow next to the <strong>Color contrast</strong> value to reveal more information. Two lines will appear in the color picker.</li><li>Use these lines to choose a color that meets the recommendation.</li></ol><p><img loading="lazy" alt="Screencast showing the color picker in the Styles pane, with the 2 guide lines to choose a color that has enough contrast. Moving the current color selection across those 2 lines recalculates the ratio in real time." src="/assets/images/contrastratiolines-5324dcb3651c55cd8744ad18317b5a08.gif" width="1585" height="622" class="img_ev3q"></p><p>Another very common accessibility problem is missing alternative text for images (or alt text). Alt text helps users of screen readers perceive the content of an image, but it also important for cases where users decide to disable images, or when images fail to load, and even for search engine optimization. And, DevTools can detect missing alt text automatically! So there's really no excuses for not writing great textual substitute for your images.</p><ol><li>Open DevTools by pressing <strong>F12</strong>.</li><li>Click <strong>More Tools</strong> (<strong>+</strong>) in the main toolbar at the top and select the <strong>Issues</strong> tool from the list.</li><li>Check if the list of issues contains an <strong>Accessibility</strong> category. If it does, check for <strong>Images must have alternate text</strong> warnings.</li><li>Open one of the warnings, review the problem, and click <strong>Open in Elements</strong> to see the problem directly in the <strong>Elements</strong> tool.</li></ol><p><img loading="lazy" alt="Screenshot of the Issues tool in Edge, showing 4 missing alt-text warnings." src="/assets/images/alttext-adcf6bb1488c4a5fede9ec2f27b21898.png" width="1400" height="844" class="img_ev3q"></p><p>Now let's talk about source order. The order in which assistive technology (such as screen readers) navigates a page is linked to the order in which the various elements appear in the document source code. Now, this order might be very different from the order in which the elements appear, visually, on the screen. Using CSS, you can re-order things visually, without changing the document source order.</p><p>So, to make sure the document navigation makes sense to all, even to users of assistive technology, it is important to check that the source order itself makes sense.</p><p>Edge and Chrome DevTools have a <strong>Source Order Viewer</strong> feature that helps with this.</p><ol><li>Open DevTools by pressing <strong>F12</strong>.</li><li>Open the <strong>Elements</strong> tool and select a layout element which you want to check the source order in.</li><li>Click <strong>Accessibility</strong> in the tool's sidebar.</li><li>At the bottom of the <strong>Accessibility</strong> pane, select the <strong>Show source order</strong> checkbox. An overlay appears showing the source order with numbers.</li><li>Keep selecting different elements in the DOM tree to review their source order.</li></ol><p><img loading="lazy" alt="Screenshot of the Accessibility pane in the Elements tool in Edge, with the source order viewer checkbox selected, and the numbers overlay displayed on the page." src="/assets/images/sourceorder-d1935ff13ef4d6989c2c2a2e76c9369e.png" width="1500" height="848" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="improve-performance">Improve performance<a href="#improve-performance" class="hash-link" aria-label="Direct link to Improve performance" title="Direct link to Improve performance">​</a></h3><p>Great performance can have a very positive impact on your website. A page that appears fast and responds to user actions instantly can impact user retention, engagement, and even revenue.</p><p>Performance improvement work can be daunting, but there are two useful tools in DevTools that can ease the pain: the <strong>Performance</strong> tool and the <strong>Detached Elements</strong> tool.</p><p>Let's start with the <strong>Performance</strong> tool. You'll find one in all browser DevTools, Edge, Chrome, Firefox, or Safari. They're all a little bit different, but at their core give you ways to understand the runtime performance of the inspected web page over a given period of time.</p><p>To use the tool in Edge:</p><ol><li>Open DevTools by pressing <strong>F12</strong>.</li><li>Click <strong>Performance</strong> in the main toolbar at the top (you might have to click on the <strong>More tabs</strong> (<strong>&gt;&gt;</strong>) button first if the tab isn't visible.</li><li>Click the <strong>Record</strong> button.</li><li>Use the web page as a normal user would.</li><li>Stop the recording with the <strong>Stop</strong> button.</li></ol><p><img loading="lazy" alt="Screenshot of the performance tool in Edge DevTools" src="/assets/images/perftool-d83b9f20cec06e68b3a5c901c4095376.png" width="1400" height="944" class="img_ev3q"></p><p>The <strong>Performance</strong> tool can tell you how busy (or idle) the browser was with things like running JavaScript code, reacting to user events, and re-rendering the page during the recording period. So it's a great way to find bottlenecks in your site's performance and therefore know what fixes would give the best bang for your bucks.</p><p>One example, if your site does a lot of animations and other visual things, is that the tool can report on frames per second (FPS) and alert you when the rate drops too low and could impact the user experience.</p><p>The <strong>Performance</strong> tool has a lot of functionality packed into a small user interface, so it can be important to go through its documentation to understand what everything does. To learn more, check out <a href="https://docs.microsoft.com/microsoft-edge/devtools-guide-chromium/evaluate-performance/" target="_blank" rel="noopener noreferrer">Get started analyzing runtime performance</a></p><p>Another important performance aspect is memory. How much memory your site uses of what's available, and whether it keeps on using more and more memory over time can make your site, and even the entire computer, run slow.</p><p>One type of memory leaks is DOM leaks, where the front-end JavaScript code does a lot of DOM node manipulation and, in the process, keeps references to more and more DOM nodes it doesn't need any longer. As the complexity of your app or site grows, it gets easier to make mistakes and introduce these types of memory leaks by accident.</p><p>Edge comes with a tool called <strong>Detached Elements</strong> which is great for investigating this type of memory leaks. Knowing that you have a leak isn't too hard, but knowing where it originates from can feel like playing hide-and-seek in the dark. The <strong>Detached Elements</strong> tool points at DOM nodes that are still around in memory but not used in the page, and tells you which part of your code still references them. This way you can take a look at your code, and decide whether these nodes are, indeed, being leaked and need to be destroyed, potentially saving a lot of memory and improving performance.</p><p>To use the tool in Edge:</p><ol><li>Open DevTools by pressing <strong>F12</strong>.</li><li>Click <strong>More Tools</strong> (<strong>+</strong>) in the main toolbar at the top and select the <strong>Detached Elements</strong> tool from the list.</li><li>Click the <strong>Get detached elements</strong> button to list the DOM nodes in memory that aren't used in the page.</li><li>You can then use the app as a user would, and keep clicking that button to update the list. You can also click the <strong>Collect garbage</strong> button to force the browser to run its garbage collection mechanism, to see if some nodes have been collected in the meantime.</li></ol><p><img loading="lazy" alt="Screenshot of the detached elements tool in Edge, showing 3 DOM nodes in the list" src="/assets/images/detachedelements-9a4c5df57ba20165ac51702374143e54.png" width="1400" height="462" class="img_ev3q"></p><p>This should already give you a pretty good idea of where to start looking, but the tool is also integrated with the <strong>Memory</strong> tool, and using the <strong>Memory</strong> tool is great for finding where the listed DOM nodes are references from.</p><ol><li>Click the <strong>Analyze</strong> button and wait for the heap snapshot to be taken.</li><li>Click any of the numbers appearing in the <strong>Id</strong> column to jump right from a DOM node in the <strong>Detached Elements</strong> tool to its list of retainers in the <strong>Memory</strong> tool.</li></ol><p>The information displayed in the <strong>Retainers</strong> section of the <strong>Memory</strong> tool will give you hints as to which part of your code is currently keeping the DOM node alive in memory.</p><p><img loading="lazy" alt="Screenshot of the detached elements tool in Edge, with the memory tool below it showing the list of retainers for one of the DOM nodes in the list" src="/assets/images/detachedelements-memory-89afa908a1aa61fcade4fe3ad147c480.png" width="1400" height="1004" class="img_ev3q"></p><p>Learn more about using the <strong>Detached Elements</strong> tool in <a href="https://docs.microsoft.com/microsoft-edge/devtools-guide-chromium/memory-problems/dom-leaks" target="_blank" rel="noopener noreferrer">Debug DOM memory leaks with the Detached Elements tool</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2><p>I hope what we saw today was useful. If there's one thing I'd love for you to take away from this is that building a great Azure Static Web App starts with building a great web experience for all!</p><p>Learning the tools at your disposal to find and fix the most common mistakes that prevent such a great experience is important, and the Edge DevTools VS Code extension eases the pain by integrating directly in your existing environment.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>Install the latest version of the <strong><a href="https://marketplace.visualstudio.com/items?itemName=ms-edgedevtools.vscode-edge-devtools" target="_blank" rel="noopener noreferrer">Microsoft Edge Developer Tools extension for VS Code</a></strong> and try out some of these features. <strong>Try identifying and fixing accessibility issues</strong>, or use the <strong>Performance tool</strong> to analyze the runtime performance, of a Static Web App you've deployed.</p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>dev-tools</category>
        </item>
        <item>
            <title><![CDATA[#19: Develop with SWA CLI]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/devtools-swacli-develop</link>
            <guid>https://www.azurestaticwebapps.dev/blog/devtools-swacli-develop</guid>
            <pubDate>Fri, 20 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 3, Day 5 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 3, Day 5</code> of <strong>#30DaysOfSWA</strong>!! </p><p>We're past the halfway mark in "Dev Tools" week! We looked at developer tools to help provision Azure resources, automate cross-browser testing, streamline CI/CD, and debug/audit your SWA for performance and accessibility. But what about <strong>local development</strong> - something to help me go from <em>start</em> (project creation &amp; configuration) to <em>finish</em> (build &amp; deploy) in <strong>one tool</strong>? Let's say hello to the <a href="https://aka.ms/30DaysOfSWA/swa-cli" target="_blank" rel="noopener noreferrer">Azure Static Web Apps CLI</a>.</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>What We'll Cover</div><div class="admonitionContent_S0QG"><ul><li><code>swa</code> - One command to rule them all!</li><li>Creating the configuration</li><li>Building your project</li><li>Running your app locally</li><li><strong>Exercise</strong>: Use the new <code>swa</code> CLI to build and run a starter app!</li></ul></div></div><p><img loading="lazy" src="/assets/images/19-banner-ecd588da06f9f1af0f0e8a5f3323aa20.png" width="1000" height="420" class="img_ev3q"></p><p>You may have missed it, but the <a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer">new Azure Static Web Apps CLI</a> is now available!</p><p>It would take a whole post to describe all the changes and new features, but here are some of the highlights. With the new <code>init</code>, <code>build</code>, <code>start</code> and <code>deploy</code> commands, the complete developement cycle of your app is now available <em>in a single tool</em>, directly from the command line. </p><p><img loading="lazy" src="/assets/images/19-cli-banner-1-1bac73f4685c9f14cf25034fe74a405e.jpeg" width="1000" height="420" class="img_ev3q"></p><p>To get started, make sur you have a recent <a href="https://nodejs.org" target="_blank" rel="noopener noreferrer">Node.js</a> version installed (&gt;14) and type this command in your terminal:</p><div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npm i -g @azure/static-web-apps-cli</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>We'll now have a look at the new commands and the most important features.</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>If you've never heard of Static Web Apps (or SWA for short), it's a web app hosting service provided by Azure, offering streamlined full-stack development with many built-in features like authentication, customizable routing, serverless functions and more. It also has a great <a href="https://azure.microsoft.com/free/?WT.mc_id=javascript-0000-yolasors" target="_blank" rel="noopener noreferrer">free tier</a> 😉</p></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="swa"><code>swa</code><a href="#swa" class="hash-link" aria-label="Direct link to swa" title="Direct link to swa">​</a></h2><p>As the new CLI introduces a gazillion new options, it must quite a steep learning curve to get started? Quite the opposite!</p><p>Every command starts with <code>swa</code>, and now it might also be the only thing you'll need.</p><div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"># yes, that's all you need to type</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">swa</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>This command is a macro shorcut for <code>swa init</code>, <code>swa build</code>, <code>swa login</code> and <code>swa deploy</code>. We'll get to the details of all these commands in a bit, the most important thing here is that <code>swa</code> is the only command you need to know to configure a new project for use with Static Web Apps, build it and deploy it. You don't have to worry about any options or flags, just type <code>swa</code> and you'll be on your way. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="creating-the-configuration">Creating the configuration<a href="#creating-the-configuration" class="hash-link" aria-label="Direct link to Creating the configuration" title="Direct link to Creating the configuration">​</a></h2><p>The first of the new commands is <code>swa init</code>. This commands with detect your project configuration and the frameworks you're using to suggest a configuration for you, so you won't have to read through <a href="https://azure.github.io/static-web-apps-cli/" target="_blank" rel="noopener noreferrer">the shiny new docs</a> to figure out what options you need.</p><p><img loading="lazy" alt="swa init command screenshot" src="/assets/images/19-init-d5f344eba5b610e07a7b54f390b6a958.png" width="1138" height="423" class="img_ev3q"></p><p>After asking a name for your project configuration, you can validate or edit the detected project settings. Once finished, it will create a <code>swa-cli.config.json</code> file in the current folder with your settings. You can commit this file in your project repository so everyone from your team can use it.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="building-your-project">Building your project<a href="#building-your-project" class="hash-link" aria-label="Direct link to Building your project" title="Direct link to Building your project">​</a></h2><p>After the configuration is created, you're all set to use other commands without having to bother with any options or flags.</p><p>Whether you need to build your front-end app, your API, or both, the <code>swa build</code> command will do the job. It also takes care of installing your NPM dependencies (if needed) detecting if you're using npm, Yarn or PNPM with your project.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="running-your-app-locally">Running your app locally<a href="#running-your-app-locally" class="hash-link" aria-label="Direct link to Running your app locally" title="Direct link to Running your app locally">​</a></h2><p>Historically, being able to run your app locally was the first feature of the SWA CLI. Of course it's still there, and <code>swa start</code> allows you to emulate the SWA runtime environment, along with the routing, authentication features and API. A few changes were made to improve the developer experience, and of course bugs were fixed to more closely match the real SWA runtime.</p><p>Previously, if you were using an API, you had to install <a href="https://docs.microsoft.com/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash&amp;WT.mc_id=javascript-0000-yolasors#publish" target="_blank" rel="noopener noreferrer">Functions Core Tools</a> and make sure to match the tools version with the Node.js version you're using, but now the whole process is automated for you. If you don't have the tools installed or if the wrong version is installed, you don't have to worry about it: it will be automatically installed for you when needed.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="next-steps">Next steps<a href="#next-steps" class="hash-link" aria-label="Direct link to Next steps" title="Direct link to Next steps">​</a></h2><p>With these new commands, you can already setup your project, build it and test it locally. Using <code>swa start</code> is also great for debugging your app and API in a live running environment. Once you're happy with the result, you can deploy it to Azure, and that's what we'll explore in the next post.</p><p>In the meantime, you can also head to <a href="https://azure.github.io/static-web-apps-cli/" target="_blank" rel="noopener noreferrer">the new docs website</a> to learn more about the new features and how to use them.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="tell-us-your-feedback">Tell us your feedback!<a href="#tell-us-your-feedback" class="hash-link" aria-label="Direct link to Tell us your feedback!" title="Direct link to Tell us your feedback!">​</a></h2><p>We're also <a href="https://dev.to/azure/get-started-with-the-new-azure-static-web-apps-cli-mm3" target="_blank" rel="noopener noreferrer">here on dev.to</a> to listen and help as much as we can! 🙂</p><p>Please tell us your experience, your difficulties, your questions, and what features you would like to see in the next versions of the SWA CLI.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Want to see the Static Web Apps CLI in action? The tool became generally available yesterday, launching at the <a href="https://aka.ms/swaanniversary" target="_blank" rel="noopener noreferrer">Azure Static Web Apps Anniversary</a>. Watch the segment to see the SWA CLI in action.</p><iframe width="560" height="315" frameborder="0" src="https://www.youtube.com/embed/1e6k5HNK4F8" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>dev-tools</category>
        </item>
        <item>
            <title><![CDATA[#20: Deploy with SWA CLI]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/devtools-swacli-deploy</link>
            <guid>https://www.azurestaticwebapps.dev/blog/devtools-swacli-deploy</guid>
            <pubDate>Sat, 21 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 3, Day 6 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 3, Day 6</code> of <strong>#30DaysOfSWA</strong>!! </p><p>This is second part of the 2-part series that focuses on the launch of the <a href="https://azure.github.io/static-web-apps-cli/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">Azure Static Web Apps CLI</a> at the <a href="https://docs.microsoft.com/en-us/events/learntv/swa-anniversary-may-2022?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">Azure Static Web Apps Anniversary event</a> on May 19, 2022. Yesterday's post introduced the core <code>swa</code> command and walked through the <code>swa init</code> and <code>swa start</code> commands - and covered configuration. </p><p>Today, we'll explore the <code>swa login</code> and <code>swa deploy</code> commands that help with deploying your locally-developed app to the Azure cloud. And we'll cover the use of Environment Variables to streamline the developer experience further.</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>What We'll Cover</div><div class="admonitionContent_S0QG"><ul><li>Logging in to Azure</li><li>Deploying your app</li><li>Environment variables</li><li><strong>Exercise</strong>: Use the new <code>swa</code> CLI to authenticate, and deploy your app</li></ul></div></div><p><img loading="lazy" src="/assets/images/20-banner-62cb7a9019981d88c514d8875b8547d9.png" width="1000" height="420" class="img_ev3q"></p><p>For this second article about the SWA CLI, we'll talk about the new deployment options. And yes, you can now deploy your apps straight from the command line! Who's better than the person who implemented it to talk about it? I'll let my friend <a href="https://twitter.com/manekinekko" target="_blank" rel="noopener noreferrer">Wassim</a> explain it all to you.</p><blockquote><p>If you've never heard of Static Web Apps (or SWA for short), it's a web app hosting service provided by Azure, offering streamlined full-stack development with many built-in features like authentication, customizable routing, serverless functions and more. It also has a great <a href="https://azure.microsoft.com/free/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">free tier</a> 😉</p></blockquote><h2 class="anchor anchorWithStickyNavbar_LWe7" id="logging-in-to-azure">Logging in to Azure<a href="#logging-in-to-azure" class="hash-link" aria-label="Direct link to Logging in to Azure" title="Direct link to Logging in to Azure">​</a></h2><p>In the new SWA CLI for Azure Static Web Apps, we introduced a new <code>swa login</code> command allowing you to log in to your Azure account, straight from the command line. This command will encrypt and store your credentials in your system's key Chain, so you don't have to enter them again.</p><p>In most common cases, the <code>swa login</code> will pick your current active Azure credentials from the following locations (in this order):</p><ol><li>Your environment variables, if you have set one or all of following <a href="https://azure.github.io/static-web-apps-cli/docs/cli/env-vars#azure-identity?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">variables</a>:<ul><li><code>AZURE_TENANT_ID</code></li><li><code>AZURE_CLIENT_ID</code></li><li><code>AZURE_CLIENT_SECRET</code></li></ul></li><li>Your current Visual Studio Code, if you're using VS Code and is connected to Azure.</li><li>Interactive prompt using your browser.</li><li>The last fallback is the device code flow, which will prompt you to log in to your Azure account using a generated device code.</li></ol><p>However, if you need, you can also provide any of these credentials from the command line, using the available flags:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Usage: swa login </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">login into Azure</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Options:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -S, --subscription-id </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">subscriptionId</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">    Azure subscription ID used by this project</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">default: </span><span class="token string" style="color:#e3116c">"process.env.AZURE_SUBSCRIPTION_ID"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -R, --resource-group </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">resourceGroupName</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">  Azure resource group used by this project</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -T, --tenant-id </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">tenantId</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">                Azure tenant ID </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">default: </span><span class="token string" style="color:#e3116c">"process.env.AZURE_TENANT_ID"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -C, --client-id </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">clientId</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">                Azure client ID</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -CS, --client-secret </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">clientSecret</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">       Azure client secret</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -n, --app-name </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">appName</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">                  Azure Static Web App application name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -cc, --clear-credentials                  </span><span class="token function" style="color:#d73a49">clear</span><span class="token plain"> persisted credentials before login </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">default: </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -u, --use-keychain                        </span><span class="token builtin class-name">enable</span><span class="token plain"> using the operating system native keychain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> persistent credentials </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">default: </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -nu, --no-use-keychain                    disable using the operating system native keychain</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Once logged in, the SWA CLI will store your active Azure subscription ID and tenant ID in a local file called <code>.env</code> at the root of your project:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">➜ swa login</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Welcome to Azure Static Web Apps CLI </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Checking Azure session</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔ Successfully logged into Azure</span><span class="token operator" style="color:#393A34">!</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔ Saved project credentials </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> .env file.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔ Successfully setup project</span><span class="token operator" style="color:#393A34">!</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>This file will be used when deploying your project to Azure using the <code>swa deploy</code> command.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploying-your-app">Deploying your app<a href="#deploying-your-app" class="hash-link" aria-label="Direct link to Deploying your app" title="Direct link to Deploying your app">​</a></h2><p>The new SWA CLI makes it even more easier to deploy your apps to Azure. You can now deploy your app directly from the command line, using one single <code>swa deploy</code> command.</p><p>The <code>swa deploy</code> command is smarter enough to figure out if you already have an Azure Static Web Apps instance available, and if so, it will use it. Otherwise, it will create a new one on the fly - or prompt you to select one from a list of already available ones:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">➜ swa deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Welcome to Azure Static Web Apps CLI </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Using configuration </span><span class="token string" style="color:#e3116c">"thundr"</span><span class="token plain"> from file:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  /home/wassimchegham/oss/@thundr-dev/thundr/swa-cli.config.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Deploying front-end files from folder:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  /home/wassimchegham/oss/@thundr-dev/thundr/app/dist/thundr-ui</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Deploying API from folder:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  /home/wassimchegham/oss/@thundr-dev/thundr/api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Checking Azure session</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔ Successfully logged into Azure</span><span class="token operator" style="color:#393A34">!</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Checking project settings</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">? Choose your Static Web App › - Use arrow-keys. Return to submit.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">❯   </span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> Create a new application</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    swa_samples/angular-web-bluetooth</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    swa_samples/catsify</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    swa_samples/hexa</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    swa_samples/ngxtools</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    swa_samples/nitrooo</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ↓ swa_samples/photobooth-teams</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>The <code>swa deploy</code> command is also able to detect if your existing Static Web Apps instance has already been deployed from a CI/CD pipeline and inform you about it!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploying-from-a-cicd-pipeline">Deploying from a CI/CD pipeline<a href="#deploying-from-a-cicd-pipeline" class="hash-link" aria-label="Direct link to Deploying from a CI/CD pipeline" title="Direct link to Deploying from a CI/CD pipeline">​</a></h2><p>Deploying from CI/CD pipelines is a common practice in many projects. You can use the <code>swa deploy</code> command to deploy your app to Azure from your CI/CD pipeline. You can accomplish this by setting a deployment token:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">➜ swa deploy --print-token --app-name thundr --resource-group swa_samples</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Welcome to Azure Static Web Apps CLI </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Checking project </span><span class="token string" style="color:#e3116c">"thundr"</span><span class="token plain"> settings</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔ Successfully setup project</span><span class="token operator" style="color:#393A34">!</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Deploying to environment: preview</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Deployment token:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">7c3fc44b858164b677-truncated-8c80ace9-39a8-416c-ae22-864745c0470b003</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">swa deploy --deployment-token</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">7c3fc44b858164b677-truncated-8c80ace9-39a8-416c-ae22-864745c0470b003b003</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>You can also set the deployment token as an <a href="https://azure.github.io/static-web-apps-cli/docs/cli/env-vars#deploy-settings?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">environment variable</a>:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token builtin class-name">export</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">SWA_CLI_DEPLOYMENT_TOKEN</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">7c3fc44b858164b677-truncated-8c80ace9-39a8-416c-ae22-864745c0470b003b003</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">swa deploy</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="environment-variables">Environment variables<a href="#environment-variables" class="hash-link" aria-label="Direct link to Environment variables" title="Direct link to Environment variables">​</a></h2><p>The new SWA CLI introduced a new set of environment variables to make it easier for you to configure your experience. You can customize the behavior of the SWA CLI by setting the following environment variables:</p><ul><li>General settings</li><li>Emulator settings</li><li>Deploy settings</li><li>Runtime settings</li><li>Login experience</li></ul><p>You can read more about these environment variables in the <a href="https://azure.github.io/static-web-apps-cli/docs/cli/env-vars??WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">Environment Variables section</a> in our new documentation website.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="next-steps">Next steps<a href="#next-steps" class="hash-link" aria-label="Direct link to Next steps" title="Direct link to Next steps">​</a></h2><p>From the start of your project to its deployment to Azure, with all the needed local testing in-between, you should now be equipped to take care of your complete development process all from the command line. Now the main challenge remaining for you is to deploy and grow your app 😉.</p><p>If you'd like to learn some tips you can use when developing your app, you can check out the <a href="https://aka.ms/StaticWebAppsTips??WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">Static Web Apps - Tips &amp; Tricks</a> video series.</p><p>You can also learn more about all the new features of the SWA CLI and how to use them by looking at the <a href="https://azure.github.io/static-web-apps-cli/?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">new docs website</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="tell-us-your-feedback">Tell us your feedback!<a href="#tell-us-your-feedback" class="hash-link" aria-label="Direct link to Tell us your feedback!" title="Direct link to Tell us your feedback!">​</a></h2><p>We're also here on dev.to to listen and help as much as we can! 🙂</p><p>Please tell us your experience, your difficulties, your questions, and what features you would like to see in the next versions of the SWA CLI.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Want to see the Static Web Apps CLI in action? The tool became generally available yesterday, launching at the <a href="https://aka.ms/swaanniversary" target="_blank" rel="noopener noreferrer">Azure Static Web Apps Anniversary</a>. Watch the segment to see the SWA CLI in action.</p><iframe width="560" height="315" frameborder="0" src="https://www.youtube.com/embed/1e6k5HNK4F8?WT.mc_id=30daysofswa-61155-cxall" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>dev-tools</category>
        </item>
        <item>
            <title><![CDATA[#21: Develop With VSCode]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/devtools-vscode</link>
            <guid>https://www.azurestaticwebapps.dev/blog/devtools-vscode</guid>
            <pubDate>Sun, 22 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 3, Day 7 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 3, Day 7</code> of <strong>#30DaysOfSWA</strong>!! </p><p>This week has been all about the SWA developer tools. To conclude the week, we'll show how the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">Azure Static Web Apps extension for VS Code</a> can make using all of these awesome tools easier!</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>WHAT WE'LL COVER TODAY</div><div class="admonitionContent_S0QG"><ul><li>Debugging with VS Code</li><li>Easily add an API endpoint</li><li>Debug API and Frontend simultaneously</li><li><strong>Resource(s):</strong> <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Azure Static Web Apps Quickstart: With VS Code</a></li></ul></div></div><p><img loading="lazy" src="/assets/images/21-banner-4c8833d85f3b63b56f65329fd492dcb5.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites-️">Prerequisites 🛠️<a href="#prerequisites-️" class="hash-link" aria-label="Direct link to Prerequisites 🛠️" title="Direct link to Prerequisites 🛠️">​</a></h2><ol><li><p><strong>Google Chrome installed</strong> - we make use of the debugger</p></li><li><p><strong>Azure Static Web Apps extension for VS Code</strong> - <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">View on Marketplace</a></p></li><li><p><strong>Azure Static Web Apps CLI</strong> - <a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer">View on GitHub</a></p></li></ol><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npm install -g @azure/static-web-apps-cli@latest</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-getting-started-">1. Getting started 🟢<a href="#1-getting-started-" class="hash-link" aria-label="Direct link to 1. Getting started 🟢" title="Direct link to 1. Getting started 🟢">​</a></h2><ol><li>Clone one of these repositories, and open it up in VS Code</li></ol><table><thead><tr><th>Framework</th><th>Repository</th></tr></thead><tbody><tr><td>Angular</td><td><a href="https://github.com/staticwebdev/angular-basic" target="_blank" rel="noopener noreferrer">https://github.com/staticwebdev/angular-basic</a></td></tr><tr><td>React</td><td><a href="https://github.com/staticwebdev/react-basic" target="_blank" rel="noopener noreferrer">https://github.com/staticwebdev/react-basic</a></td></tr><tr><td>Svelte</td><td><a href="https://github.com/staticwebdev/svelte-basic" target="_blank" rel="noopener noreferrer">https://github.com/staticwebdev/svelte-basic</a></td></tr></tbody></table><ol start="2"><li>Run <code>npm install</code></li></ol><p><img loading="lazy" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c00m73mzlt49kkwl4iiw.png" alt="Running npm install in VS Code" class="img_ev3q"></p><blockquote><p>Theme: <a href="https://marketplace.visualstudio.com/items?itemName=wesbos.theme-cobalt2" target="_blank" rel="noopener noreferrer">Cobalt2 Theme Official by Wes Bos</a></p></blockquote><h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-run-and-debug-">2. Run and debug 🐞<a href="#2-run-and-debug-" class="hash-link" aria-label="Direct link to 2. Run and debug 🐞" title="Direct link to 2. Run and debug 🐞">​</a></h2><p><img loading="lazy" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pahznac0f8cjqt8haifb.png" alt="Show automatic debug configurations" class="img_ev3q"></p><ol><li>Go to the "Run and Debug" view</li><li>Click "Show all automatic debug configurations."</li><li>In the dropdown, select "Azure Static Web Apps..."</li><li>Select the app you want to debug</li></ol><p>This will start the Azure Static Web Apps CLI in the VS Code terminal, and launch the Chrome debugger on <code>http://localhost:4280</code>.</p><p>Now you can set and hit breakpoints in your frontend code. </p><p><img loading="lazy" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aprutdzi9opkbegdnf2p.png" alt="Set breakpoints" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-add-api-route-️">3. Add API route ⚡️<a href="#3-add-api-route-️" class="hash-link" aria-label="Direct link to 3. Add API route ⚡️" title="Direct link to 3. Add API route ⚡️">​</a></h2><p>Azure Static Web Apps has integrated API support provided by Azure Functions. In order to add and debug an API route, we must install some Azure Functions tools.</p><ol><li><p><strong>Azure Functions extension for VS Code</strong> - <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions" target="_blank" rel="noopener noreferrer">Install from Marketplace</a></p></li><li><p><strong>Azure Functions Core Tools</strong> - <a href="https://github.com/Azure/azure-functions-core-tools" target="_blank" rel="noopener noreferrer">View on GitHub</a></p></li></ol><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npm i -g azure-functions-core-tools@4 --unsafe-perm true</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Now, you can add an API route to your app using the command palette (press <code>F1</code>) and searching "Create HTTP Function".</p><p><img loading="lazy" src="https://user-images.githubusercontent.com/12476526/169424449-3a10a9a0-025f-4fa3-b15f-294846fb0291.png" alt="Add HTTP Function" class="img_ev3q"></p><p>Select a language (I chose JavaScript), then name your Function (I put "hello"). And then an API route will be created for you that you can make requests to at <code>/api/hello</code>.</p><p><img loading="lazy" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emd9wo9q26m51aboyydd.png" alt="API route" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="4-debug-app--api-">4. Debug app &amp; API ✨<a href="#4-debug-app--api-" class="hash-link" aria-label="Direct link to 4. Debug app &amp; API ✨" title="Direct link to 4. Debug app &amp; API ✨">​</a></h2><p>We can debug our API routes and our frontend app simultaneously in VS Code.</p><p>Select the "SWA: Run ..." debug configuration and click the green "Run and debug" button.</p><p><img loading="lazy" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/234k0e1p9jzmtyeeli56.png" alt="Run and debug" class="img_ev3q"></p><p>VS Code will now run your Functions API routes and your frontend. When it's all started, a Chrome window will open at <code>http://localhost:4280</code>.</p><p>Set a breakpoint in your Function endpoint.</p><p><img loading="lazy" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89kolpnqbsrqysh661ep.png" alt="Function endpoint breakpoint" class="img_ev3q"></p><p>Go to <code>http://localhost:4280/api/hello</code> in the Chrome window to hit the breakpoint.</p><p><img loading="lazy" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2q8zt9j70wz4dr5h3mcm.png" alt="Hitting an API breakpoint" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="5-next-steps-️">5. Next steps 🏃‍♀️<a href="#5-next-steps-️" class="hash-link" aria-label="Direct link to 5. Next steps 🏃‍♀️" title="Direct link to 5. Next steps 🏃‍♀️">​</a></h2><p>Now that you got your static web app running locally, you can <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=react" target="_blank" rel="noopener noreferrer">deploy your static web app to Azure for free</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="troubleshooting-">Troubleshooting 🔍<a href="#troubleshooting-" class="hash-link" aria-label="Direct link to Troubleshooting 🔍" title="Direct link to Troubleshooting 🔍">​</a></h2><p>If you're having issues, please check out the <a href="https://github.com/microsoft/vscode-azurestaticwebapps/wiki/Guide:-Debugging-a-Static-Web-App-with-VS-Code#troubleshooting-" target="_blank" rel="noopener noreferrer">troubleshooting section in our wiki</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources-">Resources 🔗<a href="#resources-" class="hash-link" aria-label="Direct link to Resources 🔗" title="Direct link to Resources 🔗">​</a></h2><ul><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Static Web Apps documentation</a></li><li><a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer">Azure Static Web Apps CLI</a></li><li><a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">Azure Static Web Apps extension for VS Code</a></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="next-week">Next Week<a href="#next-week" class="hash-link" aria-label="Direct link to Next Week" title="Direct link to Next Week">​</a></h2><p>This marks the end of Week 3 of #30DaysOfSWA, with a focus on <code>Developer Tools</code>. Want a visual recap of what we covered .. here you go!! To recap:</p><ul><li>We provisioned Azure resources - using the Azure Portal and Azure CLI</li><li>We added automated, cross-browser, e2e testing - using Playwright</li><li>We built multi-stage deployment pipelines - using Azure DevOps</li><li>We debugged and audited perf &amp; accessibility - using Edge DevTools on VSCode</li><li>We got unified local development and cloud deployment - using SWA CLI</li><li>We explored rich extensions and seamless CLI interactions - using VS Code</li></ul><p><img loading="lazy" alt="Week 3 Visual Roadmap" src="/assets/images/week3-roadmap-75060ba5a95b7914046572100b6effdd.png" width="1000" height="563" class="img_ev3q"></p><p>So what do we have planned for next week? </p><p>We've already covered core concepts, usage examples and developer tools -- so that leaves: <strong>Best Practices!</strong> Join us for the final week of #30DaysOfSWA where we define the end-to-end developer experience, explore various Azure Service integrations to enhance your SWA, dive into a cool case study, and end with a <code>Tips &amp; Tricks</code> series that brings you back full circle to development.</p><p>Thanks for sticking with us on this journey!</p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>dev-tools</category>
        </item>
        <item>
            <title><![CDATA[#22: E2E Development & SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/practices-e2e</link>
            <guid>https://www.azurestaticwebapps.dev/blog/practices-e2e</guid>
            <pubDate>Mon, 23 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 4, Day 1 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 4, Day 1</code> of <strong>#30DaysOfSWA</strong>!! </p><p>This kickstarts our <strong>"Best Practices"</strong> week where we'll explore additional topics that help up deliver an enhanced or more optimal modern web application experience to our users. We'll start by looking at the End-to-End <em>developer experience (DX)</em> - the importance of having a smooth and seamless DX to complement the UX (user experience), and best practices to improve your developer experience by architecting your applications and integrating services in more effective ways. Let's dive in!</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>What We'll Cover</div><div class="admonitionContent_S0QG"><ul><li>What is an end-to-end developer experience (DX)?</li><li>What are core DX components when building and deploying static web apps?</li><li>How can we improve DX implementing best practices?</li><li>How can we create an architecture matrix to guide E2E DevEx?</li><li><strong>Exercise</strong>: Try to reproduce the architecture seen below!</li></ul></div></div><p><img loading="lazy" src="/assets/images/22-banner-c5cc6f06159eb61034c900af02756c3a.png" width="1000" height="420" class="img_ev3q"></p><p>Today we explore the importance of a great development experience and how can you improve yours, when building and deploying your static web applications using Azure Static Web Apps!</p><p>I admit it took me some time to write this post. It would have been much easier for me to write about a specific topic with code examples and technical definitions, than describing what developer experience means to me.</p><p>The definition of developer experience, like anything else you <em>experience</em>, is subjective. It has a lot of you, in it. It changes with you, and the context you're a part of. Things like <em>how long you've been in the business</em> or <em>what type of software you work on</em>, or <em>where do you deploy it</em>, will all impact your perception of an experience.</p><p>So how to put it in words? How to define it and scope it? </p><p>It's impossible for me to do it in a way that feels relatable to everyone. I can only explain it, from the perspective inferred by my needs and my perception of the outcome, as an individual developer, and how it impacts my vision and my work. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="predictability">Predictability<a href="#predictability" class="hash-link" aria-label="Direct link to Predictability" title="Direct link to Predictability">​</a></h2><p>Let me start by saying that in my personal life, when I think of memorable experiences, a lot of them have been the consequence of an impulse. A spontaneous act. In my personal life, I am not much of a planner. I am the kind of person that wakes up every Saturday morning and declares "We are going somewhere far away this weekend!". And my husband (who is all the contrary from me and needs a lot of structure!) will ask questions like:</p><ul><li>Ok, where do you wanna go? </li><li>Have you booked a hotel? </li><li>Do you know where we will have lunch? </li></ul><p>And I would invariably respond: "I don't care! Let's just hop in the car, drive somewhere and figure it all out on the way there!". That's because I think that experimenting and experiencing, go hand in hand, when it comes to adventure. And the actual <em>way there</em>, is part of the fun.</p><blockquote><p><strong>At work, however, I like predictability.</strong> </p></blockquote><p>I like structure, repeatability, patterns &amp; conventions. I appreciate having a framework, an opinion others agree with so I'm on the same page with my team. And I like all this because it oftentimes leads to quick results and success.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-road-analogy">A Road Analogy<a href="#a-road-analogy" class="hash-link" aria-label="Direct link to A Road Analogy" title="Direct link to A Road Analogy">​</a></h2><p>Experiences are like roads. They can take you places -- or not. And to me, <strong>development experiences are just like the roads we travel on</strong>:</p><ul><li>They have milestones - so I can measure progress.</li><li>They have multiple lanes - so I have flexibility.</li><li>They have entry and exit ramps - so I can change paths quickly. </li><li>They have destinations - so I know I'm getting somwhere specific.</li></ul><p>When I first got into web development, there were a fewer types of roads. Most were linear and slow, particularly when it came to frontend development. You needed repeated round-trips to the same server, just to get something to render on a page.</p><p><img loading="lazy" alt="the roundtrip road of boring development" src="/assets/images/swaF1-2f10c6d9065a83c8c963ec50a95e9c2e.png" width="2120" height="1181" class="img_ev3q"></p><p>By contrast, today we're speeding along multi-lane freeways with numerous twists and turns, interconnecting roads, and possibilities (<a href="https://dev.to/azure/04-configuring-static-web-apps-2oa7" target="_blank" rel="noopener noreferrer">aka configurations</a>) to choose from. To reach a destination, you may have to use ramps to connect two different roads - similar to how we connect tow different services <a href="https://dev.to/azure/03-api-enabling-static-web-apps-25kh" target="_blank" rel="noopener noreferrer">via an API</a>. </p><p><img loading="lazy" alt="more lanes, more connectivity, more fun, more speed" src="/assets/images/swaF3-c85e864b2af858458f7034a071d45127.png" width="3331" height="1244" class="img_ev3q"></p><p>If we continue with this analogy, then <strong>a bad development experience is like poor road planning or construction</strong>:</p><ul><li>the road is old, bumpy, cracked</li><li>the signposts are few and far between, giving the user insufficient time to process and follow instructions. </li><li>if you miss an exit, you may have to travel a long distance before you have the opportunity to turn around</li><li>there may be no way to access a desired road from another one - no exit or entry ramps at all!</li><li>if your car breaks down, or your run out of fuel - there may not be service stations nearby to for refill or recharge.</li><li>or you may find a station, but you have no idea of the cost of refill or recharge before you commit to taking that exit.</li><li>there may not be any way to get food or drinks for many miles.</li></ul><p>You can probably guess how these travel constraints map onto poor developer experiences, but let's spell it out:</p><ul><li>having to slow down due to infrastructure conditions</li><li>feeling like you're not making any progress</li><li>having the certainty that your application quality is degrading due the environment and lack of resources or support, resulting in technical debt</li><li>not having the ability to <a href="https://dev.to/azure/05-securing-static-web-apps-5fe3" target="_blank" rel="noopener noreferrer">secure your implementation</a></li><li>not finding the right, complete or fresh documentation to help you understand the best path</li><li>not having the right SDK's, API methods, or means of integrating your app to other software, to accomplish simple or more complex tasks, like authentication, storage, content authoring <a href="https://dev.to/azure/12-headless-cms-swa-built-with-blazor-1e2d" target="_blank" rel="noopener noreferrer">with a headless CMS</a> or setting up your CI/CD pipeline</li><li>not having the right tools to <a href="https://dev.to/azure/02-building-static-web-apps-2j72" target="_blank" rel="noopener noreferrer">build</a>, <a href="https://dev.to/azure/07-deploying-static-web-apps-48e" target="_blank" rel="noopener noreferrer">deploy</a>, optimize, <a href="https://dev.to/azure/06-previewing-static-web-apps-4p36" target="_blank" rel="noopener noreferrer">preview</a>, monitor or speed up your processes</li><li>not being able to scale or not being sure how much it will cost you</li><li>not having fun, as you go</li></ul><p><strong>Because, let's face it: developing should be a fun experience. And for that you need the right vehicle, the right infrastructure, and a plan.</strong>
And when you lack all that, it's like riding a Lamborghini across a sandy desert.</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>WHAT WE CAN CONCLUDE</div><div class="admonitionContent_S0QG"><p>Is that developer experience refers to the entirety of physical, emotional and cognitive experiences of an individual while using a tool or technology to complete a software development task. It can equate to suffering (when bad), enduring (when fustrating or neutral), or to feeling pleasure and delight (when great).</p></div></div><p><img loading="lazy" alt="The right infrastructure, capabilities and resources, to support the right architecture" src="/assets/images/swaF4-0bd6686927cf3493451a953651fd6b0e.png" width="3169" height="1299" class="img_ev3q"></p><p>Making the right architecture and technology decisions, will definitely impact the outcome. And we can only make those decisions right, when we ask the right questions.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="architecture-what-core-infrastructure-capabilities-and-resources-do-we-need">Architecture: What core infrastructure, capabilities and resources do we need?<a href="#architecture-what-core-infrastructure-capabilities-and-resources-do-we-need" class="hash-link" aria-label="Direct link to Architecture: What core infrastructure, capabilities and resources do we need?" title="Direct link to Architecture: What core infrastructure, capabilities and resources do we need?">​</a></h2><p>As we hope you have learned from following this <a href="https://dev.to/azure/kicking-off-30daysofswa-2d8g" target="_blank" rel="noopener noreferrer">30 days of Static Web Apps</a>, it is a dedicated offering for frontend developers working with SPA's and Static Generated websites. We continue to work to extend its capabilities, and support more frameworks and use cases.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="documentation-should-be-fresh--relevant">Documentation: Should be fresh &amp; relevant!<a href="#documentation-should-be-fresh--relevant" class="hash-link" aria-label="Direct link to Documentation: Should be fresh &amp; relevant!" title="Direct link to Documentation: Should be fresh &amp; relevant!">​</a></h3><p>When thinking about those milestones that should hit along the road of a great end-to-end developer experience, we are working hard to make sure you always find complete and fresh documentation to help you get started and know all the possibilities you have with Static Web Apps, upfront, and to keep supporting you with relevant documentation and content as your applications grow.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="workflows-building-blocks--seamless-integrations">Workflows: Building blocks &amp; seamless integrations!<a href="#workflows-building-blocks--seamless-integrations" class="hash-link" aria-label="Direct link to Workflows: Building blocks &amp; seamless integrations!" title="Direct link to Workflows: Building blocks &amp; seamless integrations!">​</a></h3><p>Not only have we been working to offer an intuitive user interface at the Azure portal itself. We have been very intentional at the time of making sure integration with the <a href="https://dev.to/azure/15-develop-with-azure-tools-3h47" target="_blank" rel="noopener noreferrer">tools</a>, and platforms frontend developers know, use and love, like GitHub and VS Code, is seamless. </p><p>Static Web Apps automatically pushes a GitHub actions workflow file as you generate the application as a resource, and you can create it from the portal, if you prefer a UI guided experience, but also without ever leaving your favorite code editor, by installing the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">official extension</a>!</p><p>And if you prefer a command line experience, you can use the brand new Static Web Apps CLI, with extended support to login to Azure, create, build and deploy apps, and a local emulator, so you can test your apps before you ever deploy to the cloud.</p><p>Creating your static web applications and configuring your pipelines, has never been this easy!</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="efficient--versatile-serverless--containerized-apis">Efficient &amp; Versatile: Serverless + Containerized APIs<a href="#efficient--versatile-serverless--containerized-apis" class="hash-link" aria-label="Direct link to Efficient &amp; Versatile: Serverless + Containerized APIs" title="Direct link to Efficient &amp; Versatile: Serverless + Containerized APIs">​</a></h3><p>Because we recognize that the use cases for Jamstack and JavaScript full-stacks applications in general are becoming more and more complex, part of our strategy for a delightful end-to-end development experience relies on the simplification and standarization of mechanisms for API integration, via serverless functions through industry compliant patterns and via our super efficient devkits.</p><p>And that includes a concern that has historically been a challenge for frontend developers: the integration with databases and data storage. Azure Static Web Apps is unique in that it integrates very well with our CosmosDB database, a versatile cloud database that offers different API's to meet different developer skills and server a myriad of use cases in a very effective way.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="security--performance-e2e-testing--debugging">Security &amp; Performance: E2E testing + debugging<a href="#security--performance-e2e-testing--debugging" class="hash-link" aria-label="Direct link to Security &amp; Performance: E2E testing + debugging" title="Direct link to Security &amp; Performance: E2E testing + debugging">​</a></h3><p>And when we go to the service station, it may be a good time to check our oil levels, air pressure and wipe our window panes. And what a better way to do it than with tools from the same developer ecosystem and that play right (yes, you got me! I'm playing with words now!) like <a href="https://dev.to/azure/16-test-automation-with-playwright-odk" target="_blank" rel="noopener noreferrer">Playwright</a> and Edge Developer Tools. </p><p>So now when you use the newly release Preview environments, to test development from a specific staging branch, you will have also the ability to integrate with best-in-class tooling, iteration after iteration, until feature complete.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="alignment-the-ultimate-e2e-roadmap-should-map-to-the-development-cycle">Alignment: The ultimate e2e roadmap should <em>map</em> to the development cycle<a href="#alignment-the-ultimate-e2e-roadmap-should-map-to-the-development-cycle" class="hash-link" aria-label="Direct link to alignment-the-ultimate-e2e-roadmap-should-map-to-the-development-cycle" title="Direct link to alignment-the-ultimate-e2e-roadmap-should-map-to-the-development-cycle">​</a></h2><p>Any aspect on its own, can describe an end-to-end experience. For instance:</p><ul><li>If I want to secure my app against unauthorized access, I must implement identity. That's an E2E experience.</li><li>If I want to persist data, I'll need to integrate with a database. An E2E experience.</li><li>If I want to integrate third-party services on demand, I'll need event-driven functions. Another E2E experience.</li></ul><p>The ultimate end-to-end experience, however, is that that encompasses all components described by a matrix of architecture definitions and best practices,  mapping to the software development cycle itself.</p><p><img loading="lazy" alt="development roadmap equals cycle" src="/assets/images/SWAF5-bb8f52ffabf09a08d7f08a8f53f4463c.png" width="2283" height="1598" class="img_ev3q"></p><p>When we are in the system design phase for our application, we will start thinking about what in research is known as "Jobs to be Done", and materialize them or <em>get them done</em> , using tools or integrating with other products or services.</p><p> <strong>Setup phase</strong>.
Job to be done will be generic - "I need to build a static web app. </p><ul><li>What do I need? =&gt; I need a framework.</li><li>What does the framework require =&gt; It's a JS framework that runs in the browser, or in a Node.js runtime. I need a node environment and a node package manager to manage dependencies. </li><li>Selected framework has its own CLI =&gt; I need it to optimize it and build it. </li><li>I want to version it, so I need a version control tool. To collaborate, I need to host that code in a central, remote location (aka version control hosting). </li><li>And because we want to build it remotely each time we integrate with a CI/CD pipeline, that includes a runner and some virtualization or emulation. - And we want to publish it, so I need a hosting service. </li><li>And..."_</li></ul><p>And those are the <em>requirements</em> that we start mapping to <em>setup and service capabilities</em>, so we can put together local and remote environments capable to fulfill them.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="welcome-to-the-matrix">Welcome to the matrix<a href="#welcome-to-the-matrix" class="hash-link" aria-label="Direct link to Welcome to the matrix" title="Direct link to Welcome to the matrix">​</a></h2><p>So let's do together an exercise of architecture definitions based out of developer <em>jobs to be done</em>, classifying them by the milestone we defined in the previous graphic. As a bonus, we will map them to a requirement, that can be a business requirement, a developer job to be done, or an end user story.</p><p>The matrix will be roughly based on the high-level diagram below:</p><p><img loading="lazy" alt="static web app high level architecture diagram" src="/assets/images/swaF6-650f434fb7606309668b8cc10cb640ee.png" width="3374" height="2411" class="img_ev3q"></p><table><thead><tr><th>Job to be done</th><th>Product/Service</th><th>Phase</th><th>Requirement</th></tr></thead><tbody><tr><td>As a developer, I want to use the tools I am familiar with, to code, build and deploy my Jamstack (Statically Generated) applications</td><td>VS Code / SWA CLI</td><td>Setup</td><td>As an end-user, I want to be able to access an online catalogue of products with their respective detail pages</td></tr><tr><td>As a developer, I want to connect my remote repository where I collaborate with other team members, to the service I will be deploying my app to</td><td>GitHub / VS Code / Static Web Apps*</td><td>Setup</td><td>As a business owner, I want the code and secrets for my e-commerce platform to be stored safely</td></tr><tr><td>As a developer, I want to setup a CI/CD pipeline, for remote collaboration and fast/agile integration</td><td>GitHub Actions Static Web Apps</td><td>Setup</td><td>As a content author, I want to see the new content published when I submit it to the content authoring tool, without any additional manual work</td></tr><tr><td>As a developer, I want to integrate with a database to store content and assets</td><td>CosmosDB<em>† / Azure Functions</em>† / Static Web Apps*</td><td>Implementation or Integration</td><td>As a business owner I want all assets and information to stored safely and versioned</td></tr><tr><td>As a developer, I want to integrate with a (headless) CMS for 3rd party content authoring</td><td>Azure Functions<em>† / Static Web Apps</em></td><td>Implementation or Integration</td><td>As a content author, I want to see the new content published when I submit it to the content authoring tool</td></tr><tr><td>As a developer, I want to trigger the CI/CD workflows via custom/scheduled events</td><td>GitHub Actions* / Durable Functions**</td><td>Integration</td><td>As a business owner, I want my teams to automate the process of building and deploying new code or content so we can achieve optimal time-to-value</td></tr><tr><td>As a developer, I want to secure my implementation to make sure requests to our service come from my application</td><td>Indentity Platform†</td><td>Implementation or Integration</td><td>As a business owner, I want to make sure our e-commerce tool is secure and compliant with laws and regulations</td></tr><tr><td>As a developer, I want to restrict access to certain pages to users with a certain role</td><td>Identity Platform†</td><td>Implementation or Integration</td><td>As an end user, I want to keep a private profile with my payment methods and other PII</td></tr><tr><td>As a developer, I want to localize the UI to several different languages</td><td>Cognitive Services*†</td><td>Implementation or Integration</td><td>As an end user, I want to access content in my own language</td></tr><tr><td>As a developer, I want to personalize recommendations in dynamic pages</td><td>Cognitive Services*†</td><td>Implementation or Integration</td><td>As an end user, I want to have recommendations that are relevant to me</td></tr><tr><td>As a developer, I want to integrate with a 3rd party payment platform</td><td><em>3rd party</em> / Azure Functions*</td><td>Implementation or Integration</td><td>As a business owner, I want payments processed by a reliable 3rd party provider</td></tr><tr><td>As a developer, I want to preview and debug changes before I promote them to production</td><td>Static Web Apps Preview/Edge Developer Tools</td><td>Build/Deploy/Testing</td><td>As a business owner, I want to preview changes before they go live</td></tr><tr><td>As a developer, I want to reduce technical debt by implementing an e2e test automation suite</td><td>Playwright / GitHub Actions</td><td>Testing</td><td>As an end user, I want the user interface to respond quickly and accurately, when I interact with it</td></tr><tr><td>As a developer, I want to be able to publish my application to the web</td><td>Static Web Apps</td><td>Build/Deploy</td><td>As a business owner, I want my application to be accessible by web users from all parts of the world, with the least possible latency</td></tr><tr><td>As a developer, I want to enable a mechanism for the application to be accessible via a distributed network</td><td>Azure Front Door</td><td>Setup/Integration</td><td>As a user I want web pages I visit, to load very fast</td></tr><tr><td>As a developer I want to integrate with analytics tools, to share data with stakeholders</td><td>Static Web Apps / App Insights</td><td>Setup/Testing</td><td>As a business owner, I want to know what products are being queried the most to understand market trends</td></tr></tbody></table><p>(*)Expresses the ability to operate directly from the VS Code context via an extension, or locally with the CLI capability
(†) Expresses the existence of an SDK to accelerate and secure the implementation</p><blockquote><p><strong>As we can see, you don't need to be part of a massive organization or a large, distributed team, to implement certain workflows and give structure to your own development cycles in process, to gain in developer productivity and delightful experiences.</strong></p></blockquote><p>Writing down your own matrix as you start, and extending it as your application scales and has extended requirements, can help you better organize yourself, make sure you're implementing best practices, and even evaluate tools and technologies to make sure you're on the right, most optimal path.</p><p>Static Web Apps is a modern, low configuration capability for Jamstack development, that offers you a myriad of satellite integrations, for free! And it has the advantage of growing with you, should you need more capacity, more tools, or even a full migration.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="to-wrap-this-up">To wrap this up...<a href="#to-wrap-this-up" class="hash-link" aria-label="Direct link to To wrap this up..." title="Direct link to To wrap this up...">​</a></h2><p>Developer Experience is an end-to-end exercise that can be connected to the development, implementation and/or integration of a single feature or a group of them, from design, to execution, to testing, to release. </p><p>In order for developers to have a <em>great</em> experience they enjoy, from one end to the other, they need to find:</p><ul><li>guidelines that help them define a problem they can design an effective solution</li><li>technologies that are compatible as building blocks for it</li><li>complete, accurate and fresh documentation to support at all times</li><li>tools that simplify the <em>jobs to be done</em> or tasks, individual and collective (to a single developer or a team of them)</li><li>underlying mechanisms (exposed to the developer or not depending on their wishes or needs), for effectual program compilation, transpilation, testing, deployment and execution (such as runtimes and pipelines)</li><li>definitions and hooks for integration (with other technologies) or and migration (to other technologies)</li></ul><p>When all those, and some more, are fulfilled, developers become more productive, focused, and can spend their time doing what they love, instead of wasting it in undifferentiated tasks.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>Try to reproduce the architecture seen above! Most of the integrations are available to the free tier! Show us how far you got!</p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>best-practices</category>
        </item>
        <item>
            <title><![CDATA[#23: Cognitive Search & SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/practices-cognitive-search</link>
            <guid>https://www.azurestaticwebapps.dev/blog/practices-cognitive-search</guid>
            <pubDate>Tue, 24 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 4, Day 2 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 4, Day 2</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Yesterday, we kicked off "Best Practices" week by talking about the end-to-end developer experience. Key to this is the ability to seamlessly integrate relevant tools and services that enhance the user experience - without adding complexity to the developer workflow. Today, we'll look at this in practice, by walking through a tutorial that integrates your Azure Static Web Apps deployed website with <strong>Azure Cognitive Search</strong> - allowing you to add custom search capability to your deployed web app in just a few steps.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What is Azure Cognitive Search?</li><li>What is a Search Index?</li><li>Add Cognitive Search to a Website</li><li>Deploy to Azure Static Web Apps</li><li><strong>Exercise</strong>: Create your own search index. Deploy your app to SWA.</li></ul><p><img loading="lazy" src="/assets/images/23-banner-7829400df111a8a2022e6a411ac66aec.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="make-your-app-searchable">Make Your App Searchable!<a href="#make-your-app-searchable" class="hash-link" aria-label="Direct link to Make Your App Searchable!" title="Direct link to Make Your App Searchable!">​</a></h2><p>Today we explore adding search to a website with <a href="https://docs.microsoft.com/en-us/azure/search/search-what-is-azure-search" target="_blank" rel="noopener noreferrer">Azure Cognitive Search</a> - a cloud search service that provides infrastructure, APIs, and tools, for building rich integrated search capabilities for your mobile and web applications. It even allows for custom search functionality to enhance the default experience.</p><p>We'll walk through the following example today. Want to follow along? You can <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/" target="_blank" rel="noopener noreferrer">grab the source code</a> and explore it as we walk through the tutorial.</p><p>We will be using a <strong>Book Catalog</strong> example - one of the most common uses of search for a website - to demonstrate how fast it is to get this service up and running with your deployed Azure Static Web App.</p><p><img loading="lazy" alt="Sample with Cognitive Search functionality" src="/assets/images/cognitive-search-enabled-book-website-02bb16800c27a094125a915451aa099a.png" width="1503" height="682" class="img_ev3q"></p><p>This sample website provides access to a catalog of 10,000 books. The user experience goes something like this:</p><ul><li>The user searches the catalog by entering text in the search bar. </li><li>As they enter text, we can use the Search Index's suggest feature to complete the text proactively. </li><li>Once the query finishes, we display the results with a subset of details. </li><li>Users select a book to see the details stored in the book's Search Index.</li></ul><p>Simple, right? Let's look under the hood at how this works, and then dive into the implementation details.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-azure-cognitive-search">What is Azure Cognitive Search?<a href="#what-is-azure-cognitive-search" class="hash-link" aria-label="Direct link to What is Azure Cognitive Search?" title="Direct link to What is Azure Cognitive Search?">​</a></h2><p><a href="https://docs.microsoft.com/en-us/azure/search/search-what-is-azure-search" target="_blank" rel="noopener noreferrer">Azure Cognitive Search</a> is a cloud search service that gives you, as the developer, the ability to provide rich search experiences. Architecturally, a search service sits between the external data stores that contain your unindexed data, and your client app that sends query requests to a search index and handles the response.</p><p><img loading="lazy" alt="the roundtrip road of boring development" src="/assets/images/azure-search-diagram-f9a574f0bbffddfff49e59ec0e7a37dc.svg" width="820" height="153" class="img_ev3q"></p><p>Cognitive Search <strong>can integrate with other Azure services</strong> that automate data ingestion/retrieval from Azure data sources, and skillsets that incorporate consumable AI from Cognitive Services, such as image and natural language processing, or custom AI that you create in Azure Machine Learning or wrap inside Azure Functions.</p><p>Once you create your Azure resource for Cognitive Search, you can access it with the following key information:</p><ul><li><strong>Resource name:</strong> what you named your Cognitive Search instance.</li><li><strong>Index name:</strong> your resource can hold many indexes, each with its own identifiable name.</li><li><strong>Admin key:</strong> used to upload data into the search index</li><li><strong>Query key:</strong> used by the API to find data in the search index</li></ul><p>So, we've used the term <em>search index</em> many times - what does that mean?</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-a-search-index">What is a search index?<a href="#what-is-a-search-index" class="hash-link" aria-label="Direct link to What is a search index?" title="Direct link to What is a search index?">​</a></h2><p>Search functionality needs data to query. In Azure Cognitive Search, this data is held in a <em>search index</em>. Because this particular sample is already written for you, it includes the upload of the JSON data into the search index. If you're starting from scratch, look at the <a href="https://docs.microsoft.com/en-us/azure/search/search-get-started-portal" target="_blank" rel="noopener noreferrer">Quickstart</a> to learn how you can create an Azure Cognitive Search index with <strong>your</strong> data.</p><p>The trickiest part is mapping your data into Cognitive Search types. In order to do this, you provide a <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/bulk-insert/good-books-index.json" target="_blank" rel="noopener noreferrer">schema file</a> that describes each data field. </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="searchable-title">Searchable title<a href="#searchable-title" class="hash-link" aria-label="Direct link to Searchable title" title="Direct link to Searchable title">​</a></h3><p>An example of a field in the schema file for this book catalog is the book title:</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"title"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Edm.String"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"facetable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"filterable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"key"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"retrievable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"searchable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"sortable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"analyzer"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"standard.lucene"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"indexAnalyzer"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token null keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"searchAnalyzer"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token null keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"synonymMaps"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"fields"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>The <strong>type</strong> is a <code>Edm.String</code> and it uses the <code>standard.lucene</code> <strong>analyzer</strong>. It is searchable and retrievable (comes back in the query results).</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="filter-by-language">Filter by language<a href="#filter-by-language" class="hash-link" aria-label="Direct link to Filter by language" title="Direct link to Filter by language">​</a></h3><p>The book catalog search also allows a filter by language. This filter, known as a facet, is provided by the <strong>facetable</strong> property.</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"language_code"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Edm.String"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"facetable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"filterable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"key"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"retrievable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"searchable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"sortable"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"analyzer"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token null keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"indexAnalyzer"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token null keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"searchAnalyzer"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token null keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"synonymMaps"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"fields"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="suggest-search-terms-as-a-user-types">Suggest search terms as a user types<a href="#suggest-search-terms-as-a-user-types" class="hash-link" aria-label="Direct link to Suggest search terms as a user types" title="Direct link to Suggest search terms as a user types">​</a></h3><p>The schema also tells the search index what fields to watch when providing search <strong>suggesters</strong>, as the user types an entry in the search box. For this sample, suggestions are based on author names and book titles.</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">"suggesters"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sg"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"searchMode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"analyzingInfixMatching"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"sourceFields"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"authors"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"original_title"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Once the search index is created with data, you can view the data in the Visual Studio Code extension for Cognitive Search.</p><p><img loading="lazy" alt="Search index viewed with VS Code extension" src="/assets/images/visual-studio-code-search-extension-view-docs-1ee0d82da81abed12fb98bdf68f1fcc8.png" width="1329" height="794" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="add-search-to-website">Add search to website<a href="#add-search-to-website" class="hash-link" aria-label="Direct link to Add search to website" title="Direct link to Add search to website">​</a></h2><p>After the search index is created with the data, you can add search functionality through the UI. Your UI passes the user's search request to your API. The API queries the search index and returns the results. </p><p>The <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/src" target="_blank" rel="noopener noreferrer">client code</a> provides interactive functionality:</p><ul><li>Provides <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/src/components/SearchBar/SearchBar.js" target="_blank" rel="noopener noreferrer">Search component</a><ul><li>Provides <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/src/components/SearchBar/Suggestions/Suggestions.js" target="_blank" rel="noopener noreferrer">suggestions</a> from the API as the user types in the search box</li><li><a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/src/components/Facets/Facets.js" target="_blank" rel="noopener noreferrer">Filters the results</a> when the user selects or deselects from a list of filters (facets).</li></ul></li><li>Provides <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/src/components/Results/Results.js" target="_blank" rel="noopener noreferrer">results component</a>, possibly <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/src/components/Pager/Pager.js" target="_blank" rel="noopener noreferrer">paging</a>. </li></ul><p>The <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/tree/master/search-website/api" target="_blank" rel="noopener noreferrer">serverless code</a> provides the following API to respond to client requests:</p><ul><li><a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/api/Search/index.js" target="_blank" rel="noopener noreferrer">Search</a> the catalog</li><li>Provide <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/blob/master/search-website/api/Suggest/index.js" target="_blank" rel="noopener noreferrer">suggestions</a></li><li>Get <a href="https://github.com/Azure-Samples/azure-search-javascript-samples/tree/master/search-website/api/Lookup" target="_blank" rel="noopener noreferrer">specific item's</a> data</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-to-swa">Deploy to SWA<a href="#deploy-to-swa" class="hash-link" aria-label="Direct link to Deploy to SWA" title="Direct link to Deploy to SWA">​</a></h2><p>The sample is deployed to SWA from a GitHub action, created for you by the Visual Studio Code extension for SWA.</p><p>Once you create and deploy the sample, you need to set environment variables to connect from the serverless API to your Cognitive Search resource. Then the book catalog website is available and searchable. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-upload-data-to-search-index">Exercise: Upload data to search index<a href="#exercise-upload-data-to-search-index" class="hash-link" aria-label="Direct link to Exercise: Upload data to search index" title="Direct link to Exercise: Upload data to search index">​</a></h2><ol><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-overview#fork-and-clone-the-search-sample-with-git" target="_blank" rel="noopener noreferrer">Fork the GitHub sample repo</a>, and clone it to your local computer. This is a necessary step because the GitHub action needs to be written to a repo your user account has access to.</p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-overview#create-a-resource-group-for-your-azure-resources" target="_blank" rel="noopener noreferrer">Create a resource group</a> to hold both your SWA and Cognitive Search resources.</p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-create-load-index#create-an-azure-search-resource" target="_blank" rel="noopener noreferrer">Create a search index</a> in Visual Studio Code with the Cognitive Search extension.  </p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-create-load-index#create-an-azure-search-resource" target="_blank" rel="noopener noreferrer">Get the admin key</a>. </p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-create-load-index#prepare-the-bulk-import-script-for-search" target="_blank" rel="noopener noreferrer">Set admin key and resource name</a> in sample's bulk_insert_books.js script. </p></li><li><p>Don't check in these changes with git. You don't want these secrets in your public fork.</p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-create-load-index#run-the-bulk-import-script-for-search" target="_blank" rel="noopener noreferrer">Install dependencies and bulk insert data</a> in the <code>./bulk-insert</code> folder:</p><div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npm install </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> npm start</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li><p>Your search index is ready to answer search queries.</p></li></ol><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-deploy-swa-to-azure">Exercise: Deploy SWA to Azure<a href="#exercise-deploy-swa-to-azure" class="hash-link" aria-label="Direct link to Exercise: Deploy SWA to Azure" title="Direct link to Exercise: Deploy SWA to Azure">​</a></h2><ol><li><p>In Visual Studio Code, <a href="https://docs.microsoft.com/azure/search/tutorial-javascript-deploy-static-web-app#create-a-static-web-app-in-visual-studio-code" target="_blank" rel="noopener noreferrer">create the SWA resource</a>. This process adds a GitHub action YAML file to your fork and deploys that version to your SWA resource.</p><p>At this point, the website should be available, but search isn't connected yet.</p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-deploy-static-web-app#get-cognitive-search-query-key-in-visual-studio-code" target="_blank" rel="noopener noreferrer">Get the query key</a> for your search index. Your API needs these secrets (query key and Cognitive Search resource name), to answer queries from your serverless API.</p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-deploy-static-web-app#add-configuration-settings-in-azure-portal" target="_blank" rel="noopener noreferrer">Set the secrets</a> for your serverless API in the Azure portal. </p><p>Search is now connected from your API to your Cognitive Search index.</p></li><li><p><a href="https://docs.microsoft.com/azure/search/tutorial-javascript-deploy-static-web-app#use-search-in-your-static-web-app" target="_blank" rel="noopener noreferrer">Use your search-enabled website</a> to find a book. </p></li><li><p>Type <em>slowly</em> to see the suggestions based on what you enter.</p></li><li><p>Filter the results to a different language. </p></li><li><p>Select a book to see all its details. </p></li></ol><h2 class="anchor anchorWithStickyNavbar_LWe7" id="troubleshooting">Troubleshooting<a href="#troubleshooting" class="hash-link" aria-label="Direct link to Troubleshooting" title="Direct link to Troubleshooting">​</a></h2><ul><li>Make sure you used the <strong>admin key</strong> in the upload file.</li><li>Make sure you used the <strong>query key</strong> in the SWA config. </li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="next-steps">Next steps<a href="#next-steps" class="hash-link" aria-label="Direct link to Next steps" title="Direct link to Next steps">​</a></h2><p>This website provides basic search functionality for books. Go beyond the basics with:</p><ul><li><a href="https://docs.microsoft.com/en-us/azure/search/speller-how-to-add" target="_blank" rel="noopener noreferrer">Spell check</a></li><li><a href="https://docs.microsoft.com/en-us/azure/search/search-query-fuzzy" target="_blank" rel="noopener noreferrer">Fuzzy search</a></li><li><a href="https://docs.microsoft.com/en-us/azure/search/semantic-ranking" target="_blank" rel="noopener noreferrer">Semantics</a></li></ul><p>This is just one of many samples provided in the <a href="https://docs.microsoft.com/en-us/azure/developer/javascript/how-to/create-static-web-app" target="_blank" rel="noopener noreferrer">Azure for JavaScript Developers</a> page. Explore the Static Web Apps section and explore other Azure services you can integrated into your modern web app!</p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>best-practices</category>
        </item>
        <item>
            <title><![CDATA[#24: Cognitive Services & SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/practices-cognitive-services</link>
            <guid>https://www.azurestaticwebapps.dev/blog/practices-cognitive-services</guid>
            <pubDate>Wed, 25 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 4, Day 3 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 4, Day 3</code> of <strong>#30DaysOfSWA</strong>!!</p><p>We continue our Best Practices week by looking at year another Azure Services integration option for your Azure Static Web Apps deployment. Yesterday we talked about adding search to your website using pre-trained Azure AI models. Today we'll discuss how you can use Vision AI Services.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What are Azure Vision Services</li><li>How to get started building your AI applications</li><li>How to use the JavaScript AI SDKs</li><li>How to analyze a document using Form Recognizer</li><li>How to deploy your APIs and Static Web App(SWA)</li><li><strong>Exercise</strong> <a href="https://docs.microsoft.com/samples/azure-samples/js-e2e-client-cognitive-services/build-and-deploy-a-static-web-app-to-azure/?WT.mc_id=javascript-68057-ayyonet" target="_blank" rel="noopener noreferrer">Build and deploy a SWA to analyse images</a></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><ul><li><a href="https://aka.ms/AzureCustomVision" target="_blank" rel="noopener noreferrer">Azure Custom Vision</a> - Documentation</li><li><a href="https://docs.microsoft.com/en-us/learn/paths/explore-computer-vision-microsoft-azure/?WT.mc_id=javascript-68057-ayyonet" target="_blank" rel="noopener noreferrer">Azure AI Fundamentals: Explore computer vision</a> - Learn Module</li><li><a href="https://docs.microsoft.com/azure/static-web-apps/deploy-nextjs?WT.mc_id=javascript-68057-ayyonet" target="_blank" rel="noopener noreferrer">SWA Next.js </a> - Documentation</li></ul><p><img loading="lazy" src="/assets/images/24-banner-ab6720f7206b937aa107fdbb0084e7e9.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-are-azure-vision-services">What are Azure Vision Services?<a href="#what-are-azure-vision-services" class="hash-link" aria-label="Direct link to What are Azure Vision Services?" title="Direct link to What are Azure Vision Services?">​</a></h2><p>Azure AI Vision is part of <a href="https://docs.microsoft.com/azure/cognitive-services/what-are-cognitive-services?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Azure Cognitive Services</a> - cloud-based AI services that give you Terminator-like powers.</p><p><img loading="lazy" src="https://media.giphy.com/media/NHUaA15Nk910hFczxu/giphy.gif" class="img_ev3q"></p><p>You can take a picture and <a href="https://docs.microsoft.com/azure/cognitive-services/computer-vision/quickstarts-sdk/image-analysis-client-library?tabs=visual-studio&amp;pivots=programming-language-javascript&amp;WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">analyze it to describe the image, detect objects, landmarks and famous people</a> or <a href="https://docs.microsoft.com/azure/cognitive-services/face/build-enrollment-app?tabs=android&amp;WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">your users</a>, <a href="https://docs.microsoft.com/azure/cognitive-services/computer-vision/quickstarts-sdk/client-library?tabs=visual-studio&amp;pivots=programming-language-javascript&amp;WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">read documents</a> and scan information on an ID or a business card. All of these superpowers are available to you - an API call away - using Azure’s Cognitive and Applied AI Services. Let’s dive into what we can build and what we can customize.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="get-started-building-ai-apps">Get Started building AI apps<a href="#get-started-building-ai-apps" class="hash-link" aria-label="Direct link to Get Started building AI apps" title="Direct link to Get Started building AI apps">​</a></h2><p>If you are planning to infuse your application with AI, the first place you need to look at is our <a href="https://docs.microsoft.com/azure/applied-ai-services/?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Applied AI Services</a>. Applied AI services are solving the most common use cases and build on top of our Cognitive Services. In terms of Vision related services, we have two Applied AI Services, <a href="https://docs.microsoft.com/azure/applied-ai-services/form-recognizer/?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Form Recognizer</a> and <a href="https://docs.microsoft.com/azure/azure-video-analyzer/?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Video Analyzer</a>.</p><p>Azure Form Recognizer is built using <a href="https://docs.microsoft.com/azure/cognitive-services/computer-vision/overview-ocr?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Optical Character Recognition(OCR)</a>, <a href="https://docs.microsoft.com/azure/cognitive-services/language-service/overview?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Text Analytics</a> and <a href="https://docs.microsoft.com/azure/cognitive-services/language-service/custom-text-classification/overview?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Custom Text</a> from Azure Cognitive Services and has <a href="https://docs.microsoft.com/azure/applied-ai-services/form-recognizer/concept-custom?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">custom trained models</a> for things like vaccination cards, passports and tax documentation. If you are wondering why you need Form Recognizer, you can try reverse engineering some of its features by using the Cognitive Services.</p><p><img loading="lazy" src="https://media.giphy.com/media/tH2Ur5u1wpfPDNHhgm/giphy.gif" alt="Building things from scratch instea of using a ready solution" class="img_ev3q"></p><p>I won’t wish that for any of you and that’s why your first stop should be <a href="https://docs.microsoft.com/azure/applied-ai-services/?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Applied AI Services documentation</a> to see if your problem is solvable by any of these services. Whenever your problem is not solved or you need more flexibility, you can build with Cognitive Services, <a href="https://docs.microsoft.com/azure/cognitive-services/computer-vision/overview-image-analysis?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Computer Vision</a>, <a href="https://docs.microsoft.com/azure/cognitive-services/custom-vision-service/?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Custom Vision</a> or <a href="https://docs.microsoft.com/azure/cognitive-services/face/overview?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Face</a> APIs.</p><p>A great way to start playing with these APIs and explore your specific use case is through <a href="https://preview.vision.azure.com/" target="_blank" rel="noopener noreferrer">Vision Studio Preview</a> or <a href="https://formrecognizer.appliedai.azure.com/studio" target="_blank" rel="noopener noreferrer">Form Recognizer Studio preview</a>. For example, I was wondering if I can recognize Mixed Reality devices using Computer Vision. Since these devices are very new and still not a common object, they were not recognized by our all-purpose object detection model. Before building an app, I was able to easily see that I need to train a custom model. You can check and see your logo or your product is easily recognizable or you should start training a custom model on the Studio without writing any code and find the code samples right inside the Studio.</p><p>If the object you want to detect is not recognized, you can train a custom model through <a href="https://customvision.ai" target="_blank" rel="noopener noreferrer">customvision.ai</a> and deploy it. You will get a custom API endpoint to call and your client implementation won’t be different than using any other service. There are couple of best practices for training a custom model. Most importantly, you need a variety of images in different contexts. For example if you want to find Waldo, you can’t just train with Waldo’s profile picture, you need to also use his pictures in a crowd.</p><p>You can read how I’ve trained my custom model and built an <a href="https://medium.com/microsoftazure/no-code-ai-app-with-azure-cognitive-services-custom-vision-and-power-apps-ca47c019dcd0" target="_blank" rel="noopener noreferrer">No Code prototype here</a> using <a href="https://docs.microsoft.com/ai-builder/overview?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Power Apps AI Builder</a></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-to-use-the-javascript-ai-sdks">How to use the JavaScript AI SDKs<a href="#how-to-use-the-javascript-ai-sdks" class="hash-link" aria-label="Direct link to How to use the JavaScript AI SDKs" title="Direct link to How to use the JavaScript AI SDKs">​</a></h2><p>Using any of these APIs works pretty much the same way if you are working with an image instead of a video to analyze:</p><ul><li>Sign into your Azure account or <a href="https://azure.microsoft.com/free/?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">sign up for $200 free credit</a>.</li><li><a href="https://docs.microsoft.com/en-us/azure/cognitive-services/cognitive-services-apis-create-account?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Create an Azure Cognitive Services or Specific service resource</a> and get the key and endpoint information.</li><li>Install the related service’s <a href="https://www.npmjs.com/~azure-sdk" target="_blank" rel="noopener noreferrer">JavaScript SDK</a> and <a href="https://www.npmjs.com/package/@azure/identity" target="_blank" rel="noopener noreferrer">Azure Identity SDK</a>.</li><li>Take a picture or upload an image.</li><li>Initialize an AzureCredentials object using your resource key.</li><li>Initialize a Client object with the Azure credential object &amp; endpoint.</li><li>Use the client’s analyze method to make an API call, wait for response.</li></ul><p>The class and method names change, like <code>DocumentAnalysisClient</code> for Form Recognizer, <code>PredictionAPIClient</code> for Custom Vision or <code>FaceClient</code> for facial recognition. If you are training a custom model or using a specific model for form recognizer, you have couple of things that you will do but the most important part of it is taken care of by our SDK functionality.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-to-analyze-a-document-using-form-recognizer">How to analyze a document using Form Recognizer<a href="#how-to-analyze-a-document-using-form-recognizer" class="hash-link" aria-label="Direct link to How to analyze a document using Form Recognizer" title="Direct link to How to analyze a document using Form Recognizer">​</a></h2><p>Let’s see the code in action for Form Recognizer using their <a href="https://www.npmjs.com/package/@azure/ai-form-recognizer/v/4.0.0-beta.3" target="_blank" rel="noopener noreferrer">new JavaScript SDK</a>. You can start with your <a href="https://github.com/staticwebdev" target="_blank" rel="noopener noreferrer">choice of Static Web Apps templates</a> or add the code to your existing application.</p><p>We need to import the SDK objects and your environment variables:</p><div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">    </span><span class="token imports maybe-class-name">AzureKeyCredential</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">    </span><span class="token imports maybe-class-name">DocumentAnalysisClient</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">    </span><span class="token imports maybe-class-name">DocumentField</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">    </span><span class="token imports maybe-class-name">FormRecognizerApiVersion</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">    </span><span class="token imports maybe-class-name">PrebuiltModels</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports"></span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@azure/ai-form-recognizer"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FORM_RECOGNIZER_KEY</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> endpoint </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FORM_RECOGNIZER_ENDPOINT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>In your async callback function that starts the analysis, like a picture upload or click event callback, you will initialize the client object and poll until you have all the results from your analysis.</p><div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Analyze</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> client </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">DocumentAnalysisClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">endpoint</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">AzureKeyCredential</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> poller </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">beginAnalyzeDocument</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"prebuilt-document"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> formUrl</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> keyValuePairs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> entities </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> poller</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">pollUntilDone</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//Do amazing things with the data.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Do something with the results, either sign in your user with their ID doc data or display the key value pairs to your user.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deploy-your-app-to-swa">Deploy your app to SWA<a href="#deploy-your-app-to-swa" class="hash-link" aria-label="Direct link to Deploy your app to SWA" title="Direct link to Deploy your app to SWA">​</a></h2><p>If you are using one of the SWA templates, all you need to do is push your code to share it with the word.</p><p>If you are not using a template, you can use the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps" target="_blank" rel="noopener noreferrer">Azure Static Web Apps VS Code Extension</a> or <a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer">SWA CLI</a> to <a href="https://docs.microsoft.com/azure/static-web-apps/deploy-nextjs?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">deploy your app to an</a> SWA resource.</p><p>If you have a lot of images and would like to batch process or if you are doing multiple things with your image, like detect objects, read the text in the image and translate, you might want to use a <a href="https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">Azure Functions App</a>. Thankfully <a href="https://docs.microsoft.com/azure/static-web-apps/functions-bring-your-own?WT.mc_id=javascript-57623-ayyonet" target="_blank" rel="noopener noreferrer">creating and API for your Static Web App</a> is one of the features of the VSCode extension.
Check out my video for step by step instructions to deploy your SWA with Functions.</p><p><a href="https://youtu.be/VzML-6DClVU" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://img.youtube.com/vi/VzML-6DClVU/0.jpg" alt="How to add an API to your Azure Static Web App | Azure Tips and Tricks: Static Web Apps" class="img_ev3q"></a></p><p>I hope you are inspired to enhance your applications with Azure Applied AI or Cognitive Services. Checkout the <a href="https://aka.ms/MSBuild2022" target="_blank" rel="noopener noreferrer">Build AI talk</a> and <a href="https://github.com/Azure-Samples/papiro" target="_blank" rel="noopener noreferrer">demo</a> to see what else you can do with AI.</p><p><a href="https://youtu.be/L10-LnbXxEo" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://media.giphy.com/media/YSsOvebCkyeglsqsaQ/giphy.gif" alt="MS Build 2022 AI Session Demo" class="img_ev3q"></a></p><p><a href="https://twitter.com/AysSomething" target="_blank" rel="noopener noreferrer">Reach out to me on twitter</a> if you have questions, you want to share what you build or discuss your ideas.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>Want to explore Azure Cognitive Service integrations with your Azure Static Web App? Try walking through one of these tutorials to get hands-on experience with development:</p><ul><li><a href="https://docs.microsoft.com/samples/azure-samples/js-e2e-client-cognitive-services/build-and-deploy-a-static-web-app-to-azure/?WT.mc_id=javascript-68057-ayyonet" target="_blank" rel="noopener noreferrer">Build and deploy a SWA to analyse images</a> - build a React application that analyzes an image using Azure Cognitive Services (Computer Vision) - deploy the app to Azure Static Web Apps.</li><li><a href="http://aka.ms/ws-customvision" target="_blank" rel="noopener noreferrer">Machine Learning With Custom Vision</a> - complete this workshop where you learn to build a model to detect dog breeds using the Custom Vision API, then deploy it to Azure Static Web Apps with an Azure Functions backend.</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>best-practices</category>
            <category>AI</category>
            <category>ComputerVision</category>
            <category>CognitiveServices</category>
        </item>
        <item>
            <title><![CDATA[#25: KlipTok & SWA: Case Study]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/practices-case-study</link>
            <guid>https://www.azurestaticwebapps.dev/blog/practices-case-study</guid>
            <pubDate>Thu, 26 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 4, Day 4 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 4, Day 4</code> of <strong>#30DaysOfSWA</strong>!! </p><p>Week 4 focuses on Best Practices for Azure Static Web Apps. In the last two posts we explored Azure Services integrations that enhance and extend the capabilities of your deployed static website. Today, we take things in a different direction with our first <strong>Case Study</strong> - featuring  <a href="https://kliptok.com" target="_blank" rel="noopener noreferrer">KlipTok</a>, a <a href="https://twitch.tv" target="_blank" rel="noopener noreferrer">Twitch</a> clip search and indexing service built by Jeff Fritz, and hosted on Azure Static Web Apps!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What is KlipTok?</li><li>Why did KlipTok choose Azure Static Apps?</li><li>How do Azure Static Apps and Blazor work together?</li><li><strong>Exercise</strong>: Check out the <a href="https://kliptok.com" target="_blank" rel="noopener noreferrer">KlipTok</a> website and see it in action.</li></ul><p><img loading="lazy" src="/assets/images/25-banner-cc7ac88ea8ec3a509d9e466aa991ce50.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="kliptok-makes-twitch-videos-searchable">KlipTok Makes Twitch Videos Searchable<a href="#kliptok-makes-twitch-videos-searchable" class="hash-link" aria-label="Direct link to KlipTok Makes Twitch Videos Searchable" title="Direct link to KlipTok Makes Twitch Videos Searchable">​</a></h2><p><a href="https://kliptok.com" target="_blank" rel="noopener noreferrer">KlipTok</a> is a website that I started building while streaming live on Twitch in November 2019.  At the time, I wanted to build a website that would allow folks to discover Twitch clips from their favorite creators in the same way that they navigate and interact with TikTok. </p><p><a href="https://twitch.tv" target="_blank" rel="noopener noreferrer">Twitch</a> is a live-streaming service that many people use to watch folks play video games.  When something interesting happens on Twitch, viewers can isolate a clip (up to 60 seconds long) from the stream and share it with their friends.  These clips are often fun and interesting, but typically they are not discoverable.  This is <strong>KlipTok's goal - index and make those clips more available to everyone</strong>.</p><p><img loading="lazy" alt="Screenshot of the KlipTok Website" src="/assets/images/kliptok-site-b225ffed0aaa079117dbfd68b1ec4419.png" width="1143" height="783" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-does-kliptok-work">How does KlipTok Work?<a href="#how-does-kliptok-work" class="hash-link" aria-label="Direct link to How does KlipTok Work?" title="Direct link to How does KlipTok Work?">​</a></h2><p>Behind the scenes, KlipTok monitors Twitch for new clips from streamers that are signed up with the site and indexes them.  The clips are then transcribed and searchable on the site.  Visitors can view, like, and comment on clips.  Additionally, anyone can create playlists of clips to share with their friends.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/6uMCAHEM8Es" title="YouTube video player" frameborder="0"></iframe><p>You can read the full story behind my decision process <a href="https://jeffreyfritz.com/2021/04/introducing-kliptok/" target="_blank" rel="noopener noreferrer">on my blog</a> or watch me build a subset of its features on a livestream in Nov 2020, in the video above.</p><p>After the first 18 months of running KlipTok, the <strong>application currently manages almost 12 million clips, totalling nearly 60 GB of data in the index</strong>.  You can view the live dashboard at <a href="https://kliptok.com/status" target="_blank" rel="noopener noreferrer">kliptok.com/status</a> to see the current status of the application.</p><p> <img loading="lazy" alt="Screenshot of the KlipTok dashboard showing almost 12 million clips" src="/assets/images/kliptok-dashboard-7e7559d51f8308b612ef84568c0269ca.png" width="690" height="231" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="kliptok-chooses-azure-static-apps">KlipTok Chooses Azure Static Apps<a href="#kliptok-chooses-azure-static-apps" class="hash-link" aria-label="Direct link to KlipTok Chooses Azure Static Apps" title="Direct link to KlipTok Chooses Azure Static Apps">​</a></h2><p> I chose <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview" target="_blank" rel="noopener noreferrer">Azure Static Apps</a> to build and deploy the KlipTok application, and to help demonstrate <a href="https://blazor.net" target="_blank" rel="noopener noreferrer">Blazor</a> running at scale in a large application.  This allows the application to <strong>scale the HTTP services to deliver content</strong> into the browser while delivering a high-performance experience with the Blazor application running in the browser on top of WebAssembly. </p><p> KlipTok also operates a second <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview" target="_blank" rel="noopener noreferrer">Azure Functions</a> service called the 'BackOffice' that performs the <strong>synchronization of Twitch clips</strong> and other data aggregation tasks.  When new channels are added to KlipTok for monitoring, the BackOffice service is triggered with a message on <a href="https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview" target="_blank" rel="noopener noreferrer">Azure Service Bus</a> to add the channel and begin processing their clips for the index.  </p><p> We also use this Backoffice functions app to create an <a href="https://docs.microsoft.com/en-us/dotnet/machine-learning/" target="_blank" rel="noopener noreferrer">ML.NET</a> model that is used to <strong>recommend streamers to the user</strong>.  The model is trained on the collection of channels that KlipTok users follow and recommends channels to users based on other users who follow the same channels.	The model is updated every day with new data to help make more accurate recommendations to logged in KlipTok users. </p><p> By Twitch's terms of service, no videos are allowed to be shipped off of their platform for the first 24 hours after they are recorded.  This means that the clips should be referenced and embedded from Twitch using their own clip player, saving KlipTok from having to download and store the content. KlipTok can now deliver appropriate SEO-optimized content as well as render open-graph cards appropriate for Twitter, Facebook, LinkedIn and other sites.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-kliptok-architecture">The KlipTok Architecture<a href="#the-kliptok-architecture" class="hash-link" aria-label="Direct link to The KlipTok Architecture" title="Direct link to The KlipTok Architecture">​</a></h2><p>We do have one small problem when using Blazor Web Assembly and Azure Static Websites -- search engines and social media sites do not know <strong>how to crawl and present web assembly generated content</strong>.  </p><p>To solve this, I added <a href="https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview" target="_blank" rel="noopener noreferrer">Azure Front Door</a> to the site with an Azure App Service we ironically call the 'Static Site'. Azure Front Door is Microsoft’s modern cloud Content Delivery Network (CDN) - allowing us to take advantage of a globally-distributed edge network to make our content delivery faster and more efficient.</p><p>With a few rules added to Azure Frontdoor (to detect bots), users can now be redirected to the static site and KlipTok can deliver appropriate SEO optimized content along with the <a href="https://ogp.me/" target="_blank" rel="noopener noreferrer">open-graph</a> cards for Twitter, Facebook, LinkedIn and other social sharing sites.</p><p> <img loading="lazy" alt="Simplified Diagram of the KlipTok System Architecture" src="/assets/images/kliptok-architecture-simplified-36827cbae5acd8f594b589288919d468.png" width="632" height="485" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-azure-static-web-apps">Why Azure Static Web Apps?<a href="#why-azure-static-web-apps" class="hash-link" aria-label="Direct link to Why Azure Static Web Apps?" title="Direct link to Why Azure Static Web Apps?">​</a></h2><p>When KlipTok was originally conceived, I wanted to <strong>spend very little money and allow the site to scale easily</strong> with new traffic as it grows.  As a C# and Blazor developer, this gave me the perfect intersection of my favorite technologies, keep costs low, and start to develop an application that demonstrates the capabilities of Blazor with a <strong>VERY</strong> large dataset.</p><p>Over time, the system components of KlipTok have matured and been swapped out.  Azure Table Storage gave way to MySQL and has been since replaced by RavenDb.  The Azure Functions were originally communicating using Azure Queues, and many of them are now using Azure Service Bus.</p><p>This maturing of the system components has allowed me to build and understand how other customers are using Azure and how we can improve the product to make developers of systems like KlipTok more productive. </p><p>Using Azure Static Web Apps makes it easier for developers to integrate other Azure services - which then makes it possible for me to evolve KlipTok's architecture and capabilities quickly, to reflect changing needs.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="swa--blazor-made-for-each-other">SWA &amp; Blazor: Made for each other<a href="#swa--blazor-made-for-each-other" class="hash-link" aria-label="Direct link to SWA &amp; Blazor: Made for each other" title="Direct link to SWA &amp; Blazor: Made for each other">​</a></h2><p>As a developer, I've been very happy with the combination of Blazor and Azure Static Web Apps.  The ability to build a Blazor application and know that I will always have APIs scaling to meet my customers needs is a huge plus.</p><p>Blazor Web Assembly uses an HttpClient to communicate with web servers;in the case of an Azure Static Web App it communicated with an HTTP triggered function.  This allows me to dramatically simplify the definition and interaction of front-end code and the back-end code.</p><p>For example: when a user clicks the <strong>Like</strong> button on a clip, the Blazor application can post a message to the hosted function to increment the like count.  This function then updates the like count in RavenDb, then updates the UI with the new like count.  The Blazor application needn't wait for the function to complete before updating the UI - it can just add or subtract one from the like count.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2><p>KlipTok has been an absolute joy to build and the journey to deliver it has been a great success.  I'm very excited to continue working on KlipTok and continue to grow the application while discovering and demonstrating more cool Blazor and Azure features. Have questions or comments? Find me on Twitch </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><ul><li><strong>Want to see this Azure Static Web App in action</strong>? Click over to <a href="https://kliptok.com" target="_blank" rel="noopener noreferrer">KlipTok</a> and login with your Twitch account! Then browse the site  to have KlipTok start showing you clips from your favorite creators. </li><li><strong>Want to explore building your own Azure Static Web App with Blazor?</strong> Check out my <a href="/blog/build-with-blazor#exercise-remix-fritzs-hats">earlier blog post</a> for a great exercise where you'll start with my open-source project - <a href="https://github.com/csharpfritz/Fritz.HatCollection" target="_blank" rel="noopener noreferrer">Fritz's Really Cool Hats</a> - to customize, build and deploy a Blazor-powered app to Azure Static Web Apps.</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>best-practices</category>
        </item>
        <item>
            <title><![CDATA[#26: Azure Functions & SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/practices-byo-functions</link>
            <guid>https://www.azurestaticwebapps.dev/blog/practices-byo-functions</guid>
            <pubDate>Fri, 27 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 4, Day 5 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 4, Day 5</code> of <strong>#30DaysOfSWA</strong>!! </p><p>All week, we'll explore end-to-end development workflows with Azure Static Web Apps as one component that is integrated with other services to deliver an enhanced modern web application experience.</p><p>The default Azure Static Web Apps architecture separates the web application into two components: static assets (served from global content distribution services) and dynamic API endpoints (implemented using serverless architectures). In our <a href="/blog/blog/deploying-swa">API-enabling SWA</a> post, we focused on <strong>Managed Functions</strong>, where the Azure Static Web Apps service configures and manages your Azure Functions Deployment.</p><p>Today, we'll explore the other option <strong>Bring Your Own Functions</strong> - where you can use pre-existing (or independently developed) Azure Functions applications and manage their deployment separately.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What is "Bring Your Own Functions" (BYOF)? </li><li>Benefits of BYOF over Managed Functions</li><li>Switching from Managed Functions to BYOF</li><li><strong>Resources</strong>: Building Serverless apps with Azure Functions</li><li><strong>Exercise</strong>: Complete <a href="https://docs.microsoft.com/en-us/learn/modules/automatic-update-of-a-webapp-using-azure-functions-and-signalr/" target="_blank" rel="noopener noreferrer">this learning module</a>, add real-time updates to your SWA!</li></ul><p><img loading="lazy" src="/assets/images/26-banner-ee6f6144b61a1105d00210e8edd5b271.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-does-bring-your-own-functions-byof-mean">What does "Bring Your Own Functions" (BYOF) mean?<a href="#what-does-bring-your-own-functions-byof-mean" class="hash-link" aria-label="Direct link to What does &quot;Bring Your Own Functions&quot; (BYOF) mean?" title="Direct link to What does &quot;Bring Your Own Functions&quot; (BYOF) mean?">​</a></h2><p>In our <a href="/blog/blog/deploying-swa">API-enabling SWA</a> post, we mentioned that the Azure Static Web App can implement Serverless API using Azure Functions in two ways:</p><ul><li><strong>Managed Functions</strong> - where the Azure Static Web Apps service configures and manages your Azure Functions deployment.</li><li><strong>Bring Your Own Functions</strong> - where you use a pre-existing Azure Functions application and manage the deployment yourself.</li></ul><p>The second option means that you build and deploy a serverless application using Azure Functions that exists <em>independent</em> of your Azure Static Web App deployment. These applications can make use of the <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview" target="_blank" rel="noopener noreferrer">full Azure Functions feature set</a> without any of the limitations imposed for Managed Functions in SWA. All you need to do is <strong>configure</strong> the Static Web App service to use this new serverless API endpoint.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-bring-your-own-functions">Why "Bring Your Own Functions"?<a href="#why-bring-your-own-functions" class="hash-link" aria-label="Direct link to Why &quot;Bring Your Own Functions&quot;?" title="Direct link to Why &quot;Bring Your Own Functions&quot;?">​</a></h2><p>Bring Your Own Functions is a power feature of Azure Static Web Apps that lets you link existing Functions apps and allows you to <strong>avoid the restrictions of Managed Functions</strong>. This means you can:</p><ul><li>Implement and run functions in any language using <strong><a href="https://docs.microsoft.com/azure/azure-functions/functions-custom-handlers" target="_blank" rel="noopener noreferrer">custom handlers</a></strong>.</li><li>Use <strong><a href="https://docs.microsoft.com/azure/azure-functions/functions-triggers-bindings?tabs=csharp" target="_blank" rel="noopener noreferrer">triggers and bindings</a></strong> to create complex workflows with ease.</li><li>Implement <strong><a href="https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-overview?tabs=csharp" target="_blank" rel="noopener noreferrer">Durable Functions</a></strong> that remain stateful in serverless contexts.</li><li>Use any other Azure Functions features and adopt <strong><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-best-practices?tabs=csharp" target="_blank" rel="noopener noreferrer">best practices</a></strong>.</li></ul><p>These kinds of capabilities become critical when you deploy real-world applications at scale. Note that Azure Static Web Apps has two hosting plans: free and standard where the Free tier supports only Managed Functions. To take advantage of the power of "Bring Your Own Functions" you need to be on the standard plan.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="linking-an-existing-functions-app">Linking an existing Functions app<a href="#linking-an-existing-functions-app" class="hash-link" aria-label="Direct link to Linking an existing Functions app" title="Direct link to Linking an existing Functions app">​</a></h2><p>Using an existing Functions app in Static Web Apps is easy - <strong>all your have to do is link the two apps together</strong>. Once you create the link, then a Functions app published under the following URL:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">https://my-functions-app.azurewebsites.net/api/data</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>...is now also available under the <code>api</code> route in your static web app. </p><p>For instance:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">https://red-sea-123.azurestaticapps.net/api/data</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Linking an existing Functions app is a two step process: (1) Update the <a href="https://docs.microsoft.com/azure/static-web-apps/configuration" target="_blank" rel="noopener noreferrer">staticwebapp.config.json</a> file, and (2) Link the apps via the Azure portal.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-update-the-configuration">1. Update the configuration<a href="#1-update-the-configuration" class="hash-link" aria-label="Direct link to 1. Update the configuration" title="Direct link to 1. Update the configuration">​</a></h3><p>Edit your site's <code>staticwebapp.config.json</code> file to make these changes:</p><ul><li>Set the <code>api_location</code> value to an empty string (<code>""</code>)</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-link-apps-via-the-azure-portal">2. Link apps via the Azure portal<a href="#2-link-apps-via-the-azure-portal" class="hash-link" aria-label="Direct link to 2. Link apps via the Azure portal" title="Direct link to 2. Link apps via the Azure portal">​</a></h3><p>Navigate to your static web app in the Azure portal and make these changes:</p><ul><li>Click on <strong>Functions</strong> in the <em>Settings</em> menu</li><li>Click <strong>Production</strong> in the <em>Environment</em> dropdown</li><li>Click <strong>Link to Function app</strong> next to the <em>Functions type</em> dropdown</li><li>Select your subscription from the <em>Subscription</em> dropdown</li><li>Select your Functions app name from the <em>Function App</em> dropdown</li><li>Click the <strong>Link</strong> button</li></ul><p>Now your Functions app is linked to your website and is available under the <code>api</code> route for your Static Web App!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-overview">1. Overview<a href="#1-overview" class="hash-link" aria-label="Direct link to 1. Overview" title="Direct link to 1. Overview">​</a></h3><p>Are you new to the whole idea of serverless applications and a Functions-based backend? Watch this video overview of Azure Functions - then check out the <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=blob" target="_blank" rel="noopener noreferrer">developer guide</a>.</p><iframe width="640" height="360" src="https://www.youtube.com/embed/8-jz5f_JyEQ" title="YouTube video player" frameborder="0"></iframe><h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-quickstart">2. Quickstart<a href="#2-quickstart" class="hash-link" aria-label="Direct link to 2. Quickstart" title="Direct link to 2. Quickstart">​</a></h3><p>Want to get a quickstart with Azure Functions? You can code your functions in C#, Java, JavaScript, PowerShell, Python, TypeScript and more (e.g., Go, Rust). For example, you can create JavaScript Functions apps in the following ways:</p><ul><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node" target="_blank" rel="noopener noreferrer">Using Visual Studio Code</a></li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-node?tabs=azure-cli%2Cbrowser" target="_blank" rel="noopener noreferrer">Using Commandline Tools</a></li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-resource-manager?tabs=visual-studio-code%2Cazure-cli" target="_blank" rel="noopener noreferrer">Using an ARM Template</a> = JSON configuration file</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-learning-path">3. Learning Path<a href="#3-learning-path" class="hash-link" aria-label="Direct link to 3. Learning Path" title="Direct link to 3. Learning Path">​</a></h3><p>Want a more comprehensive tour of Azure Functions features and capabilities, with hands-on modules? Try the <a href="https://docs.microsoft.com/en-us/learn/paths/create-serverless-applications/" target="_blank" rel="noopener noreferrer">Create Serverless Applications</a> learning path. It has 11 modules covering both core concepts and usage examples.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>Complete <a href="https://docs.microsoft.com/en-us/learn/modules/automatic-update-of-a-webapp-using-azure-functions-and-signalr/" target="_blank" rel="noopener noreferrer">this learning module</a>to learn how to use Azure SignalR to get real-time updates to your app using Azure Functions. <em>Then put that learning to use by updating one of your existing SWA projects to use this capability</em>.</p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>best-practices</category>
        </item>
        <item>
            <title><![CDATA[#27: Video Conf with ACS & SWA]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/practices-cosmosdb</link>
            <guid>https://www.azurestaticwebapps.dev/blog/practices-cosmosdb</guid>
            <pubDate>Sat, 28 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 4, Day 6 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 4, Day 6</code> of <strong>#30DaysOfSWA</strong>!! </p><p>In an earlier example this week, we looked at a real-world case study with KlipTok, involving Azure Static Web Apps integration with <em>multiple</em> backend services, to deliver the desired user experience. Today we look at another great example of an end-to-end development workflow that involves multiple service integrations - this time with a focus on deliver a rich video conferencing web application experience. Let's learn how to build this with <strong>a workflow that involves Azure Static Web Apps, Azure Functions, Azure CosmosDB - and Azure Communications Services (ACS)</strong>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>What is Azure Communications Services (ACS)?</li><li>The Video Conference Authentication Workflow<ul><li>Azure Static Web Apps for social authentication</li><li>Azure CosmosDB to store ACS identity information</li><li>Azure Functions to map social auth to ACS identity</li></ul></li><li>A Static Web App - hosting a Metaverse? 🤯</li><li><strong>Exercise</strong> Deploy the sample yourself following the step-by-step tutorial</li></ul><p><img loading="lazy" src="/assets/images/27-banner-5146de1cca8588633d6475561df82410.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-azure-communications-services-acs">What is Azure Communications Services (ACS)?<a href="#what-is-azure-communications-services-acs" class="hash-link" aria-label="Direct link to What is Azure Communications Services (ACS)?" title="Direct link to What is Azure Communications Services (ACS)?">​</a></h2><p><a href="https://docs.microsoft.com/en-us/azure/communication-services/overview" target="_blank" rel="noopener noreferrer">Azure Communication Services (ACS)</a> is a set of <strong>rich communication, video, and SMS APIs</strong> to deploy your applications across any device, on any platform. If you want to enable emails, chat, audio/video conferencing, phone calls or SMS inside an existing app, this service is right for you. You can view it as your building blocks to create your own custom version of Microsoft Teams, it uses the same underlying infrastructure. This <a href="https://www.forbes.com/advisor/business/software/what-is-cpaas/" target="_blank" rel="noopener noreferrer">CPaaS</a> (Communications Platform As A Service) will manage scalability, quality &amp; availability of this service for you. This platform is also built on top of our secure and compliant cloud.  </p><p>Watch this short video for a quick introduction 👇🏼</p><iframe width="560" height="315" src="https://www.youtube.com/embed/chMHVHLFcao" title="YouTube video player" frameborder="0"></iframe><p>Of course, this service comes with a price. You can find the cost of each service by visiting <a href="https://azure.microsoft.com/en-us/pricing/details/communication-services/" target="_blank" rel="noopener noreferrer">Azure Communication Services pricing | Microsoft Azure</a>. </p><p>ACS exposes its services via various SDKs: <a href="https://github.com/Azure/communication" target="_blank" rel="noopener noreferrer">Azure Communication Services – Samples and Tools</a> available for JavaScript, .NET, Java, Android, iOS &amp; Python developers. </p><p>You can also optionally use this on top of the ACS UI library: <a href="https://azure.github.io/communication-ui-library/?path=/story/overview--page" target="_blank" rel="noopener noreferrer">Overview – Page ⋅ Storybook</a> which consists of React-based components implementing the <a href="https://developer.microsoft.com/fluentui/" target="_blank" rel="noopener noreferrer">Microsoft Fluent Design</a> to help you build visually engaging web apps. The best sample mixing all of these concepts is <strong><a href="https://docs.microsoft.com/en-us/azure/communication-services/samples/calling-hero-sample?pivots=platform-web" target="_blank" rel="noopener noreferrer">Group calling hero sample – An Azure Communication Services sample overview</a></strong>. </p><p>To give you a brief idea, watch this 2 min video tutorial that shows you how to get the internal ACS authentication token to connect to its infrastructure. I can then join an existing Teams meeting using a simple web page and the ACS JavaScript SDK:</p><iframe width="560" height="315" src="https://www.youtube.com/embed/FFBBLUtRyZw" title="YouTube video player" frameborder="0"></iframe><p><strong>Want to follow along at home?</strong> You simply need to:</p><ul><li><a href="https://docs.microsoft.com/en-us/azure/communication-services/quickstarts/create-communication-resource?tabs=windows&amp;pivots=platform-azp" target="_blank" rel="noopener noreferrer">Create an Azure Communication Services resource in your Azure Portal</a> </li><li>Navigate to <a href="https://aka.ms/acsquicktest" target="_blank" rel="noopener noreferrer">https://aka.ms/acsquicktest</a> and follow the video tutorial above.</li></ul><p>You’ll discover that, by default, Azure Communication Services provides the basic authentication &amp; identity layer. But you need to build on top of it to connect your own identity platform. Let’s see how to do that, next!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="building-an-authentication-layer-with-azure-function-cosmosdb--static-web-app">Building an authentication layer with Azure Function, CosmosDB &amp; Static Web App<a href="#building-an-authentication-layer-with-azure-function-cosmosdb--static-web-app" class="hash-link" aria-label="Direct link to Building an authentication layer with Azure Function, CosmosDB &amp; Static Web App" title="Direct link to Building an authentication layer with Azure Function, CosmosDB &amp; Static Web App">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-azure-static-web-apps---social-authentication">1. Azure Static Web Apps - social authentication<a href="#1-azure-static-web-apps---social-authentication" class="hash-link" aria-label="Direct link to 1. Azure Static Web Apps - social authentication" title="Direct link to 1. Azure Static Web Apps - social authentication">​</a></h3><p>Well, it turns out that SWA provides an awesome out of the box authentication experience. To know more about it, please read: <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization?tabs=invitations" target="_blank" rel="noopener noreferrer">Authentication and authorization for Azure Static Web Apps</a>. In seconds, without any additional code required, you’ll have an authentication layer provided to you!</p><p>We’re going to use it as our front end to welcome and authenticate our users. </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-azure-functions---map-to-acs-identity">2. Azure Functions - map to ACS identity<a href="#2-azure-functions---map-to-acs-identity" class="hash-link" aria-label="Direct link to 2. Azure Functions - map to ACS identity" title="Direct link to 2. Azure Functions - map to ACS identity">​</a></h3><p>Then, we will map their social account identity with the internal ACS identity via an Azure Function. The Azure Function will store the mapping into a small CosmosDB table. Here’s the flow. </p><p>First, you’ll land on a page asking you to choose your favorite social provider:</p><p><img loading="lazy" alt="Screenshot of the Static Web App sample showing the Twitter, Github, Microsoft &amp;amp; Google logos" src="/assets/images/ACSSWA001-e655d56ddaf55e97d82a83a96250c726.jpg" width="1536" height="610" class="img_ev3q"></p><p>Then, once authenticated, you’ll be directly connected to the Azure Communication Services infrastructure. No need to generate a token or whatever, the Azure Function took care of it. I’ve been using my Twitter account in this screenshot for instance:</p><p><img loading="lazy" alt="Screenshot of the Static Web App sample once authentified, showing the web camera active" src="/assets/images/ACSSWA002-cfcc34d95d25a76a1e84c8d0a8a82873.jpg" width="2256" height="1434" class="img_ev3q"></p><p>You see that the UI shows how my Twitter account, <em>davrous@twitter</em>, is mapped to the internal ACS user ID <em>8:acs:4ba98fcc</em>… that you should normally not share to the users of course 😉. </p><p>Thanks to that, you’re ready to call friends and colleagues immediately or join a Teams meeting via simply using their social account email address as the person to call.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-azure-functions--cosmosdb-binding">3. Azure Functions + CosmosDB Binding<a href="#3-azure-functions--cosmosdb-binding" class="hash-link" aria-label="Direct link to 3. Azure Functions + CosmosDB Binding" title="Direct link to 3. Azure Functions + CosmosDB Binding">​</a></h3><p>Let’s have a look to the Azure Function code enabling this scenario. First, you can see in the <a href="https://github.com/davrous/acsauth/blob/main/api/users/function.json" target="_blank" rel="noopener noreferrer">function.json file</a> that I’m using the CosmosDB binding feature. To know more about this feature:</p><ul><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-cosmosdb-v2-input?tabs=in-process%2Cfunctionsv2&amp;pivots=programming-language-javascript" target="_blank" rel="noopener noreferrer">Azure Cosmos DB input binding for Functions 2.x and higher</a></li><li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-cosmosdb-v2-output?tabs=in-process%2Cfunctionsv2&amp;pivots=programming-language-csharp" target="_blank" rel="noopener noreferrer">Azure Cosmos DB output binding for Functions 2.x and higher</a></li></ul><p>In a nutshell, via a simple declaration in the <em>function.json</em> file, you have a simple data access layer available in your Azure Function code for free. </p><p>If you look into my json file, I’m defining a route under <em>users/{email}/{lookup:bool?}</em> that will be exposed under 2 functions in my Azure Function: <em>setUser</em> as the output binding (to write or update into CosmosDB) and <em>getUser</em> as the input binding (to read from CosmosDB). </p><p>In this declaration file, I’m also asking the Azure Function to use the CosmosDB database named “<em>ACS</em>” with the table named “<em>users</em>” using “<em>email</em>” parameter as the partition key. </p><p><em>getUser</em> will be called with a first required parameter which is an email address associated to the ACS internal identity. It has a second optional parameter which is a boolean. This asks to the Azure Function to do a simple resolve query to return the internal ACS id associated with the email address. It’s useful when you’d like to call someone on ACS by simply providing his email address rather than being forced to know its internal ACS identity (starting with <em>8:acs:xxx</em>).</p><p><em>setUser</em> simply create a new record or update it.</p><p>You can find the complete source code of the Azure Function there: <a href="https://github.com/davrous/acsauth/blob/main/api/users/index.ts" target="_blank" rel="noopener noreferrer">acsauth/index.ts at main · davrous/acsauth (github.com)</a>. </p><p>The first block is simply doing the resolve logic I was mentioning just before. The second block is first checking if the user has already been created in the CosmosDB table and if the ACS token is still valid. Indeed, ACS tokens are valid for 24 hours only. If the user doesn’t exist or if its token has expired, we’re using the ACS JavaScript SDK to create a new identity &amp; authentication token to map it to the email address. </p><p>If you’re interested in the ACS identity concepts, please read:</p><ul><li><a href="https://docs.microsoft.com/en-us/azure/communication-services/concepts/identity-model" target="_blank" rel="noopener noreferrer">Identity model - An Azure Communication Services concept</a></li><li><a href="https://docs.microsoft.com/en-us/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-javascript" target="_blank" rel="noopener noreferrer">Quickstart - Create and manage access tokens - An Azure Communication Services quickstart</a></li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-cosmosdb---stores-acs-identity-data">4. CosmosDB - stores ACS identity data<a href="#4-cosmosdb---stores-acs-identity-data" class="hash-link" aria-label="Direct link to 4. CosmosDB - stores ACS identity data" title="Direct link to 4. CosmosDB - stores ACS identity data">​</a></h3><p>Now, let’s have a look to what’s stored in the CosmosDB table thanks to the Azure Portal:</p><p><img loading="lazy" alt="Screenshot of Azure Portal, in the CosmosDB blade showing the content of the table" src="/assets/images/ACSSWA003-6bfaf3849bb96b70144a46f3aa55ac37.jpg" width="2196" height="909" class="img_ev3q"></p><p>You can find all the required information for my scenario:</p><ul><li><strong>id</strong>: an email address coming from the social network, which is my partition key and my primary key for my requests</li><li><strong>userId</strong>: the associated internal ACS identity in the form of 8:acs:xxxx.</li><li><strong>userToken</strong>: the associated internal ACS authentication token required to be able to connect to the ACS infrastructure</li><li><strong>expiresOn</strong>: when the ACS authentication token will expire</li></ul><p>The beauty of the Azure Function binding feature is that I didn’t have to write any code to manage the reading or writing part of the records. It can even update an existing record if needed. </p><p>With few lines of code, I’ve been able to create a small authentication layer on top of ACS to create users mapped to ACS internal identity. With the out of the box Static Web App authentication experience, I didn’t even need to write any code to authenticate users with their social identity!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-static-web-app-hosting-a-metaverse-">A Static Web App hosting a Metaverse? 🤯<a href="#a-static-web-app-hosting-a-metaverse-" class="hash-link" aria-label="Direct link to A Static Web App hosting a Metaverse? 🤯" title="Direct link to A Static Web App hosting a Metaverse? 🤯">​</a></h2><p>In the same sample, I’ve been building on top of the architecture described just above a small metaverse using <a href="https://www.babylonjs.com" target="_blank" rel="noopener noreferrer">Babylon.js</a>, an open source &amp; free WebGL engine I’ve been contributing to. The logic is identical to what I’ve described up to now. </p><p>Thanks to the SWA, I’m authenticating the user using his social profile. But then, I can do the video call to another ACS user or someone in Teams from a 3D scene. And everything is waayyy cooler inside a 3D scene, right? </p><p><img loading="lazy" alt="Screenshot of the Static Web App with a 3D scene of a museum loaded" src="/assets/images/ACSSWA004-2c90a2336105c38bffc821977311f72f.jpg" width="1914" height="1431" class="img_ev3q"></p><p>But wait, there’s even better. You can experience this Babylon.js scene in VR thanks to its native WebXR support! To give you an idea, here’s a video where I’m using my Valve Index to call my girl friend in Teams so we can visit this museum together.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/Wd4qNeLV_P8" title="YouTube video player" frameborder="0"></iframe><p>If you’re interested in WebXR, I’ve written a full article on what you can build with it sharing lot of my samples: <a href="https://www.davrous.com/2022/04/12/from-gaming-to-metaverses-building-webxr-apps-with-babylon-js/" target="_blank" rel="noopener noreferrer">From gaming to metaverses, building WebXR apps with Babylon.js – David Rousset (davrous.com)</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise">Exercise<a href="#exercise" class="hash-link" aria-label="Direct link to Exercise" title="Direct link to Exercise">​</a></h2><p>If you’d like to play and learn from this sample mixing ACS, SWA, Azure Function, CosmosDB &amp; Babylon.js, you can <strong>deploy it in less than 10 minutes</strong> by following the step-be-step tutorial available in this associated repo: <a href="https://github.com/davrous/acsauth" target="_blank" rel="noopener noreferrer">davrous/acsauth: Deploy in less than 10 min an Azure Communication Services sample to be shared &amp; tested with your colleagues &amp; friends</a>.</p><p>Enjoy and see you in the metaverse! 😊</p>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>best-practices</category>
        </item>
        <item>
            <title><![CDATA[#28: Full-Stack SWA: React + Mongoose]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/practices-full-stack-react</link>
            <guid>https://www.azurestaticwebapps.dev/blog/practices-full-stack-react</guid>
            <pubDate>Sun, 29 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to Week 4, Day 7 of #30DaysOfSWA!!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <code>Week 4, Day 7</code> of <strong>#30DaysOfSWA</strong>!!</p><p>We're at the last post of the series, so let's close the loop to where we started on Day 1. We started by talking about End-to-End Developer Experiences built on Azure Static Web Apps - and continued with a series of posts exploring various Azure service integrations that showcase this vision. Wouldn't it be great if you could have one end-to-end development example that you could use as a <strong>starter</strong> for your next prototype? Let's end this week with the perfect example. Today we'll look at an end-to-end developer workflow for a full-stack app:</p><ul><li>Front-end built with <a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">React</a> and <a href="https://redux-toolkit.js.org/" target="_blank" rel="noopener noreferrer">Redux Toolkit</a></li><li>Back-end built with <a href="https://docs.microsoft.com/azure/static-web-apps/add-api?tabs=vanilla-javascript" target="_blank" rel="noopener noreferrer">Azure Functions</a></li><li>Deployed to the cloud with <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/" target="_blank" rel="noopener noreferrer">Azure Static Web Apps</a></li><li>With a <a href="https://docs.microsoft.com/azure/cosmos-db/mongodb/mongodb-introduction" target="_blank" rel="noopener noreferrer">MongoDB database hosted in Cosmos DB</a>, accessed using <a href="https://mongoosejs.com/" target="_blank" rel="noopener noreferrer">Mongoose</a></li><li>(Optionally, with Playwright testing)</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-well-cover">What We'll Cover<a href="#what-well-cover" class="hash-link" aria-label="Direct link to What We'll Cover" title="Direct link to What We'll Cover">​</a></h2><ul><li>Building a Full-Stack App</li><li>Why use Mongoose?</li><li>Why use Redux Toolkit?</li><li><strong>Build</strong>: Implement and deploy the React/Mongoose template</li><li><strong>Exercise</strong>: Add your own features</li></ul><p><img loading="lazy" src="/assets/images/28-banner-aab132c8523d51f1fc3653502c480d82.png" width="1000" height="420" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="building-a-full-stack-app-with-swa">Building a Full-Stack App with SWA<a href="#building-a-full-stack-app-with-swa" class="hash-link" aria-label="Direct link to Building a Full-Stack App with SWA" title="Direct link to Building a Full-Stack App with SWA">​</a></h2><p>In the first week of this series, we looked <a href="/blog/building-swa">Building Static Web Apps</a> using an <strong>existing starter template</strong> and learned about options for working with Azure Static Web Apps:</p><ol><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=react" target="_blank" rel="noopener noreferrer">using VS Code</a> - if you prefer an IDE</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=react" target="_blank" rel="noopener noreferrer">using Azure CLI</a> - if you prefer the command-line</li><li><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal?tabs=react&amp;pivots=github" target="_blank" rel="noopener noreferrer">using Azure Portal</a> - if you prefer a browser-based workflow </li><li><a href="https://azure.github.io/static-web-apps-cli/docs/use/install" target="_blank" rel="noopener noreferrer">using Azure Static Web Apps CLI</a> - if you prefer a unified develop-deploy tool</li></ol><p>The default starter templates (for vanillaJS, React, Angular, Blazor, Vue) use a simple <strong>front-end application</strong> to validate your local development setup, and familiarize you with the automated build/deploy workflow setup by Azure Static Web Apps. </p><p>Today we'll look at something different - a <a href="https://github.com/staticwebdev/mongoose-starter" target="_blank" rel="noopener noreferrer">mongoose-starter</a> template for building a <strong>full-stack application</strong> with a React/Redux front-end, a serverless back-end (using Azure Functions) and a NoSQL database (using Azure CosmosDB API for MongoDB) that works seamlessly with the popular mongoose client. </p><p>Learn more about creating full-stack apps using this technology stack, in this video:</p><iframe src="https://learn-video.azurefd.net/vod/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=create-javascript-serverless-apps-w-azure-static-web-apps-etc-14-of-16--azure-tips-and-tricks" width="600" height="400" frameborder="0"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-use-mongoose">Why use Mongoose?<a href="#why-use-mongoose" class="hash-link" aria-label="Direct link to Why use Mongoose?" title="Direct link to Why use Mongoose?">​</a></h2><p>When accessing a data store you can either use APIs to interact directly with the backend or use a library which can provide additional functionality. Many developers prefer to use a library as it allows them to focus more on creating their code and logic while offloading some of the work. Mongoose is just such a library.</p><p><a href="https://mongoosejs.com/" target="_blank" rel="noopener noreferrer">Mongoose</a> is an Object-Database-Mapper (ODM) which allows you to define the objects you need to store in a NoSQL database. Mongoose can be used with any database which supports MongoDB APIs, which <a href="https://docs.microsoft.com/azure/cosmos-db/mongodb/mongodb-introduction" target="_blank" rel="noopener noreferrer">Cosmos DB does</a>. With Mongoose you can create schemas for your data, enforce validation, and streamline the process of interacting with your data.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-use-redux-toolkit">Why use Redux Toolkit?<a href="#why-use-redux-toolkit" class="hash-link" aria-label="Direct link to Why use Redux Toolkit?" title="Direct link to Why use Redux Toolkit?">​</a></h2><p><a href="https://redux.js.org/" target="_blank" rel="noopener noreferrer">Redux</a> is the most popular tool for managing state in a <a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">React</a> application. <a href="https://redux-toolkit.js.org/" target="_blank" rel="noopener noreferrer">Redux Toolkit</a> helps create projects which use Redux by providing an additional framework for some of the most common tasks when using Redux. Redux Toolkit includes functions to streamline the process of creating reducers and updating and accessing state.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="quickstart-using-the-reactmongoose-template">Quickstart: Using the React/Mongoose template<a href="#quickstart-using-the-reactmongoose-template" class="hash-link" aria-label="Direct link to Quickstart: Using the React/Mongoose template" title="Direct link to Quickstart: Using the React/Mongoose template">​</a></h2><p>To help jump start your development process, we'll <a href="https://github.com/staticwebdev/mongoose-starter" target="_blank" rel="noopener noreferrer">use the mongoose-starter template</a> built on the following libraries and tools:</p><ul><li>React</li><li>Redux Toolkit</li><li>Mongoose</li><li><a href="https://github.com/node-config/node-config#readme" target="_blank" rel="noopener noreferrer">Node-config</a></li><li>SWA CLI</li></ul><p>The template is a todo application and contains models for items and lists (which contain the items). It uses <a href="https://docs.microsoft.com/azure/static-web-apps/authentication-authorization?tabs=invitations" target="_blank" rel="noopener noreferrer">GitHub authentication through Azure Static Web Apps</a>. To support local development, a <code>devcontainer.json</code> file is included <a href="https://code.visualstudio.com/docs/remote/containers" target="_blank" rel="noopener noreferrer">use a dev container</a>.</p><p>Follow <strong><a href="https://docs.microsoft.com/azure/static-web-apps/add-mongoose" target="_blank" rel="noopener noreferrer">this tutorial</a></strong> to build and deploy the full-stack application to Azure Static Web Apps by completing the following steps:</p><ul><li>create the Cosmos DB server</li><li>create a new repository from the template</li><li>create the Azure Static Web App</li><li>configure the Azure Static Web App</li><li>use the site</li></ul><p><strong>Watch this segment</strong> to walk interactively through the process of using the mongoose-starter template build/deploy the basic project to Azure Static Web Apps.</p><iframe src="https://learn-video.azurefd.net/vod/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=how-to-create-your-azure-static-web-apps-from-a-github-template-15-of-16--azure-tips-and-tricks" width="600" height="400" frameborder="0"></iframe><p><strong>And watch this segment</strong> to learn how you can setup and configure your Azure CosmosDB resource to work with your Azure Static Web Apps deployment.</p><iframe src="https://learn-video.azurefd.net/vod/player?show=azure-tips-and-tricks-static-web-apps&amp;ep=setup-cosmos-db-w-a-mongodb-api-to-use-w-azure-static-web-apps-16-of-16--azure-tips--tricks" width="600" height="400" frameborder="0"></iframe><h2 class="anchor anchorWithStickyNavbar_LWe7" id="exercise-add-your-own-features">Exercise: Add your own features<a href="#exercise-add-your-own-features" class="hash-link" aria-label="Direct link to Exercise: Add your own features" title="Direct link to Exercise: Add your own features">​</a></h2><p>The template is designed to be used as the starter for your own projects. </p><p>To build upon what you've learned, you could <strong>explore expanding the functionality</strong> by adding your own features. Clone the repository you created and begin writing your own code! This could include:</p><ul><li>allowing items to be labeled</li><li>implementing archive functionality</li><li>potentially incorporating <a href="https://docs.microsoft.com/azure/cognitive-services/language-service/sentiment-opinion-mining/quickstart?pivots=programming-language-javascript" target="_blank" rel="noopener noreferrer">artificial intelligence to detect the sentiment of tasks</a>.</li></ul><p>Alternatively, use what you learned to add CosmosDB as a database for an application built using a different front-end framework  - try one of the usage examples from Week 2, or enhance something you've already built.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2><p>Here is a collection of resources you may find helpful for digging more into creating applications hosted on Azure Static Web Apps:</p><ul><li>SWA Quickstart: <a href="https://docs.microsoft.com/azure/static-web-apps/get-started-cli?tabs=react" target="_blank" rel="noopener noreferrer">Using Azure CLI</a></li><li><a href="https://reactjs.org/tutorial/tutorial.html" target="_blank" rel="noopener noreferrer">Official Tutorial: Intro to React</a></li><li><a href="https://docs.microsoft.com/learn/paths/react/" target="_blank" rel="noopener noreferrer">Creating your first web apps with React</a> - on Microsoft Learn</li><li><a href="https://github.com/microsoft/Web-Dev-For-Beginners" target="_blank" rel="noopener noreferrer">Web Dev For Beginners</a> - project-based curriculum</li></ul>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
            <category>best-practices</category>
            <category>react</category>
            <category>mongoose</category>
        </item>
        <item>
            <title><![CDATA[#29: Learn in #30Days]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/30days-summary</link>
            <guid>https://www.azurestaticwebapps.dev/blog/30days-summary</guid>
            <pubDate>Mon, 30 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Hello there!!]]></description>
            <content:encoded><![CDATA[<p>Hello there!!</p><p>The #30DaysOfSWA series embarks us on a quick and easy journey to learn about Azure Static Web Apps - from Core Concepts to Best Practices <strong>in just four weeks</strong>! The content is structured in a way that allows you to jumpstart or revisit the journey at any time! Here's a summary of what is covered and what you'll learn by taking this journey with us!! And stay tuned for a follow-up post a little later, where we'll share resources and next steps you can take, to keep skilling up.🚀</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-30daysofswa-journey">The #30DaysOfSWA Journey<a href="#the-30daysofswa-journey" class="hash-link" aria-label="Direct link to The #30DaysOfSWA Journey" title="Direct link to The #30DaysOfSWA Journey">​</a></h2><ul><li>SWA Anniversary Highlights</li><li>Week 1: Core Concepts</li><li>Week 2: Usage Examples</li><li>Week 3: Developer Tools</li><li>Week 4: Best Practices</li><li>Our Amazing Contributors!</li><li>What's Next</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="prelude---swaanniversary-and-the-birth-of-30daysofswa">Prelude - SWAanniversary and the birth of #30DaysOfSWA<a href="#prelude---swaanniversary-and-the-birth-of-30daysofswa" class="hash-link" aria-label="Direct link to Prelude - SWAanniversary and the birth of #30DaysOfSWA" title="Direct link to Prelude - SWAanniversary and the birth of #30DaysOfSWA">​</a></h2><p>The #30DaysOfSWA blog series started off on Apr 30 with <a href="/blog/swanniversary">this post</a> announcing the <strong>SWA Anniversary</strong> event, before <a href="/blog/kickoff"><strong>kicking off</strong></a> the <strong>#30DaysOfSWA</strong> on May 1, then completing four themed weeks of content, publishing <strong>one new blog everyday</strong>. The intent of the series is to take a developer from zero to hero. You can <a href="/roadmap"><strong>find the entire roadmap here</strong></a>.</p><p>On 19th and 20th May, we celebrated the <a href="https://www.azurestaticwebapps.dev/blog/swanniversary?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">#SWAanniversary</a> to commemorate a year of Static Web App's <strong>General Availability</strong>! It was a fun-and-engaging event featuring <strong>top community speakers</strong>, and the latest SWA feature demos! </p><div class="theme-admonition theme-admonition-success alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>ANNOUNCEMENT: SWA CLI V1.0 RELEASED!🚀</div><div class="admonitionContent_S0QG"><p>On May 19th, we also witnessed a big announcement - <strong>the General Availability (GA) of SWA CLI</strong>!! Try out the <a href="https://aka.ms/swa-cli-ga?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">SWA CLI</a>, deploy your amazing Static Web Apps, and tell us about your experience!🌹</p></div></div><p>Watch this video to learn more about how this CLI streamlines your workflow from <code>init</code> to <code>deploy</code>.</p><iframe src="https://learn-video.azurefd.net/vod/player?ev=swa-anniversary-may-2022&amp;session=explore-static-web-apps-cli" width="600" height="400" frameborder="0"></iframe><p>And if you happened to miss the live stream, worry not! You can watch (<em>and re-watch</em>) the <a href="https://aka.ms/swaanniversary-ondemand?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer"><strong>on-demand recordings of the event</strong></a> to catch up on key talks including:</p><ul><li><a href="https://docs.microsoft.com/en-us/events/swa-anniversary-may-2022/how-static-web-apps-saved-scott-hanselman-time-and-money/" target="_blank" rel="noopener noreferrer">How Static Web Apps saved (me) time and money</a> - Scott Hanselman</li><li><a href="https://docs.microsoft.com/en-us/events/swa-anniversary-may-2022/azure-static-web-apps-for-your-cli-oh-my-posh/" target="_blank" rel="noopener noreferrer">SWA Case Study: ohmyposh.dev </a>- Jan De Dobbeleer</li><li><a href="https://docs.microsoft.com/en-us/events/swa-anniversary-may-2022/hybrid-rendering-with-zero-config-nuxt-3-azure-swa/" target="_blank" rel="noopener noreferrer">Hybrid Rendering with Zero Config - Nuxt ♥️ SWA</a> - Daniel Roe &amp; Anthony Chu</li><li><a href="https://docs.microsoft.com/en-us/events/swa-anniversary-may-2022/how-i-created-my-brand-using-static-web-apps-with-blazor-and-azure-functions/" target="_blank" rel="noopener noreferrer">How I Created My Brand with SWA and..</a> - Stacy Cashmore &amp; Frank Boucher</li><li>...and many more!</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="week-1-core-concepts">Week 1: Core Concepts<a href="#week-1-core-concepts" class="hash-link" aria-label="Direct link to Week 1: Core Concepts" title="Direct link to Week 1: Core Concepts">​</a></h2><p><img loading="lazy" alt="Banner with people" src="/assets/images/week1-roadmap-7f10986393cc2e96edea4819c3bf9d72.png" width="1000" height="563" class="img_ev3q"></p><p><code>Week 1</code> is the foundational week, focusing on what Azure Static Web Apps is, how to build, deploy, preview, customize APIs etc. This is where a Static Web App newbie earns the title of a <strong>"Successful SWA voyager"</strong>! Every blog comes with a cute little exercise at the bottom which gives a compact hands-on experience of using Static Web Apps 😄 </p><p><strong>The best part?</strong> Every blog has a visual narrative of what we cover, and some of them also feature video lessons! Do give us a shoutout if you (<em>like us</em>) are a firm believer of visual learning!❤️ </p><p>To visit Week 1, or to start afresh - <strong><a href="/roadmap#core-concepts">click here.</a></strong> 🚀</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="week-2-usage-examples">Week 2: Usage Examples<a href="#week-2-usage-examples" class="hash-link" aria-label="Direct link to Week 2: Usage Examples" title="Direct link to Week 2: Usage Examples">​</a></h2><p><img loading="lazy" alt="Banner with people" src="/assets/images/week2-roadmap-aa8766edf791b4ed83fa999f74497b9b.png" width="1000" height="563" class="img_ev3q"></p><p><code>Week 2</code> showcases a plethora of examples, from diverse front-end frameworks to popular static site generators and languages! The creators of these mind-blowing examples come forward to teach how we can easily replicate these on our end too! After all, what better way to learn than to get your hands dirty playing with them 😉</p><p>Haven't tried them yet? Go for it <a href="/roadmap#usage-examples"><strong>right away</strong></a>!!! 👩🏽‍💻</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="week-3-developer-tools">Week 3: Developer Tools<a href="#week-3-developer-tools" class="hash-link" aria-label="Direct link to Week 3: Developer Tools" title="Direct link to Week 3: Developer Tools">​</a></h2><p><img loading="lazy" alt="Banner with people" src="/assets/images/week3-roadmap-75060ba5a95b7914046572100b6effdd.png" width="1000" height="563" class="img_ev3q"></p><p><code>Week 3</code> focuses on the plethora of partner tools and platforms available in the Azure ecosystem, which can empower your Static Web Apps to achieve <strong>more</strong>! Be it VSCode, Playwright, or Egde DevTools - we got you covered! As a bonus, we also talk about the enhanced dX (Developer Experience) for Azure DevOps🌟 as well as the ease-of-development <em>straight outta your local devboxes</em> with <a href="https://aka.ms/swa-cli-ga?WT.mc_id=30daysofswa-61155-cxall" target="_blank" rel="noopener noreferrer">SWA CLI</a>🪄 </p><p>Go ahead and familiarize yourself with these <a href="/roadmap#developer-tools">dev-tools</a>. 🧰</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="week-4-best-practices">Week 4: Best Practices<a href="#week-4-best-practices" class="hash-link" aria-label="Direct link to Week 4: Best Practices" title="Direct link to Week 4: Best Practices">​</a></h2><p><img loading="lazy" alt="Banner with people" src="/assets/images/week4-roadmap-ae23c6e2ecc1467720771a4ee45d9cea.png" width="1000" height="563" class="img_ev3q"></p><p><code>Week 4</code> marks the final phase of our journey! This week is dedicated to the Best practices to ensure a seamless end-to-end dX (Developer Experience) while using Static Web Apps. Explore enhanced services such as BYOFunctions, Cognitive search, Azure Vision, Communication Services, etc. and learn from a real-life case study on how Static Web Apps helped deliver an effective and scalable solution for <a href="https://kliptok.com" target="_blank" rel="noopener noreferrer">KlipTok</a>, allowing the developer to seamlessly integrate additional Azure services to meet challenges and deliver a richer user experience(uX). 😄</p><p>Explore the various integrations and best practices articles <a href="/roadmap#best-practices">here</a></p><p><em>Hope this is a long but fun journey!</em> <strong>Do tell us about your SWA learning experience using #30DaysOfSWA!</strong> 😉</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="our-amazing-contributors">Our Amazing Contributors<a href="#our-amazing-contributors" class="hash-link" aria-label="Direct link to Our Amazing Contributors" title="Direct link to Our Amazing Contributors">​</a></h2><p><img loading="lazy" alt="Banner with people" src="/assets/images/29-banner-f6f3b90d34599985f7da49221471144a.png" width="1000" height="420" class="img_ev3q"></p><p>A series of this magnitude would not be possible without the support, time and efforts a number of people. This includes our amazing authors (listed  <a href="/blog/kickoff#meet-the-authors">here, in our kickoff post</a>. Check out the tweet below to find them on Twitter, or <a href="https://dev.to/nitya/series/17901" target="_blank" rel="noopener noreferrer"><strong>follow the series on dev.to</strong></a> to find their profiles on that platform.</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>AUTHORS ON TWITTER</div><div class="admonitionContent_S0QG"><p>The tweet below has the Twitter profiles of the many authors who contributed to this series. Liked an article they wrote? Let them know - and follow them for more tech updates and content! </p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Thank you <a href="https://twitter.com/simona_cotin?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@simona_cotin</a> <a href="https://twitter.com/glaucia_lemos86?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@glaucia_lemos86</a> <a href="https://twitter.com/nthonyChu?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@nthonyChu</a> <a href="https://twitter.com/KarmarkarMitali?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@KarmarkarMitali</a> <a href="https://twitter.com/chris_noring?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@chris_noring</a> <a href="https://twitter.com/jenlooper?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@jenlooper</a> <a href="https://twitter.com/justinchronicle?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@justinchronicle</a> <a href="https://twitter.com/csharpfritz?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@csharpfritz</a> <a href="https://twitter.com/webmaxru?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@webmaxru</a> <a href="https://twitter.com/debs_obrien?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@debs_obrien</a> <a href="https://twitter.com/patrickbrosset?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@patrickbrosset</a> <a href="https://twitter.com/sinedied?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@sinedied</a> <a href="https://twitter.com/manekinekko?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@manekinekko</a> <a href="https://twitter.com/alexweininger?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@alexweininger</a> <a href="https://twitter.com/AnfibiaCreativa?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@AnfibiaCreativa</a> <a href="https://twitter.com/dfberry?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@dfberry</a> <a href="https://twitter.com/AysSomething?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@AysSomething</a> <a href="https://twitter.com/craigshoemaker?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@craigshoemaker</a> <a href="https://twitter.com/davrous?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@davrous</a> <a href="https://twitter.com/GeekTrainer?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">@GeekTrainer</a>🙏🏽</p>— Nitya Narasimhan (@nitya) <a href="https://twitter.com/nitya/status/1531100046275620866?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">May 30, 2022</a></blockquote> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div></div><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="next-steps">Next Steps<a href="#next-steps" class="hash-link" aria-label="Direct link to Next Steps" title="Direct link to Next Steps">​</a></h2><p>This gave you a curated tour of Azure Static Web Apps in daily bites of content. Now it's your turn to take the journey forward. Join us tomorrow to learn about three key actions you can take to continue skilling up:</p><ul><li><strong>Learn</strong>: We'll share key documentation and tutorial links to skill up!</li><li><strong>Share</strong>: Let's talk about the {where, what, how} of sharing your insights!</li><li><strong>Contribute</strong>: Built a cool sample or real-world app? Showcase it to inspire others!</li></ul><p>And thank you for staying the course with us!</p><hr>]]></content:encoded>
            <category>swa</category>
            <category>30days</category>
        </item>
        <item>
            <title><![CDATA[SWA Roundup: Aug 2022]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/roundup-2022-aug</link>
            <guid>https://www.azurestaticwebapps.dev/blog/roundup-2022-aug</guid>
            <pubDate>Wed, 31 Aug 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[It's here!! Our first roundup of This Month in SWA 🎉]]></description>
            <content:encoded><![CDATA[<p>It's here!! Our first roundup of <strong>This Month in SWA</strong> 🎉</p><p>Each month, on the last Wednesday, we'll publish a roundup of Azure Static Web Apps product news, events, and content updates on this blog. Over time, we hope to make it your one-stop destination to catch up on all the exciting things happening in the SWA ecosystem, in one friendly post.</p><ul><li>Want to make sure you don't miss it? <a target="_blank" href="/blog/rss.xml"><strong>Subscribe to the feed</strong></a>.</li><li>Want to contribute items for roundup? <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>Submit this custom issue</strong></a>.</li><li>Want to catch up on past posts? <a href="/thismonth#view-past-editions"><strong>Browse past editions.</strong></a></li></ul><hr><p><img loading="lazy" src="/assets/images/aug-ddb3ecc241b9668cba4b0a2aed121f8a.png" width="1600" height="672" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="product-news">Product News<a href="#product-news" class="hash-link" aria-label="Direct link to Product News" title="Direct link to Product News">​</a></h2><p><em>This section covers recent news or announcements from the product team. Read on to learn the latest news from the world of Azure Static Web Apps!</em> </p><ul><li><p><strong>Jun 22</strong> | <a href="https://azure.microsoft.com/en-us/updates/public-preview-new-api-backend-options-in-azure-static-web-apps/" target="_blank" rel="noopener noreferrer">Azure SWA now supports more API options</a><br> You can now link Azure App Service, Azure Container Apps, and Azure API Management services seamlessly to your SWA's API endpoint. Read the <a href="https://docs.microsoft.com/en-us/azure/static-web-apps/apis-overview" target="_blank" rel="noopener noreferrer">docs</a> and explore the <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/new-api-backend-options-in-azure-static-web-apps/ba-p/3516882" target="_blank" rel="noopener noreferrer">sample walkthrough</a> to learn more.</p></li><li><p><strong>Jun 8</strong> | <a href="https://azure.microsoft.com/en-us/updates/static-web-apps-cli-now-available/" target="_blank" rel="noopener noreferrer">Static Web Apps CLI is generally available</a>. <br> The v1.0 release was launched in late May, adding new commands like <code>swa init</code>, <code>swa login</code> and <code>swa deploy</code> to create an all-in-1 tool for local SWA development. <a href="https://azure.github.io/static-web-apps-cli/" target="_blank" rel="noopener noreferrer"><em>Explore the documentation here</em></a></p></li></ul><p>Don't forget to bookmark the <a href="https://azure.microsoft.com/en-us/updates/?query=static%20web%20apps" target="_blank" rel="noopener noreferrer"><strong>Azure Updates</strong></a> page to get updates at any time.</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="dev-resources">Dev Resources<a href="#dev-resources" class="hash-link" aria-label="Direct link to Dev Resources" title="Direct link to Dev Resources">​</a></h2><p><em>This section covers content, events and code samples from Microsoft authors. Check them out for relevant learning resources and best practices.</em></p><ul><li><p><strong>Aug 3</strong> | <code>dev.to</code> -  <a href="https://dev.to/azure/deploy-azure-static-web-apps-using-python-1hn7" target="_blank" rel="noopener noreferrer"><strong>Deploy Azure Static Web Apps using Python</strong></a> by <em>Jay Miller</em>. Are you a Python developer interested in exploring Azure Static Web Apps? In this post, Jay walks you through configuring and deploying your first Python SWA from VS Code.</p></li><li><p><strong>Jul 22</strong> | <code>TechCommunity</code> - <a href="https://techcommunity.microsoft.com/t5/educator-developer-blog/host-your-website-on-azure-static-web-apps-for-free/ba-p/3579709?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer"><strong>Host your website on Azure Static Web Apps for free</strong></a> by <em>Julia Muiruri</em>.  Students looking to get started with Azure, create your Azure for Students account and deploy your first website within minutes!</p></li><li><p><strong>Jul 20</strong> | <code>dev.to</code> -<a href="https://dev.to/azure/taking-a-swa-devops-pipeline-to-the-next-level-5co3" target="_blank" rel="noopener noreferrer"><strong>Taking a SWA DevOps Pipeline to the next level</strong></a> by <em>Aaron Powell</em>. We know SWA works seamlessly with GitHub Actions to automate the default build-deploy workflow. What if you need a more complex custom CI/CD pipeline? This article walks you through one such example. </p></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="community-buzz">Community Buzz<a href="#community-buzz" class="hash-link" aria-label="Direct link to Community Buzz" title="Direct link to Community Buzz">​</a></h2><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>AUTHORED BY DEVS LIKE YOU!</div><div class="admonitionContent_S0QG"><p><em>This section highlights content from our amazing developer community - submitted directly, or published to the relevant tag in sites like Tech Community and dev.to.</em></p></div></div><ul><li><strong>Jul 19</strong> | <code>techcommunity.com</code> - <a href="https://techcommunity.microsoft.com/t5/educator-developer-blog/azure-adventure-a-rpg-game-to-test-student-s-azure-practical/ba-p/3576331?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer"><strong>Azure Adventure – A RPG game to test student’s Azure practical skills</strong></a> by <em>Wong Cyrus, Dept Information Technology of the Hong Kong Institute of Vocational Education</em>.  Azure Adventure is an open source HTML5 RPG game that builds on top of the latest version of Azure Automatic Grading Engine, utilizing SWA.</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="upcoming-events">Upcoming Events<a href="#upcoming-events" class="hash-link" aria-label="Direct link to Upcoming Events" title="Direct link to Upcoming Events">​</a></h2><p><em>This section highlights in-person or online events that are likely to feature Azure Static Web Apps content or developer conversations - links to CFPs or registration links are welcome!</em></p><ul><li><strong>Sep 1-30, 2022</strong> | <a href="https://aka.ms/serverless-september" target="_blank" rel="noopener noreferrer">Serverless September</a> - explore Serverless on Azure</li><li><strong>Oct 7, 2022</strong> | <a href="https://developer.microsoft.com/en-us/reactor/overview/student-summit-2022/" target="_blank" rel="noopener noreferrer">Microsoft Student Summit</a> - virtual event held globally</li><li><strong>Oct 12-14, 2022</strong> | <a href="https://ignite.microsoft.com/en-US/home" target="_blank" rel="noopener noreferrer">Microsoft Ignite</a> - in-person (Seattle) and online </li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="did-you-know">Did You Know?<a href="#did-you-know" class="hash-link" aria-label="Direct link to Did You Know?" title="Direct link to Did You Know?">​</a></h2><p><em>Each month, we hope to turn the spotlight on one key resource or person that is worth knowing about, in the context of Azure Static Web Apps.</em></p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>🌟 SPOTLIGHT ON:  DEV.TO</div><div class="admonitionContent_S0QG"><p><a href="https://dev.to" target="_blank" rel="noopener noreferrer">Dev.to</a> is an inclusive community of software developers where you can publish content and have conversations on technology in collaborative and learning-driven ways. </p><ul><li>Explore the <a href="https://dev.to/t/staticwebapps" target="_blank" rel="noopener noreferrer"><strong>#staticwebapps</strong></a> tag - to browse ~100 articles on SWA.</li><li>Leave comments or reactions - to provide valued feedback! </li><li>Create <a href="https://dev.to/new/staticwebapps" target="_blank" rel="noopener noreferrer"><strong>a tagged post</strong></a> - to share your own learnings.</li></ul></div></div><p>Here's a snapshot of what that tag profile looks like! <strong>Follow</strong> the tag to get articles in your dev.to feed - or <a href="https://dev.to/feed/tag/staticwebapps" target="_blank" rel="noopener noreferrer">subscribe to the feed</a> from your favorite RSS reader.</p><blockquote><p><img loading="lazy" alt="dev.to #staticwebapps page" src="/assets/images/devto-685d9c7b97d10873a6750f86555d5219.png" width="1367" height="898" class="img_ev3q"></p></blockquote><p>That's all we had for this roundup! Tell us what you think about this new format for a monthly summary! And don't forget to send us <em>your</em> contributions.</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="--call-for-content">🚨 | Call For Content<a href="#--call-for-content" class="hash-link" aria-label="Direct link to 🚨 | Call For Content" title="Direct link to 🚨 | Call For Content">​</a></h2><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Next Roundup: Sep 28, 2022</div><div class="admonitionContent_S0QG"><p>Submissions welcome till Sep 25, 2022.</p><ul><li>Did you author an article, create a SWA application or sample?</li><li>Are you organizing an event with a SWA-related session?</li><li>Are you a student who just created your first SWA app or blog post?</li></ul><p>Submit the details <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>using this custom issue</strong></a> as soon as possible. We can't wait to share your contributions!</p></div></div>]]></content:encoded>
            <category>swa</category>
            <category>thismonth</category>
            <category>aug</category>
        </item>
        <item>
            <title><![CDATA[SWA Roundup: Sept 2022]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/roundup-2022-sep</link>
            <guid>https://www.azurestaticwebapps.dev/blog/roundup-2022-sep</guid>
            <pubDate>Wed, 28 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[It's here!! Our September roundup of This Month in SWA 🎉]]></description>
            <content:encoded><![CDATA[<p>It's here!! Our September roundup of <strong>This Month in SWA</strong> 🎉</p><p>Each month, on the last Wednesday, we'll publish a roundup of Azure Static Web Apps product news, events, and content updates on this blog. Over time, we hope to make it your one-stop destination to catch up on all the exciting things happening in the SWA ecosystem, in one friendly post.</p><ul><li>Want to make sure you don't miss it? <a target="_blank" href="/blog/rss.xml"><strong>Subscribe to the feed</strong></a>.</li><li>Want to contribute items for roundup? <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>Submit this custom issue</strong></a>.</li><li>Want to catch up on past posts? <a href="/thismonth#view-past-editions"><strong>Browse past editions.</strong></a></li></ul><hr><p><img loading="lazy" src="/assets/images/sep-3eb16aeb1437b4e946939cb065d6f0c6.png" width="1600" height="672" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="product-news">Product News<a href="#product-news" class="hash-link" aria-label="Direct link to Product News" title="Direct link to Product News">​</a></h2><p><em>This section covers recent news or announcements from the product team. Read on to learn the latest news from the world of Azure Static Web Apps!</em> </p><ul><li><p><strong>Aug 31</strong> | <a href="https://azure.microsoft.com/en-us/updates/generally-available-enterprisegrade-edge-for-azure-static-web-apps/" target="_blank" rel="noopener noreferrer">Generally available: Enterprise-grade edge for Azure Static Web Apps</a> <br> Enterprise-grade edge for Azure Static Web Apps is now generally available. Enable faster page loads, enhance security, and optimize reliability for your global applications.</p></li><li><p><strong>Sep 27</strong> | <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#platform" target="_blank" rel="noopener noreferrer">Support for .NET Core 3.1 in Azure Static Web Apps that use Azure Functions will end on Dec 3, 2022</a> <br> After this date, your existing static web apps that use Azure Functions will continue to work, but security patches and customer service for .NET Core 3.1 will no longer be provided.</p></li><li><p><strong>Sep 27</strong> | <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#platform" target="_blank" rel="noopener noreferrer">Support for Node 12 in Azure Static Web Apps will end on Dec 3, 2022</a> <br> After this date, your existing static web apps that use Azure Functions will continue to work, but security patches and customer service for Node 12 will no longer be provided.  </p></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="dev-resources">Dev Resources<a href="#dev-resources" class="hash-link" aria-label="Direct link to Dev Resources" title="Direct link to Dev Resources">​</a></h2><p><em>This section covers content, events and code samples from Microsoft authors. Check them out for relevant learning resources and best practices.</em></p><ul><li><p><strong>Aug 14</strong> | <code>learn.microsoft.com</code> - <a href="https://learn.microsoft.com/en-us/shows/beginners-series-to-learn-a-full-stack-application-with-azure-sql-prisma/" target="_blank" rel="noopener noreferrer">Learn: A Full Stack Application with Azure SQL &amp; Prisma</a> by <em>Glaucia Lemos</em>. Your complete guide to create a scalable full-stack application using: Node.Js, Prisma, Azure SQL, Azure Functions along with deploying to Azure Static Web Apps integrated with GitHub Actions!</p></li><li><p><strong>Sep 2</strong> | <code>techcommunity.com</code> - <a href="https://techcommunity.microsoft.com/t5/educator-developer-blog/how-to-move-your-react-website-from-localhost-to-the-internet/ba-p/3611601" target="_blank" rel="noopener noreferrer">How to move your React website from localhost to the internet</a> by <em>Bethany Jepchumba</em>. Now that you have your frontend React app running locally, time to take it to the cloud. Follow this step-by-step guide utilizing Azure Static Web Apps CLI to deploy your site.</p></li><li><p><strong>Sep 23</strong> | <code>youtube.com</code> - <a href="https://www.youtube.com/watch?v=adKWRm-J2oQ" target="_blank" rel="noopener noreferrer">New API back-end options in Azure Static Web Apps | Azure Friday</a> by <em>Annina Keller and Scott Hanselman</em>. Annina shows how Azure Static Web Apps provides built-in serverless API endpoints via integration with Azure services, including Azure App Service, Azure API Management, Azure Container Apps, and Azure Functions. <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/use-static-web-apps-api-and-api-management-authorizations-to/ba-p/3603755" target="_blank" rel="noopener noreferrer">Read the full Tech Community article</a></p></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="community-buzz">Community Buzz<a href="#community-buzz" class="hash-link" aria-label="Direct link to Community Buzz" title="Direct link to Community Buzz">​</a></h2><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>AUTHORED BY DEVS LIKE YOU!</div><div class="admonitionContent_S0QG"><p><em>This section highlights content from our amazing developer community - submitted directly, or published to the relevant tag in sites like Tech Community and dev.to.</em></p></div></div><ul><li><p><strong>Aug 25</strong> | <code>c-sharpcorner.com</code> - <a href="https://www.c-sharpcorner.com/article/static-web-apps-with-apis-with-azure-functions/" target="_blank" rel="noopener noreferrer">Static Web Apps With APIs With Azure Functions</a> by <em>Jorge Levy</em>.  Did you know you can deploy a full-stack application with Azure Static Web Apps?Follow along with this walk through to create a vanilla JavaScript frontend app with a C# Azure Function for an API.</p></li><li><p><strong>Sep 1</strong> | <code>dev.to</code> - <a href="https://dev.to/stacy_cash/taking-azure-static-web-apps-from-out-of-the-box-to-your-complex-pipelines-3kgf" target="_blank" rel="noopener noreferrer">Taking Azure Static Web Apps from Out of the Box to Your Complex Pipelines</a> by <em>Stacy Cashmore</em>. When you have a large and complex application, and your SWA is only a small part of that stack, build process is key. Here is how to get that dialed in to your needs.</p></li><li><p><strong>Sep 3</strong> | <code>github.com</code> - <a href="https://github.com/samipak458/Simple-Library-Managment" target="_blank" rel="noopener noreferrer">Simple Library Management</a> by <em>Muhammad Samiullah</em>. For those new to web development, here's a starter app for you! Learn JavaScript, web storage and deploying your first site to Azure Static Web Apps.</p></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="upcoming-events">Upcoming Events<a href="#upcoming-events" class="hash-link" aria-label="Direct link to Upcoming Events" title="Direct link to Upcoming Events">​</a></h2><p><em>This section highlights in-person or online events that are likely to feature Azure Static Web Apps content or developer conversations - links to CFPs or registration links are welcome!</em></p><ul><li><strong>Oct 7, 2022</strong> | <a href="https://developer.microsoft.com/en-us/reactor/overview/student-summit-2022/" target="_blank" rel="noopener noreferrer">Microsoft Student Summit</a> - virtual event held globally</li><li><strong>Oct 12-14, 2022</strong> | <a href="https://ignite.microsoft.com/en-US/home" target="_blank" rel="noopener noreferrer">Microsoft Ignite</a> - in-person (Seattle) and online</li><li><strong>Nov 9-10, 2022</strong> | <a href="https://githubuniverse.com/" target="_blank" rel="noopener noreferrer">GitHub Universe</a> - in-person (San Francisco) and online</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="did-you-know">Did You Know?<a href="#did-you-know" class="hash-link" aria-label="Direct link to Did You Know?" title="Direct link to Did You Know?">​</a></h2><p><em>Each month, we hope to turn the spotlight on one key resource or person that is worth knowing about, in the context of Azure Static Web Apps.</em></p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>🌟 SPOTLIGHT ON:  Student Ambassadors</div><div class="admonitionContent_S0QG"><p><a href="https://studentambassadors.microsoft.com/" target="_blank" rel="noopener noreferrer">Microsoft Learn Student Ambassadors</a> is our community program of over 3,000 higher-education students globally.</p><p>We ❤️ feedback! And are currently working with all of our Ambassadors to review the existing Azure Static Web Apps Learn documentation and training to hear their perspective and ideas.</p></div></div><p>If you are a student, we'd also love to hear from you while we go through this review. Here is how you can provide your feedback on our Azure Static Web App Learn documentation and training materials.</p><ol><li>Checkout this great list of current <a href="https://github.com/microsoft/studentambassadors/tree/main/Bug-Bash" target="_blank" rel="noopener noreferrer">Azure Static Web App Learn materials</a> the Ambassador team has put together.</li><li>Pick out an item to review. </li><li>If you find a bug, have an idea, or just have a question, share it with us! Go to the <a href="https://github.com/microsoft/studentambassadors" target="_blank" rel="noopener noreferrer">microsoft/studentambassadors</a> repo to <a href="https://github.com/microsoft/studentambassadors/issues/new/choose" target="_blank" rel="noopener noreferrer">create a new issue</a>. <em>Be sure to tag if you are student, Ambassador, or educator</em>.</li></ol><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="--call-for-content">🚨 | Call For Content<a href="#--call-for-content" class="hash-link" aria-label="Direct link to 🚨 | Call For Content" title="Direct link to 🚨 | Call For Content">​</a></h2><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Next Roundup: Oct 26, 2022</div><div class="admonitionContent_S0QG"><p>Submissions welcome till Oct  19, 2022.</p><ul><li>Did you author an article, create a SWA application or sample?</li><li>Are you organizing an event with a SWA-related session?</li><li>Are you a student who just created your first SWA app or blog post?</li></ul><p>Submit the details <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>using this custom issue</strong></a> as soon as possible. We can't wait to share your contributions!</p></div></div>]]></content:encoded>
            <category>swa</category>
            <category>thismonth</category>
            <category>sep</category>
        </item>
        <item>
            <title><![CDATA[SWA Roundup: Oct 2022]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/roundup-2022-oct</link>
            <guid>https://www.azurestaticwebapps.dev/blog/roundup-2022-oct</guid>
            <pubDate>Wed, 26 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[It's here!! Our October roundup of This Month in SWA 🎉]]></description>
            <content:encoded><![CDATA[<p>It's here!! Our October roundup of <strong>This Month in SWA</strong> 🎉</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>ABOUT THE ROUNDUP </div><div class="admonitionContent_S0QG"><p>We publish a roundup of Azure Static Web Apps product news, announcements and content updates <strong>on the last Wednesday of each month</strong>. Catch up on all the updates in one friendly post - and don't forget to contribute <em>your</em> updates for inclusion in the next issue!</p><ul><li>Want to make sure you don't miss it? <a target="_blank" href="/blog/rss.xml"><strong>Subscribe to the feed</strong></a>.</li><li>Want to contribute items for roundup? <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>Submit this custom issue</strong></a>.</li><li>Want to catch up on past posts? <a href="/thismonth#view-past-editions"><strong>Browse past editions.</strong></a></li></ul></div></div><hr><p><img loading="lazy" src="/assets/images/oct-4ff5be6eb81c76dafc5a32dc447d7b38.png" width="1600" height="672" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="product-news">Product News<a href="#product-news" class="hash-link" aria-label="Direct link to Product News" title="Direct link to Product News">​</a></h2><p><em>This section covers recent news or announcements from the product team. Read on to learn the latest news from the world of Azure Static Web Apps!</em> </p><ul><li><p><strong>Oct 03</strong> | <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/universal-rendering-with-nuxt-3-and-azure-static-web-apps/ba-p/3586297?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">Universal Rendering with Nuxt 3 and Azure Static Web Apps</a>. Previously, you were able to deploy a static rendered Nuxt app on Azure Static Web Apps, where the entire app is pre-generated as static content. However, Nuxt 3 also supports universal rendering, which provides the performance and search engine optimization of server-side rendering while still enabling client-side interactivity. <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/deploy-nuxtjs?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer"><strong>Get Started</strong></a> with this tutorial.</p></li><li><p><strong>Oct 08</strong> | <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/extending-next-js-support-in-azure-static-web-apps/ba-p/3627975?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">Extending Next.js Support in Azure Static Web Apps</a> <br> It's here - Azure Static Web Apps has <strong>preview</strong> support for Hybrid Next.js apps, making zero-config deployments with Next.js even easier with support for Server-Side Rendering, Incremental Static Regeneration (SSR and ISR respectively), API Routes, advanced image compression, and Next.js Auth. <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/deploy-nextjs-hybrid?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer"><strong>Get Started</strong></a> with this tutorial.</p></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="dev-resources">Dev Resources<a href="#dev-resources" class="hash-link" aria-label="Direct link to Dev Resources" title="Direct link to Dev Resources">​</a></h2><p><em>This section covers content, events and code samples from Microsoft authors. Check them out for relevant learning resources and best practices.</em></p><ul><li><p><strong>Oct 13</strong> | <a href="https://techcommunity.microsoft.com/t5/apps-on-azure-blog/cloud-native-architectures-on-azure-microsoft-ignite-update/ba-p/3650098?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">Cloud-Native Architectures on Azure: Microsoft Ignite Update</a> <br>  Read it to get a sense of where Azure Static Web Apps fits in the Cloud-Native ecosystem for building serverless solutions on Azure. Then <a href="https://ignite.microsoft.com/sessions/8950b2b1-62eb-48f9-90ef-5ad779ce8e22?source=sessions?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer"><strong>Watch The Session</strong></a> to see a demo of the Next.js Hybrid Rendering preview, and learn about what's next for Azure Static Web Apps.</p></li><li><p><strong>Oct 24</strong> | <a href="https://www.youtube.com/watch?v=w6uH1CZEhcg&amp;WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">Create blazing-fast web apps with Next.js and Azure Static Web Apps</a> <br> Discover how Azure Static Web Apps support for Next.js hybrid rendering can help you create web applications optimized for SEO and performance in this <strong>5-minute video walkthrough</strong>, part of the 20-part series of <a href="https://www.youtube.com/playlist?list=PLlrxD0HtieHgMPeBaDQFx9yNuFxx6S1VG&amp;WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">Azure Tips &amp; Tricks: Static Web Apps</a> that takes you from core concepts to best practices.</p></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="community-buzz">Community Buzz<a href="#community-buzz" class="hash-link" aria-label="Direct link to Community Buzz" title="Direct link to Community Buzz">​</a></h2><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>AUTHORED BY DEVS LIKE YOU!</div><div class="admonitionContent_S0QG"><p><em>This section highlights content from our amazing developer community - submitted directly, or published to the relevant tag in sites like Tech Community and dev.to.</em></p></div></div><ul><li><strong>Oct 03</strong> | Microsoft MVP Stacy Cashmore just published a book on <a href="https://link.springer.com/book/10.1007/978-1-4842-8146-8" target="_blank" rel="noopener noreferrer">Beginning Azure Static Web Apps</a> with a focus on "Building and Deploying Dynamic Web Applications with Blazor". The book covers dynamic content with Azure Functions, discusses the JAMstack revolution, and contains examples built using Visual Studio 2022. You can find <a href="https://twitter.com/Stacy_Cash/status/1576956491218976768" target="_blank" rel="noopener noreferrer"><strong>Stacy's tweet</strong></a> with more details.</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="upcoming-events">Upcoming Events<a href="#upcoming-events" class="hash-link" aria-label="Direct link to Upcoming Events" title="Direct link to Upcoming Events">​</a></h2><p><em>This section highlights in-person or online events that are likely to feature Azure Static Web Apps content or developer conversations - links to CFPs or registration links are welcome!</em></p><ul><li><strong>Oct 27</strong> | Join MVP Stacy Cashmore at <a href="https://reactor.microsoft.com/en-us/reactor/events/17239/" target="_blank" rel="noopener noreferrer">Microsoft Reactor</a> and go <strong>From Zero To Deployed App in 60 Minutes</strong></li><li><strong>Nov 8-10</strong> | Register for <a href="https://www.dotnetconf.net/" target="_blank" rel="noopener noreferrer"><em>.NET Conf 2022</em></a> and attend the session on <strong>Azure Static Web Apps with Blazor and .NET</strong>.</li><li><strong>Nov 9-10</strong> | Register for <a href="https://githubuniverse.com/" target="_blank" rel="noopener noreferrer">GitHub Universe</a> and look out for some great sessions from <a href="https://githubuniverse.com/events/detail/speakers" target="_blank" rel="noopener noreferrer">Microsoft speakers</a> there!</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="did-you-know">Did You Know?<a href="#did-you-know" class="hash-link" aria-label="Direct link to Did You Know?" title="Direct link to Did You Know?">​</a></h2><p><em>Each month, we hope to turn the spotlight on one key resource or person that is worth knowing about, in the context of Azure Static Web Apps.</em></p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>🌟 SPOTLIGHT ON:  Microsoft Student Summit</div><div class="admonitionContent_S0QG"><p>Did you know the <a href="https://developer.microsoft.com/en-us/reactor/overview/student-summit-2022?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">Microsoft Student Summit</a> was just held as a global virtual event <strong>on October 7, 2022</strong> The event was held virtually in several regions, to suit local time zones and regional community interests. </p><p>And you can catch up on all the recordings from these sessions in <a href="https://www.youtube.com/playlist?list=PLmsFUfdnGr3zU8GBuF3772MWhO4mMjMA-?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer"><strong>this handy playlist</strong></a></p><p><img loading="lazy" alt="Student Summit Logo" src="/assets/images/studentsummit-8e2f41e33c9852bbb6754d499da188f6.png" width="590" height="316" class="img_ev3q"></p></div></div><p>Azure Static Web Apps was a key focus for the Student Audience with sessions focused on the topic at 6 of 7 regional events. Here are links to the relevant recordings:</p><ul><li>North America (Thomas And Ricardo) - <a href="https://youtu.be/_rfVNPWdcNg?t=7505" target="_blank" rel="noopener noreferrer">View Recording</a></li><li>EMEA (Sandro) - <a href="https://www.youtube.com/watch?v=TLJvG98pSkc&amp;list=PLmsFUfdnGr3zU8GBuF3772MWhO4mMjMA-&amp;index=4&amp;t=7168s&amp;WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">View Recording</a></li><li>India (Reshmi) - <a href="https://youtu.be/e7tm1WpFK24?t=8750&amp;WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">View Recording</a></li><li>Asia Pacific (Julia) - <a href="https://youtu.be/ZjHZ5zCGPbk?t=8528&amp;WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">View Recording</a></li><li>Brasil (Lavinia) - <a href="https://youtu.be/NmjwsCExIQM?list=PLmsFUfdnGr3zU8GBuF3772MWhO4mMjMA-&amp;t=7892&amp;WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">View Recording</a></li><li>LATAM (Christopher and Francisco) - <a href="https://youtu.be/ROJFLILoJ9U?list=PLmsFUfdnGr3zU8GBuF3772MWhO4mMjMA-&amp;t=6930&amp;WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer">View Recording</a></li></ul><p>Microsoft Student Ambassadors also participated in a <a href="https://github.com/microsoft/studentambassadors/issues" target="_blank" rel="noopener noreferrer">Static Web Apps Bug Bash 🐞</a> - getting hands-on experience with providing valuable product feedback, and working with product teams to help resolve identified issues! <a href="https://studentambassadors.microsoft.com/?WT.mc_id=javascript-74011-ninarasi" target="_blank" rel="noopener noreferrer"><strong>Learn more about the Microsoft Learn Student Ambassadors Program</strong></a></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="--call-for-content">🚨 | Call For Content<a href="#--call-for-content" class="hash-link" aria-label="Direct link to 🚨 | Call For Content" title="Direct link to 🚨 | Call For Content">​</a></h2><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Next Roundup: Nov 30, 2022</div><div class="admonitionContent_S0QG"><p>Submissions welcome till Nov  23, 2022.</p><ul><li>Did you author an article, create a SWA application or sample?</li><li>Are you organizing an event with a SWA-related session?</li><li>Are you a student who just created your first SWA app or blog post?</li></ul><p>Submit the details <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>using this custom issue</strong></a> as soon as possible. We can't wait to share your contributions!</p></div></div>]]></content:encoded>
            <category>swa</category>
            <category>thismonth</category>
            <category>oct</category>
        </item>
        <item>
            <title><![CDATA[SWA Roundup: Nov 2022]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/roundup-2022-nov</link>
            <guid>https://www.azurestaticwebapps.dev/blog/roundup-2022-nov</guid>
            <pubDate>Wed, 30 Nov 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[It's here!! Our November roundup of This Month in SWA 🎉]]></description>
            <content:encoded><![CDATA[<p>It's here!! Our November roundup of <strong>This Month in SWA</strong> 🎉</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>ABOUT THE ROUNDUP </div><div class="admonitionContent_S0QG"><p>We publish a roundup of Azure Static Web Apps product news, announcements and content updates <strong>on the last Wednesday of each month</strong>. Catch up on all the updates in one friendly post - and don't forget to contribute <em>your</em> updates for inclusion in the next issue!</p><ul><li>Want to make sure you don't miss it? <a target="_blank" href="/blog/rss.xml"><strong>Subscribe to the feed</strong></a>.</li><li>Want to contribute items for roundup? <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>Submit this custom issue</strong></a>.</li><li>Want to catch up on past posts? <a href="/thismonth#view-past-editions"><strong>Browse past editions.</strong></a></li></ul></div></div><hr><p><img loading="lazy" src="/assets/images/nov-00353ecc3a55eb1e770287c02c4a0d6d.png" width="1600" height="672" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="product-news">Product News<a href="#product-news" class="hash-link" aria-label="Direct link to Product News" title="Direct link to Product News">​</a></h2><p><em>This section covers recent news or announcements from the product team. Read on to learn the latest news from the world of Azure Static Web Apps!</em> </p><ul><li><p><strong>Nov 08</strong> | <a href="https://azure.microsoft.com/en-us/updates/generally-available-azure-static-web-apps-now-fully-supports-net-7/?WT.mc_id=academic-7401100000-sagibbon" target="_blank" rel="noopener noreferrer">Azure Static Web Apps now fully supports .NET 7</a> For your app’s frontend, Static Web Apps can now automatically build and deploy .NET 7.0 Blazor WebAssembly apps. For backend APIs, you can build and deploy .NET 7.0 Azure Functions with your static web apps. <strong><a href="https://learn.microsoft.com/en-us/azure/static-web-apps/deploy-blazor?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer">Get started</a></strong> by building your own Blazor + serverless API app.</p></li><li><p><strong>Nov 09</strong> | <a href="https://azure.microsoft.com/en-us/updates/public-preview-azure-static-web-apps-now-supports-node-18/?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer">Azure Static Web Apps now Supports Node 18</a> By using Node 18 for your app, you can leverage the latest language and runtime improvements in Node. For using Node 18 in your Azure functions, please use Functions version 4.x. <strong><a href="https://learn.microsoft.com/en-us/azure/static-web-apps/languages-runtimes?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer">Learn more</a></strong> on Azure Static Web Apps supported languages.</p></li><li><p><strong>Nov 09</strong> | <a href="https://azure.microsoft.com/en-us/updates/generally-available-static-web-apps-support-for-gitlab-and-bitbucket/?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer">Static Web Apps support for Gitlab and Bitbucket</a> This allows you to use Gitlab and Bitbucket as your CI/CD providers for Static Web Apps. You can bring your Gitlab or Bitbucket Project, create a simple YAML file using the provided template, and link it to a Static Web App created with a custom deployment source. Get started with this <strong><a href="https://learn.microsoft.com/en-us/azure/static-web-apps/gitlab?tabs=vanilla-javascript?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer">Gitlab tutorial</a></strong> and <strong><a href="https://learn.microsoft.com/en-us/azure/static-web-apps/bitbucket?tabs=vanilla-javascript?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer">Bitbucket tutorial</a></strong></p></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="dev-resources">Dev Resources<a href="#dev-resources" class="hash-link" aria-label="Direct link to Dev Resources" title="Direct link to Dev Resources">​</a></h2><p><em>This section covers content, events and code samples from Microsoft authors. Check them out for relevant learning resources and best practices.</em></p><ul><li><strong>Nov 01</strong> | <code>github.com</code> -  <a href="https://github.com/aaronpowell/nextjs-graphql-trivia-demo" target="_blank" rel="noopener noreferrer">Next.js trivia app</a> by <em>Aaron Powell</em> This is a Next.js trivia demo application that shows how you can use GraphQL in an API route to talk to Azure Cosmos DB to make an application that can be deployed to Azure Static Web Apps using the hybrid Next.js app support.</li><li><strong>Nov 08</strong> | <code>techcommunity.com</code> -  <a href="https://techcommunity.microsoft.com/t5/healthcare-and-life-sciences/deploy-a-react-app-to-azure-static-web-apps/ba-p/3671939/?WT.mc_id=academic-74011-sagibbon" target="_blank" rel="noopener noreferrer">Deploy a React app to Azure Static Web Apps</a> by <em>David Ginn and Phil Jirsa</em> Watch Cloud Solution Architects David Ginn and Phil Jirsa demonstrate how to deploy a ReactJS application to Azure Static Web Apps using GitHub actions.</li><li><strong>Nov 23</strong> | <code>microsoft.github.io</code> - <a href="https://microsoft.github.io/MicrosoftCloud/tutorials/docs/ACS-to-Teams-Meeting" target="_blank" rel="noopener noreferrer">Audio/Video Calling from a Custom App into a Teams Meeting</a> by <em>Dan Wahlin and Ayca Bas</em> In this tutorial you'll learn how Azure Communication Services can be used in a custom React application to allow a user to make an audio/video call into a Microsoft Teams meeting</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="community-buzz">Community Buzz<a href="#community-buzz" class="hash-link" aria-label="Direct link to Community Buzz" title="Direct link to Community Buzz">​</a></h2><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>AUTHORED BY DEVS LIKE YOU!</div><div class="admonitionContent_S0QG"><p><em>This section highlights content from our amazing developer community - submitted directly, or published to the relevant tag in sites like Tech Community and dev.to.</em></p></div></div><ul><li><strong>Nov 14</strong> | <code>dev.to</code> - <a href="https://dev.to/danwahlin/getting-started-with-azure-static-web-apps-4a8j" target="_blank" rel="noopener noreferrer">Getting Started with Azure Static Web Apps</a> by <em>Dan Wahlin</em> Follow along with Dan has he shows you step-by-step how to create and deploy a React web app to Azure Static Web Apps, start to finish.</li><li><strong>Nov 14</strong> | <code>youtube.com</code> - <a href="https://www.youtube.com/watch?v=FjGjguW1Xa0" target="_blank" rel="noopener noreferrer">Azure Static Web Apps with Blazor and .NET</a> by <em>Melissa Houghton</em> Learn how to use Azure Static Web Apps with Blazor and .NET. Start by exploring Azure Static Web Apps, then take a look at getting started with Blazor WebAssembly paired with the serverless power of .NET Azure Functions or Azure Container Apps. And learning how to automatically build and deploy to Azure directly from our code repository.</li><li><strong>Nov 20</strong> | <code>github.com</code> -  <a href="https://github.com/geoffrich/svelte-adapter-azure-swa" target="_blank" rel="noopener noreferrer">svelte-adapter-azure-swa</a> by <em>Geoff Rich</em> Adapter for Svelte apps that creates an Azure Static Web App, using an Azure function for dynamic server rendering.</li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="2022-event-highlights">2022 Event Highlights<a href="#2022-event-highlights" class="hash-link" aria-label="Direct link to 2022 Event Highlights" title="Direct link to 2022 Event Highlights">​</a></h2><p><em>As we wrap up 2022 and plan for 2023, here are some highlighted SWA event sessions not to be missed!</em></p><ul><li><a href="https://www.youtube.com/watch?v=1e6k5HNK4F8" target="_blank" rel="noopener noreferrer">Azure Static Web Apps 1st Anniversary 🥳</a></li><li><a href="https://www.youtube.com/watch?v=vWwjMTeP1kU" target="_blank" rel="noopener noreferrer">Use Static Web Apps to add a blog and link it to your Node web app</a></li><li><a href="https://www.youtube.com/watch?v=7oPSL5wWeS0" target="_blank" rel="noopener noreferrer">Using MSAL.js to integrate React Single-page applications with Azure Active Directory – July 2022</a></li></ul><p><em>Have an upcoming event you'd like to highlight? <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer">Share it with us</a> so we can include it in our next roundup!</em></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="did-you-know">Did You Know?<a href="#did-you-know" class="hash-link" aria-label="Direct link to Did You Know?" title="Direct link to Did You Know?">​</a></h2><p><em>Each month, we hope to turn the spotlight on one key resource or person that is worth knowing about, in the context of Azure Static Web Apps.</em></p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>🌟 SPOTLIGHT ON: Awesome AZD Templates</div><div class="admonitionContent_S0QG"><p>The Azure Developer CLI (AZD) is an open-source tool that accelerates the time it takes for you to get started on Azure - with a set of developer-friendly commands that map to key stages in your workflow (code, build, deploy, monitor).</p><p>Not only that, AZD uses extensible application templates (<a href="https://azure.github.io/awesome-azd/" target="_blank" rel="noopener noreferrer">Awesome AZD Templates</a>) that include everything you need to get up and running on Azure for multiple scenarios. Each covering an end-to-end scenario that goes far beyond "Hello World!".</p></div></div><p>Checkout the Static Web App enabled <a href="https://azure.github.io/awesome-azd/" target="_blank" rel="noopener noreferrer">Awesome AZD Templates</a> we've created:</p><ul><li><a href="https://github.com/Azure-Samples/todo-nodejs-mongo-swa-func" target="_blank" rel="noopener noreferrer">ToDo Application with a Node.js API and Azure Cosmos DB API for MongoDB on Static Web Apps and Functions</a></li><li><a href="https://github.com/Azure-Samples/todo-python-mongo-swa-func" target="_blank" rel="noopener noreferrer">ToDo Application with a Python API and Azure Cosmos DB API for MongoDB on Static Web Apps and Functions</a></li></ul><p>As we work to build out Static Web App enabled <a href="https://azure.github.io/awesome-azd/" target="_blank" rel="noopener noreferrer">Awesome AZD Templates</a>, we'd love to hear from you! <strong><a href="https://github.com/Azure/awesome-azd/issues/new?assignees=nitya%2C+savannahostrowski&amp;labels=requested-contribution&amp;template=%F0%9F%A4%94-submit-an-idea-for-a-template.md&amp;title=%5BIdea%5D+%3Cyour-template-name%3E" target="_blank" rel="noopener noreferrer">Share your template idea</a></strong>, or if you have a template created you'd like to add to out list, <strong><a href="https://github.com/Azure/awesome-azd/issues/new?assignees=nitya%2C+savannahostrowski&amp;labels=new-contribution&amp;template=%F0%9F%93%B2contribute-an-azd-template-.md&amp;title=%5BNew+azd-template%5D+%3Cyour-template-name%3E" target="_blank" rel="noopener noreferrer">share your template with us</a></strong>!</p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="--call-for-content">🚨 | Call For Content<a href="#--call-for-content" class="hash-link" aria-label="Direct link to 🚨 | Call For Content" title="Direct link to 🚨 | Call For Content">​</a></h2><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Next Roundup: Dec 28, 2022</div><div class="admonitionContent_S0QG"><p>Submissions welcome till Dec 21, 2022.</p><ul><li>Did you author an article, create a SWA application or sample?</li><li>Are you organizing an event with a SWA-related session?</li><li>Are you a student who just created your first SWA app or blog post?</li></ul><p>Submit the details <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>using this custom issue</strong></a> as soon as possible. We can't wait to share your contributions!</p></div></div>]]></content:encoded>
            <category>swa</category>
            <category>thismonth</category>
            <category>nov</category>
        </item>
        <item>
            <title><![CDATA[SWA Roundup: Jan 2023]]></title>
            <link>https://www.azurestaticwebapps.dev/blog/roundup-2023-jan</link>
            <guid>https://www.azurestaticwebapps.dev/blog/roundup-2023-jan</guid>
            <pubDate>Mon, 23 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[It's here!! Our January roundup of This Month in SWA 🎉]]></description>
            <content:encoded><![CDATA[<p>It's here!! Our January roundup of <strong>This Month in SWA</strong> 🎉</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>ABOUT THE ROUNDUP </div><div class="admonitionContent_S0QG"><p>We publish a roundup of Azure Static Web Apps product news, announcements and content updates <strong>on the last Wednesday of each month</strong>. Catch up on all the updates in one friendly post - and don't forget to contribute <em>your</em> updates for inclusion in the next issue!</p><ul><li>Want to make sure you don't miss it? <a target="_blank" href="/blog/rss.xml"><strong>Subscribe to the feed</strong></a>.</li><li>Want to contribute items for roundup? <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>Submit this custom issue</strong></a>.</li><li>Want to catch up on past posts? <a href="/thismonth#view-past-editions"><strong>Browse past editions.</strong></a></li></ul></div></div><hr><p><img loading="lazy" src="/assets/images/jan-a4e4c0568f105c0a30ea6beca4bef419.png" width="1600" height="672" class="img_ev3q"></p><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="product-news">Product News<a href="#product-news" class="hash-link" aria-label="Direct link to Product News" title="Direct link to Product News">​</a></h2><p><em>This section covers recent news or announcements from the product team. Read on to learn the latest news from the world of Azure Static Web Apps!</em> </p><ul><li><strong>Dec 14</strong> | <a href="https://azure.microsoft.com/en-us/updates/generally-available-static-web-apps-diagnostics/?WT.mc_id=academic-86055-sagibbon" target="_blank" rel="noopener noreferrer">Generally available: Static Web Apps Diagnostics</a> Azure Static Web Apps Diagnostics is an intelligent tool to help you troubleshoot your static web app directly from the Azure Portal. When issues arise, Static Web Apps diagnostics will help you diagnose what went wrong and will show you how to resolve the issues. <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/diagnostics-overview/?WT.mc_id=academic-86055-sagibbon" target="_blank" rel="noopener noreferrer"><strong>Get Started</strong></a> with your Static Web App diagnositics. </li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="dev-resources">Dev Resources<a href="#dev-resources" class="hash-link" aria-label="Direct link to Dev Resources" title="Direct link to Dev Resources">​</a></h2><p><em>This section covers content, events and code samples from Microsoft authors. Check them out for relevant learning resources and best practices.</em></p><ul><li><strong>Dec 6</strong> | <code>learn.microsoft.com</code> -  <a href="https://learn.microsoft.com/en-us/shows/learn-live/modern-web-development-net6-ep04-publish-blazor-webassembly-net-api-azure-static-web-apps/?WT.mc_id=academic-86055-sagibbon" target="_blank" rel="noopener noreferrer">Publish a Blazor WebAssembly app and .NET API with Azure Static Web Apps</a> by <em>Jon Galloway and James Montemagno</em> Follow along with this Learn Live session as Jon and James walk you through how to automatically deploy and update a Blazor web application and its API from a GitHub repository. <a href="https://learn.microsoft.com/en-us/training/modules/publish-app-service-static-web-app-api-dotnet/?WT.mc_id=academic-86055-sagibbon" target="_blank" rel="noopener noreferrer"><strong>Get started</strong></a> with the accompanying Learn Module.</li><li><strong>Dec 13</strong> | <code>github.com</code> -  <a href="https://github.com/education/codespaces-project-template-js" target="_blank" rel="noopener noreferrer">JavaScript Portfolio Site with GitHub Codespaces</a> by <em>Sara Gibbons</em> Build and deploy your own portfolio site using Codespaces and Azure Static Web Apps. All from within your browser! <a href="https://www.youtube.com/watch?v=5c_X-GC7Eds" target="_blank" rel="noopener noreferrer"><strong>Watch the release discussion</strong></a> to learn more.</li><li><strong>Jan 10</strong> | <code>learn.microsoft.com</code> - <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/front-end-frameworks/?WT.mc_id=academic-86055-sagibbon" target="_blank" rel="noopener noreferrer">Configure front-end frameworks and libraries with Azure Static Web Apps</a> The list of frameworks that work with Azure Static Web Apps continues to grow! Find a new framework to explore using the provided configuration to deploy your app. <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/build-configuration?tabs=github-actions/?WT.mc_id=academic-86055-sagibbon" target="_blank" rel="noopener noreferrer"><strong>Learn more</strong></a> on all Static Web App build configuration options to get started. </li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="community-buzz">Community Buzz<a href="#community-buzz" class="hash-link" aria-label="Direct link to Community Buzz" title="Direct link to Community Buzz">​</a></h2><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>AUTHORED BY DEVS LIKE YOU!</div><div class="admonitionContent_S0QG"><p><em>This section highlights content from our amazing developer community - submitted directly, or published to the relevant tag in sites like Tech Community and dev.to.</em></p></div></div><ul><li><strong>Dec 31</strong> | <code>dev.to</code> -  <a href="https://dev.to/johnnyreilly/deep-linking-with-azure-static-web-apps-and-easy-auth-26in" target="_blank" rel="noopener noreferrer">Deep linking with Azure Static Web Apps and Easy Auth</a> by <em>John Reilly</em> Dig in on deep linking and authentication within Azure Static Web Apps. What each is, and how to implement together for your web app. </li><li><strong>Jan 10</strong> | <code>dotnetthoughts.net</code> -  <a href="https://dotnetthoughts.net/implementing-authentication-in-static-web-apps-part1/" target="_blank" rel="noopener noreferrer">Implementing Authentication in Azure Static Web Apps</a> by <em>Anuraj Parameswaran</em> In this two part series, explore creating and running an app on the Azure Static Web App free plan and standard plans, along with setting up authentication for your app. </li><li><strong>Jan 21</strong> | <code>youtube.com</code> -  <a href="https://azureday.community/en-live-from-the-netherlands/azure-static-web-apps-for-the-enterprise/" target="_blank" rel="noopener noreferrer">Azure Static Web Apps for the Enterprise</a> by <em>Stacy Cashmore</em> Azure Static Web Apps is enterprise ready, and Stacy shows you the steps from infrastructure to authentication on how you can utilize Static Web Apps for your organization. </li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="upcoming-events">Upcoming Events<a href="#upcoming-events" class="hash-link" aria-label="Direct link to Upcoming Events" title="Direct link to Upcoming Events">​</a></h2><p><em>This section highlights in-person or online events that are likely to feature Azure Static Web Apps content or developer conversations - links to CFPs or registration links are welcome!</em></p><ul><li><strong>Jan 26</strong> | ✨ <strong>Join LIVE for <a href="https://www.youtube.com/watch?v=7hTQJs9Ku5Y" target="_blank" rel="noopener noreferrer">Azure Static Web Apps Community Standups</a></strong> ✨ In this first edition of the SWA Community Standup, we'll introduce the team, the product, some community contributions, and we'll demo how to get up and running quickly from your favorite tools.</li><li><strong>Jan 23</strong> | Join <a href="https://azure.github.io/Cloud-Native/New-Year/" target="_blank" rel="noopener noreferrer">Cloud Native New Year</a></li><li><strong>Feb 1</strong> | Get ready for <a href="https://microsoft.github.io/Low-Code/blog/2023-kickoff/" target="_blank" rel="noopener noreferrer">Low Code February</a></li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="did-you-know">Did You Know?<a href="#did-you-know" class="hash-link" aria-label="Direct link to Did You Know?" title="Direct link to Did You Know?">​</a></h2><p><em>Each month, we hope to turn the spotlight on one key resource or person that is worth knowing about, in the context of Azure Static Web Apps.</em></p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>🌟 SPOTLIGHT ON:  SWA CLI</div><div class="admonitionContent_S0QG"><p><a href="https://azure.github.io/static-web-apps-cli/" target="_blank" rel="noopener noreferrer"><strong>Static Web Apps CLI</strong></a> is an all-in-one local development tool For Azure Static Web Apps. Using SWA CLI you can deploy your apps right from your local enviroment to the Azure cloud without a CI/CD workflow, and instead a simple CLI command. </p><p>From the SWA CLI you can login to Azure subscriptions, initialize an Azure Static Web Apps project, set build configurations, and deploy your app.</p></div></div><p>To get you started here is a list of SWA CLI resources:</p><ul><li><a href="https://www.azurestaticwebapps.dev/blog/devtools-swacli-develop" target="_blank" rel="noopener noreferrer"><strong>Develop with SWA CLI</strong></a> - Covering the basics of getting started with SWA CLI for your development cycle. </li><li><a href="https://www.azurestaticwebapps.dev/blog/devtools-swacli-deploy" target="_blank" rel="noopener noreferrer"><strong>Deploy with SWA CLI</strong></a> - Get connected to Azure and deploy your Static Web App. Including the use of environment variables. </li><li><a href="https://github.com/Azure/static-web-apps-cli" target="_blank" rel="noopener noreferrer"><strong>SWA CLI GitHub Repo</strong></a> - Covering all of SWA CLI, and where <a href="https://github.com/Azure/static-web-apps-cli/issues/new/choose" target="_blank" rel="noopener noreferrer"><strong>you can share</strong></a> your questions, report a bug, and request a feature. </li></ul><hr><h2 class="anchor anchorWithStickyNavbar_LWe7" id="--call-for-content">🚨 | Call For Content<a href="#--call-for-content" class="hash-link" aria-label="Direct link to 🚨 | Call For Content" title="Direct link to 🚨 | Call For Content">​</a></h2><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Next Roundup: Feb 20, 2023</div><div class="admonitionContent_S0QG"><p>Submissions welcome till Feb 15, 2023.</p><ul><li>Did you author an article, create a SWA application or sample?</li><li>Are you organizing an event with a SWA-related session?</li><li>Are you a student who just created your first SWA app or blog post?</li></ul><p>Submit the details <a href="https://github.com/staticwebdev/30DaysOfSWA/issues/new?assignees=&amp;labels=ThisMonthIn+-+Community&amp;template=---this-month-in-swa--community-submission.md&amp;title=This+Month+In%3A+Community" target="_blank" rel="noopener noreferrer"><strong>using this custom issue</strong></a> as soon as possible. We can't wait to share your contributions!</p></div></div>]]></content:encoded>
            <category>swa</category>
            <category>thismonth</category>
            <category>jan</category>
        </item>
    </channel>
</rss>