OJ Develops

Thoughts on software development. .NET | C# | Azure

Deploying a Svelte Single Page Application (SPA) with Azure Static Web Apps

22 December 2022

Azure Static Web Apps lets us host our front-end application’s files (eg. HTML, CSS, JavaScript, image files) in Azure Storage instead of in a managed host like Azure Web Apps.

To deploy a SvelteKit application to Azure Static Web Apps, we need to:

  • Ensure that the application is indeed a SPA. That is, prerender is set to false in all pages. Azure Static Web Apps can also support prerendered pages.
  • Enable building of the Svelte application. The build process should output a set of HTML, CSS, JavaScript files, and possibly other assets such as images or favicons.
  • An Azure Static Web Apps service in Azure.
  • A repository.

Building a SvelteKit Single Page Application

When we create a SvelteKit application using npm create svelte@latest, it automatically comes with an npm package which is an adapter called adapter-auto. In SvelteKit land, an adapter is the thing that turns our source code into servable HTML/CSS/JavaScript files.

Different adapters produce different outputs based on the type of the web application and the target platform. In our case, the type of the web application is a Single Page Application (without prerendering) and the target platform is Azure Static Web Apps. adapter-auto does not support our use case, and so we have to install a different adapter. I will be using @sveltejs/adapter-static:

npm i @sveltejs/adapter-static

After installing the package, we also need to update svelte.config.js to use the new adapter.

import adapter from '@sveltejs/adapter-static';

// ...

kit: {
    adapter: adapter({
        fallback: 'index.html'
    })
},

// ...

When we now run npm run build, our HTML/CSS/JavaScript files are created in a build folder. Inside, there will be an index.html file, as well as subfolders containing the CSS, JavaScript, and whatever other static assets our application uses, such as icons and fonts.

Deploying the Built Application

Similar to Azure Web Apps, we first have to create an Azure Static Web Apps resource in Azure before we can use it. In addition, we might also want to connect it to GitHub, where the source code lives, so that the app gets deployed from the repository instead of from our local machine. Finally, we might also want to enable continuous deployment, so that whenever we push new code to our repository, the application gets rebuilt and automatically deployed.

To create an Azure Static Web App in Azure, we can use the Visual Studio Code extension called Azure Static Web Apps. I will no longer list the complete steps here, as they are straightforward and listed on the relevant Microsoft documentation page. I found that the only changes that needed to be made were on the last steps of choosing the app location and build location, as those folders should reflect our repository structure.

The steps covers everything we need, from creating the Azure Static Web App in Azure to connecting it to GitHub and enabling continuous deployment via GitHub actions. After following the steps, we will be able to browse to the website. Everything should work out-of-the-box, except routing.

Routing

We have to tell Azure Static Web Apps what content to render when someone visits the site at a particular URL. In a single page application, there is only one HTML file being served regardless of the URL. The decision of what content to render is handled by the JavaScript framework in use, which in our case is SvelteKit. This is contrary to the default routing logic that Azure Static Web Apps utilizes, and so we have to make a few changes for routing to work.

To tell Azure Static Web Apps that all URLs should go to a single file, such as index.html, we need to add a configuration file named staticwebapp.config.json at the source code folder with the following contents:

{
    "routes": [
        {
            "route": "/*.html",
            "rewrite": "/index.html"
        }
    ],
    "navigationFallback": {
        "rewrite": "/index.html",
        "exclude": ["/favicon/*", "/_app/*"]
    }
}

The routes array specify a list of routes that the application should recognize. In our case, all requests to html files should get served with the index.html file. We also specify a fallback which triggers when no routes match, except for requests made to assets such as CSS and JavaScript files. Those asset files are located in the favicon and _app folders in my application, and so I included them inside the exclude array. Make sure to modify them to match your application.

Errors

If you encounter this error:

Failed to find a default file in the app artifacts folder (/). Valid default files: index.html,Index.html. If your application contains purely static content, please verify that the variable 'app_location' in your workflow file (located in .github/workflows) points to the root of your application.

Check the YAML file of the GitHub build action and make sure that app_location points to the correct folder, which is the folder containing the package.json file. Also make sure that the output_location points to the correct folder, which is the folder that gets created when you run npm run build locally.

More Information

Versions used: Svelte 3.55.0; SvelteKit 1.0.1; Adapter-Static 1.0.0