Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React template index.html caching? #3147

Closed
georgiosd opened this issue May 15, 2018 · 12 comments
Closed

React template index.html caching? #3147

georgiosd opened this issue May 15, 2018 · 12 comments
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates question

Comments

@georgiosd
Copy link

Hi,

I seem to be facing a problem when deploying a new build to my server.

It seems that index.html is cached by the browser and tries to load the old bundle, which leads to a 404.

Any ideas how to fix this?

Thanks!

@mkArtakMSFT
Copy link
Member

Hi. It looks like this is a question about how to use ASP.NET Core. While we do our best to look through all the issues filed here, to get a faster response we suggest posting your questions to StackOverflow using the asp.net-core-mvc tag.

@mkArtakMSFT
Copy link
Member

@georgiosd, you can configure the Cache-Control headers for static files as documented here: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-2.0&tabs=aspnetcore2x

@georgiosd
Copy link
Author

@mkArtakMSFT the SPA templates use UseSpaStaticFiles which also has an overload to set options but from what I could see it doesn't have an overload the allows setting BOTH the SourcePath and the cache options.

@mkArtakMSFT mkArtakMSFT reopened this May 15, 2018
@georgiosd
Copy link
Author

@mkArtakMSFT I could have been more specific :)

@SteveSandersonMS
Copy link
Member

As long as the StaticFileOptions you've passed don't specify a FileProvider, then it will automatically pick up the RootPath from your DI config: https://github.com/aspnet/JavaScriptServices/blob/15d2f5a898da584433e38c82d5b09c375d9f87b7/src/Microsoft.AspNetCore.SpaServices.Extensions/StaticFiles/SpaStaticFilesExtensions.cs#L95

If you choose to pass a custom FileProvider (which you don't need to if your only goal is to change the caching response headers) then it's up to you to configure it to load files from the desired source location.

I'm not totally sure what you mean by SourcePath - I'm guessing you meant RootPath, but apologies if I am misunderstanding.

@georgiosd
Copy link
Author

Actually I think the confusion is on my end.

I was referring to:

app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseReactDevelopmentServer(npmScript: "start");
                }
            });

But that seems to be a different call. The relevant one is:

app.UseStaticFiles();
app.UseSpaStaticFiles(/* static file options */);

@SteveSandersonMS is the call to UseStaticFiles necessary or does UseSpaStaticFiles suffice?

@georgiosd
Copy link
Author

Looks like this issue is troubling more people:

facebook/create-react-app#1910
https://stackoverflow.com/questions/49604821/cache-busting-with-create-react-app

Any many more...

This seems to be because of the service worker from CRA so the cache settings I added don't seem to have much of an effect.

If you have any ideas let me know :)

@techniq
Copy link

techniq commented Nov 3, 2018

This setup works for me (Create React App hosted on Azure App Service).

app.UseSpaStaticFiles(new StaticFileOptions()
{
    OnPrepareResponse = ctx =>
    {
        if (ctx.Context.Request.Path.StartsWithSegments("/static"))
        {
            // Cache all static resources for 1 year (versioned filenames)
            var headers = ctx.Context.Response.GetTypedHeaders();
            headers.CacheControl = new CacheControlHeaderValue
            {
                Public = true,
                MaxAge = TimeSpan.FromDays(365)
            };
        }
        else
        {
            // Do not cache explicit `/index.html` or any other files.  See also: `DefaultPageStaticFileOptions` below for implicit "/index.html"
            var headers = ctx.Context.Response.GetTypedHeaders();
            headers.CacheControl = new CacheControlHeaderValue
            {
                Public = true,
                MaxAge = TimeSpan.FromDays(0)
            };
        }
    }
});
app.UseSpa(spa =>
{
    spa.Options.SourcePath = "ClientApp";
    spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions()
    {
        OnPrepareResponse = ctx => {
            // Do not cache implicit `/index.html`.  See also: `UseSpaStaticFiles` above
            var headers = ctx.Context.Response.GetTypedHeaders();
            headers.CacheControl = new CacheControlHeaderValue
            {
                Public = true,
                MaxAge = TimeSpan.FromDays(0)
            };
        }
    };

    if (env.IsDevelopment())
    {
        //spa.UseReactDevelopmentServer(npmScript: "start");
        spa.UseProxyToSpaDevelopmentServer("http://localhost:3000");
    }
});
  • Does not cache index or client-side routing (that returns index)
    • Cache-Control: public, max-age=0
  • Caches all /static/* resources for 1 year (versioned/sha'd filenames like javascript bundles)
    • Cache-Control: public, max-age=31536000
  • Does not cache any other resources (manifest.json, service-worker.js, etc)
    • Cache-Control: public, max-age=0

The main issue I had before making this change was because there was not an explicit Cache-Control header but there was a Last-Modified header, browsers would use this to cache the response.

Finally, if neither header is present, then we look for a "Last-Modified" header. If this header is present, then the cache's freshness lifetime is equal to the value of the "Date" header minus the value of the "Last-modified" header divided by 10. This is the simplified heuristic algorithm suggested in RFC 2616 section 13.2.4.

@Eilon Eilon added the area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI label Dec 20, 2018
@cvanem
Copy link

cvanem commented Jan 8, 2019

I can confirm that @techniq 's solution also works for me. Thanks!

@Eilon Eilon added area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates and removed area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI labels Jan 9, 2019
@mkArtakMSFT
Copy link
Member

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.

@jon-peel
Copy link

I tried the solution from @techniq but it is now working, and breakpoints in OnPrepareResponse are never hit.
I copied the code exactly, I also tried without the checks so everything would be given a cache of 365 days, but everything is returned with cache-control | public, max-age=0 so for me, at least, the question has not been answered.
@mkArtakMSFT what is your solution?

@ghost ghost locked as resolved and limited conversation to collaborators Dec 4, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates question
Projects
None yet
Development

No branches or pull requests

7 participants