dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.26k stars 9.96k forks source link

Angular 6 multi project SPA #5241

Closed Axel3232 closed 5 years ago

Axel3232 commented 6 years ago

Hi,

I have a solution with two Angular 6 "projects", one for the desktop app, one for the mobile app. In dev it works fine with :

app.MapWhen((context) =>
{
    return context.Request.Path.StartsWithSegments("/mobile");
},
 (mobileApp) =>
{
      mobileApp.UseSpa((spa) =>
      {
               spa.Options.SourcePath = "ClientApp";
               if (env.IsDevelopment())
               {
                  spa.UseAngularCliServer("start:mobile");
               }
        });          
 });
 app.UseSpa(desktop =>
 {
       desktop.Options.SourcePath = "ClientApp";
       if (env.IsDevelopment())
       {
             desktop.UseAngularCliServer(npmScript: "start");
       }
});

But in production they are deployed in wwwroot :

And I am able to access only one of these application because of the

 services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "wwwroot/desktop"; 
            });

To solve this I am thinking of :

Any recommandation would be very nice.

thx

Axel3232 commented 6 years ago

Ok I ended up with a solution with the two projet folder side by side (wwwroot/desktop wwwroot/mobile) by setting a dedicated IFileProvider for the mobile folder in startup ctor :

 var absoluteRootPath = Path.Combine(
                                env.ContentRootPath,
                                "wwwroot", "mobile");
            mobileFileProvider = new PhysicalFileProvider(absoluteRootPath);

mobileFileProvider is a static var in startup class, It should be a singleton service but I was lazy :-)

                app.MapWhen((context) =>
                {
                    return context.Request.Path.StartsWithSegments("/mobile");
                },
                (mobileApp) =>
                {

                    mobileApp.UseSpa((spa) =>
                    {
                        spa.Options.SourcePath = "ClientApp";
                        if (env.IsDevelopment())
                        {

                            spa.UseAngularCliServer("start:mobile");
                        }
                        else
                        {  
                            spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions
                            {
                                RequestPath = "/mobile",
                                FileProvider = mobileFileProvider,

                            };
                            spa.Options.DefaultPage = "/mobile/index.html";

                        }
                    });

                });
                app.UseSpa(spa =>
                {
                    spa.Options.SourcePath = "ClientApp";
                    if (env.IsDevelopment())
                    {
                        spa.UseAngularCliServer(npmScript: "start");
                    }
                });

Any drawbacks with this approach ?

guftall commented 5 years ago

Hi. remove these line of codes in Startup.c:

 services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "wwwroot/desktop"; 
            });

I solved this scenario with just using StaticFileOptions in my routing.

app.Map("/angularApp1", appLevel1 =>
{
    StaticFileOptions options = new StaticFileOptions();
    options.FileProvider =
        new PhysicalFileProvider("/path/to/dist/folder/of/app1");

    appLevel1.UseSpaStaticFiles(options);
    appLevel1.UseMiddleware<SPAAuthenticationMiddleware>();
    appLevel1.UseSpa(spa =>
    {
        if (env.IsDevelopment())
        {
            spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
        }
        else
        {
            spa.Options.DefaultPageStaticFileOptions = options; // THIS IS IMPORTANT LINE
        }
    });
});

app.Map("/angularApp2", appLevel1 =>
{
    StaticFileOptions options = new StaticFileOptions();
    options.FileProvider =
        new PhysicalFileProvider("/path/to/dist/folder/of/app2");

    appLevel1.UseSpaStaticFiles(options);
    appLevel1.UseMiddleware<SPAAuthenticationMiddleware>();
    appLevel1.UseSpa(spa =>
    {
        // To learn more about options for serving an Angular SPA from ASP.NET Core,
        // see https://go.microsoft.com/fwlink/?linkid=864501

        if (env.IsDevelopment())
        {
            spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
        }
        else
        {
            spa.Options.DefaultPageStaticFileOptions = options; // THIS IS IMPORTANT LINE
        }
    });
});
marchy commented 5 years ago

Where is the specified path for the PhysicalFileProvider relative to? The code requires an an absolute path, how should it be provided to work in both development and distribution/production?

UPDATE: $"{Directory.GetCurrentDirectory()}/path/to/dist/folder" seemed to do it

mkArtakMSFT commented 5 years ago

Thanks for contacting us. We believe that the question you've raised have been answered. If you still feel a need to continue the discussion, feel free to reopen it and add your comments.