In this article, we'll create a single-page application (SPA) using Svelte-Kit and ASP.NET Core 7. First, let's talk about the advantages of this setup:
dotnet new react
.ClientApp
folder, so we'll start by deleting it. On a *nix terminal, we can use rm -rf ClientApp
.npm create svelte@latest ClientApp
cd ClientApp
npm install
Now, we'll configure the vite proxy for our ASP.NET Core API:
launchSettings.json
; In the applicationUrl
parameter, there are the URLs the application is configured to use in development mode. We can delete the one that uses https because we won't be dealing with SSL for development now.Vite allows to proxying requests, so not much work is needed. We can achieve that by adding the following to our vite.config.js
server: {
proxy: {
'/api': 'http://localhost:5125'
}
}
The configuration file now looks like this:
import { sveltekit } from '@sveltejs/kit/vite';
/** @type {import('vite').UserConfig} */
const config = {
plugins: [sveltekit()],
server: {
proxy: {
'/api': 'http://localhost:5125'
}
}
};
export default config;
Svelte-Kit uses Vite, we need to update the command that runs our development frontend in the .csproj
as follows:
<SpaProxyLaunchCommand>vite dev</SpaProxyLaunchCommand>
When running vite dev
, the app runs on port 5173. Let's define that in the csproj
file as well, for our convenience, in the SpaProxyServerUrl
property.
<SpaProxyServerUrl>http://localhost:5173</SpaProxyServerUrl>
Change the WeatherForecastController.cs
route name to [Route("api/controller")]
which will allow us to fetch the dummy data from our SvelteKit app using our proxy configuration.
That's it! We can now run our ASP.NET Core SPA project, with SvelteKit, by using dotnet run
and we can see the app running effectively and the routes being applied.
After setting up our project to run effectively in development mode, let's focus on the publishing part, which is when most of the magic happens, and when ASP.NET Core serves our SPA app.
The adapter is responsible for the publishing part of the frontend. You can learn more about it on the Svelte-Kit adapters documentation page for the intricacies of how it functions in a production build. We'll use the following setup:
build
folder to place all the needed files for the publishing part.build
folder's contents to wwwroot
which is where the actual files will be after running dotnet publish
.Our adapter of choice is @sveltejs/adapter-static
which is adequate for static-generation. First, install the package using npm install @sveltejs/adapter-static
, then we change the svelte.config.js
file to use this adapter:
import adapter from '@sveltejs/adapter-static';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter({assets: 'build', pages: 'build'})
}
};
export default config;
This will tell SvelteKit where to publish the actual content. In our setup, we are using the build folder since it's the folder our ASP.NET Core project already uses for publishing the React contents (line 47).
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)build\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
Remove the Sverdle game from the frontend project. Remove the sverdle folder and remove the link to it in the layout.svelte.
Now, we need to change the build command that the project files use to use Vite instead, so on line 44, change npm run
build to vite build
:
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="vite build" />
After the generation, for each route, we'll have a .html file. In our case, for the Index and About pages, everything should work now from the index page, but not from the about page. To have everything working, we must map the route to the file in our Program.cs:
app.MapFallbackToFile("about", "about.html");
Our Program.cs
looks like this now:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("about", "about.html");
app.MapFallbackToFile("index.html");
app.Run();
In order to see the complete project used in this example, check out AspNetSPA_SvelteKit GitHub repository.