If you are a frequent reader of this blog, you’ll know that I am an unapologetic web developer. I love everything about the web and its ability to deliver rich experiences to users. My technology stack of choice is primarily ASP.NET Core. Still, I try and adopt the technology choices that give me the most significant opportunity for success. I’ve written about VueJs and how to integrate the framework into a standard ASP.NET Core workflow.

What drew me to VueJS is what also drew me to Svelte. The ability to create components that developers can utilize when necessary. Adopting Svelte doesn’t mean we have to abandon the strengths of ASP.NET Core.

This post will go through the basics of setting up an ASP.NET Core project to use Svelte client-side JavaScript components. We’ll see that we can start consuming svelte components in our Razor pages with minimal effort and deliver a rich user experience.

What Is Svelte?

Like React, and Vue, Svelte is an approach to building user interfaces using JavaScript or TypeScript. Unlike other frameworks, Svelte emphasizes doing the bulk of the work at compile time and easing the client’s processing needs. While traditional frameworks depend on expensive virtual DOM diffing techniques, Svelte operates by updating the DOM when the application changes state.

Folks familiar with other frameworks will find the Svelte experience quite similar. Svelte has a build process using a module bundler named Rollup. Additionally, developers write components in files suffixed with .svelte.

<script>
	let name = 'world';
</script>

<h1>Hello {name}!</h1>

Svelte has a great library of Examples for beginners just learning how to implement components. In the sample library, learn the basics of structuring a component, adding reactivity, accepting external properties, and handling visibility logic. It’s an excellent place to start or refresh existing Svelte knowledge.

For my particular use case, Svelte is an excellent way to build standalone components that I can compile and shared across multiple projects. We can reference the build process artifact we generate in HTML like any other JavaScript library. The shareable nature of the Svelte artifact makes this perfect for design systems and component libraries.

ASP.NET Core Setup

We first need to start with an ASP.NET Core web application. To do this, we can use our IDE to create a new web application or run the following dotnet CLI command.

> dotnet new webapp -o SvelteApp

Once we have created the solution, we can add all the necessary node files.

Package.JSON and NPM Packages

First, let’s add a package.json file to the root of our web project. We want to add four appropriate devDependencies to our package.json file: svelte, rollup, @rollup/plugin-node-resolve, and rollup-plugin-svelte. We’ll also configure our build script command.

{
  "name": "SvelteApp",
  "version": "1.0.0",
  "scripts": {
    "build": "rollup -c rollup.config.js"
  },
  "dependencies": {},
  "devDependencies": {
    "@rollup/plugin-node-resolve": "^11.2.0",
    "rollup": "^2.39.0",
    "rollup-plugin-svelte": "^7.1.0",
    "svelte": "^3.32.3"
  }
}

We may have noticed a reference to a rollup.config.js file. We’ll add this in the next section.

Rollup Configuration For Svelte and ASP.NET Core

Let’s first look at the rollup.config.js in its entirety. Then we’ll explain the parts developers may want to change.

import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';

export default {
    // This `main.js` file we wrote
    input: 'wwwroot/js/main.js',
    output: {
        // The destination for our bundled JavaScript
        file: 'wwwroot/js/build/bundle.js',
        // Our bundle will be an Immediately-Invoked Function Expression
        format: 'iife',
        // The IIFE return value will be assigned into a variable called `app`
        name: 'app',
    },
    plugins: [
        svelte({
            // Tell the svelte plugin where our svelte files are located
            include: 'wwwroot/**/*.svelte',
            emitCss: false,
            compilerOptions: {
                customElement: true
            }
        }),
        // Tell any third-party plugins that we're building for the browser
        resolve({ browser: true }),
    ]
};

We need to modify the input to point to our main.js file found inside the wwwroot folder in our ASP.NET Core application. The next important option is our output value. Here we need to change file value to point to an output artifact. In our case, we’ll be creating a file under an existing js folder. Finally, our plugins array requires we enable the Svelte processor. Let’s look at each line within this block.

  • The include is a path filter to find all .svelte files.
  • The emitCss value of false keeps CSS style definitions within the JavaScript files. Svelte can generate .css files for post-processing. We aren’t doing any post-processing in this case.
  • compilerOptions allows us to create standalone components that we can use in our Razor pages. We can choose when and where to add Svelte components to enhance the user experience.

ASP.NET Core Build Command

Like the VueJS and Parcel build blog post, we can modify our .csproj to run the Rollup build command on every build. In our .csproj, we can add the following target.

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
    </PropertyGroup>

    <Target Name="Rollup" BeforeTargets="Build">
        <Exec Command="npm run build" />
    </Target>

</Project>

Writing A Svelte Component

We defined the location of our Svelte components in our rollup.config.js in the previous section. Let’s add a new App.svelte file to our js folder. We are using the <svelte:options> element, which allows us to define the HTML tag of svelte-app.

<svelte:options tag="svelte-app" />
<script>
    export let name;
    export let id;
</script>

<main>
    <h1 id="{id}">Hello {name}!</h1>
</main>

<style>
    h1 {
        font-size: 5em;
    }
</style>

We also need to add or modify an existing main.js file in the same js folder. Add the following line to the first immediate line. We don’t need to use the import variable App; it is only necessary for Rollup to find and build our Svelte file.

import App from './App.svelte'

Adding Our Bundle To Layout.cshtml

At the end of our _Layout.cshtml file, we’ll need to reference Rollup’s new bundle.

<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<!-- added the bundle to the end of scripts -->
<script src="~/js/build/bundle.js" asp-append-version="true"></script>

We should now be ready to use the Svelte components in any Razor files.

Using Svelte Components Within Razor Views

Inside a Razor view, let’s add our new HTML element of svelte-app, which we defined within the App.svelte file.

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<svelte-app id="khalid" name="Khalid"></svelte-app>
<svelte-app id="paul" name="Paul"></svelte-app>

Svelte will automatically take any attributes on an element and match them to any props defined in the component. Running the page, we can see the results of our rendered elements.

Running svelte inside an asp.net core web application

Awesome! To see this project in its final form, you can clone the repository from my public GitHub account.

Conclusion

Svelte is an exciting option for ASP.NET Core developers. It allows us to build rich clientside components that we can compile once and share everywhere. We don’t need to sacrifice the strengths of our current technology stack to adopt an all-or-nothing approach. Svelte is a perfect tool to bridge the workflows of UX, front-end, and backend developers.

I hope you found this post helpful, and if you are using Svelte, please leave a comment below. I’d love to hear from you.

References