question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Hosting Multiple (React) SPAs in Asp.Net Core for development.

See original GitHub issue

This might start off sounding like a general usage question; however there have been multiple SO posts that mention this topic in one way or another.

Notable example #1

Notable example #2

I also realize the tremendous amount of work it takes to handle more serious issues, so thank you for reading.

I am simply attempting to figure out how to host multiple (in this case, React) SPA’s using either App.UseProxyToSpaDevelopmentServer or App.UseReactDevelopmentServer for development.

Previously, I worked together a solution of building (npm run build) each SPA and constructing a custom StaticFilesProvider that would serve them up. Obviously this build process takes quite a while and I would like to be able to use something like App.UseProxyToSpaDevelopmentServer to take advantage of hot-reloading, etc.

I have put together a basic demo repo that illustrates the problem I am experiencing. It is linked at the bottom of this ticket.

For clarity, here is my Startup.cs class:

public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
   
            app.UseDefaultFiles();
            app.UseStaticFiles();

            app.UseRouting();
            
            app.Map("/spa1", spa1 =>
            {
                if (env.IsDevelopment())
                {
                    spa1.UseSpa(spa =>
                    {         
                        spa.Options.SourcePath = Path.Join(env.ContentRootPath, "spa1");
                        spa.UseProxyToSpaDevelopmentServer("http://localhost:3001/");
                    });
                }
            });

            app.Map("/spa2", spa2 =>
            {
                if (env.IsDevelopment())
                {
                    spa2.UseSpa(spa =>
                    {         
                        spa.Options.SourcePath = Path.Join(env.ContentRootPath, "spa2");
                        spa.UseProxyToSpaDevelopmentServer("http://localhost:3002/");
                    });
                }
            });

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }

When I use UseProxyToSpaDevelopmentServer, I start my SPAs separately (on port 3001 and 3002 for /spa1 and /spa2 respectively). I then start my .NET app, which boots as normal. I then navigate to the desired SPA endpoint (say http://localhost:5001/spa1). When inspecting the browser, I see that my static content (I.e.,https://localhost:5001/spa1/static/js/bundle.js ) all have 200 status codes, but there are MIME type errors printed out to the console:

The script from “https://localhost:5001/spa1/static/js/bundle.js” was loaded even though its MIME type (“text/html”) is not a valid JavaScript MIME type.

Here is a link to the reproduce repo

It feels like I am just overlooking something; however, if I am not, perhaps this is something that could be further documented? (I wouldn’t mind at all helping with that process if needed).

Thanks again for all of the work making awesome open source software!

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
javiercncommented, Mar 25, 2021

@spencer741 if you reverse the way the proxying works it’s actually closer to your E2E scenario. I haven’t been around that area of the codebase in quite a while, but if I recall it correctly the only thing the SPA extensions do in a production environment is serve the spa app from a different folder.

0reactions
varsi94commented, Jan 26, 2022

We have encountered the same issue and it turned out that the proxy does not create the proper URL when calling the development servers. In these scenarios, the React applications need to be configured to be hosted under /spa1 and /spa2 paths respectively so that it tries to load the resources from the proper URL (which seems to be missing from this example). Therefore the static files on the instances are similar to /spa1/static/js/bundle.js and /spa2/static/js/bundle.js.

When these requests arrive on the server, due to the Map call, the request context will look like this: Request.Path = “/static/js/bundle.js” and Request.PathBase = “/spa1”. If you look at the proxy code, you can realize that even though we set the target URL of the proxy to http://localhost:3001/spa1 and http://localhost:3002/spa2, the logic of the Uri concatenation will strip down the important /spa1 and /spa2 segments because it is ignoring the PathBase property.

I understand that just adding the PathBase property here might break some things, but configuring the proxy path based on the incoming request might be a solution for this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to host multiple React SPA apps on a single ASP.NET ...
I'm trying to run multiple React SPA apps using ASP.NET Core 3.1 with the lastest SpaServices extension and have a problem serving static...
Read more >
How to host multiple React SPA apps on a single ASP.NET ...
NET Core project that uses the same name as the route the SPA will use. In this case we have two apps, guestuser...
Read more >
ASP.Net 6 with multiple react entry points
Net 6 project with multiple entry points, providing shared CSS for Razor pages and a better local development experience.
Read more >
Creating SPAs using ASP.NET Core and React
This function contains a branch of logic that calls spa.UseReactDevelopmentServer(npmScript: "start") if you're in development mode. This tells ...
Read more >
Coding Shorts: Hosting SPAs in ASP.NET Core - YouTube
I've been talking with clients for a long time about hosting a SPA (e.g. Vue, Angular, React, Svelte, etc.) in ASP. NET Core...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found