Skip to content
This repository has been archived by the owner on Jan 23, 2021. It is now read-only.

How to cache "/"? #246

Closed
natecox opened this issue Feb 10, 2017 · 14 comments
Closed

How to cache "/"? #246

natecox opened this issue Feb 10, 2017 · 14 comments

Comments

@natecox
Copy link
Contributor

natecox commented Feb 10, 2017

Most of the guides online will tell you to set of your service worker cache like so (taken from the google airhorn pwa example):

self.addEventListener('install', function(e) {
 e.waitUntil(
   caches.open('airhorner').then(function(cache) {
     return cache.addAll([
       '/',
       '/index.html',
       '/index.html?homescreen=1',
       '/?homescreen=1',
       '/styles/main.css',
       '/scripts/main.min.js',
       '/sounds/airhorn.mp3'
     ]);
   })
 );
});

Notice that the first thing being added is '/', which caches the home page. What I can't figure out is how to get sw-precache to include this. I've been able to get it to successfully include every actual static file that I need, but not that open /.

@jeffposnick
Copy link
Contributor

Maintaining 4 different cached copies of the same underlying HTML file—/, /?homescreen=1, /index.html, and /index.html?homescreen=1—is not the best practice to emulate in a real-world application.

sw-precache handles that for you, via the directoryIndex option, which tells the service worker to treat requests for optional/path/to/ as if they were requests for optional/path/to/index.html. It defaults to index.html by default, which is normally what you want, so things should work out of the box.

There's another option in sw-precache, ignoreUrlParametersMatching, that would allow you to specify that the ?homescreen=1 parameter should be ignored when doing cache matching.

Using both of those options together, sw-precache will generate a service worker that keeps one copy of the underlying HTML file, and uses that cached copy to respond to any of those 4 possible request URLs.

(I've suggested using sw-precache for Airhorner in the past, but @PaulKinlan wants the project to demonstrate the use of a "vanilla" service worker.)

@natecox
Copy link
Contributor Author

natecox commented Feb 10, 2017

@jeffposnick Sorry, but this does not address the issue that I'm having. Let me see if I can clarify:

I'm using sw-precache with this configuration:

swPrecache: {
  swFileName: 'service-worker.js',
  directoryIndex: '/',
  options: {
    stripPrefix: 'priv/static/',
    staticFileGlobs: ['priv/static/**/*.*']
  }
}

My application cache currently looks like this:
image

However, in order to get my app to render in offline mode, one of those entries must be
simply http://localhost:4000/ with no actual filename associated. I don't actually have a
index.html file to cache because my web framework is rendering HTML directly to / (which is a common pattern across many frameworks).

If I manually create a service worker to look like this:

self.addEventListener('install', function(e) {
  e.waitUntil(
    caches
      .open('vuechat')
      .then(cache => cache.addAll([
        '/',
        '/service-worker.js',
        '/js/app.js',
        '/css/app.css',
        '/css/components.css',
        '/images/vuechat-logo.png',
        '/favicon.ico',
        '/browserconfig.xml',
        '/manifest.json',
        '/robots.txt',
        '/favicons/android-chrome-144x144.png',
        '/favicons/apple-touch-icon.png',
        '/favicons/favicon-16x16.png',
        '/favicons/favicon-32x32.png',
        '/favicons/favicon.ico',
        '/favicons/mstile-150x150.png',
        '/favicons/safari-pinned-tab.svg',
      ]))
 );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches
      .match(event.request)
      .then(response => response || fetch(event.request))
  );
});

I get exactly the behavior that I'm expecting.

So, my question is, how do I get sw-precache to include http://localhost:4000/ as a part of the cached assets?

@natecox
Copy link
Contributor Author

natecox commented Feb 10, 2017

I should also note that if I go to the generated service-worker.js file, and add ["/", "12345678"], to the very beginning of var precacheConfig, I am able to load the page from the offline cache without a problem, and my cache becomes:

image

Note the first entry.

@jeffposnick
Copy link
Contributor

Gotcha.

What you describe is handled by the dynamicUrlToDependencies option, which allow you to map server-rendered (or "dynamic") URLs to the list of files that they depend on. That way if any of those dependencies change, sw-precache knows to expire the cached entry for / and to retrieve the updated version from the network.

You can see an example configuration at https://github.com/GoogleChrome/sw-precache/blob/master/app-shell-demo/gulpfile.babel.js#L127—it uses /shell as the server-rendered URL, so you'd just swap in / instead, and include the array of files that uniquely determine the output of / as the parameter's value.

See also #156 for some discussion around whether "dynamicUrlToDependencies" makes sense as a name, and whether it's surfaced properly in the documentation.

@natecox
Copy link
Contributor Author

natecox commented Feb 10, 2017

haha, I was going to complain that I couldn't get it to work, and then realized I didn't have the dynamicUrlToDependencies inside the options block.

Working fine now, thanks!

@janhoogeveen
Copy link

But what if your dependencies have nested dependencies? In React we use composition a lot, so there's no guarantee that when my top-level component's hash doesn't change the HTML response is the same.

@jeffposnick
Copy link
Contributor

@janhoogeveen, if we're talking specifically about keeping the App Shell HTML up to date when using React to populate your content, the model that I've seen used successfully is to include just the basic placeholder where the DOM insertion will take place in the App Shell HTML, as in this example:

https://github.com/GoogleChrome/sw-precache/blob/master/app-shell-demo/src/views/index.handlebars#L17

Maybe there are scenarios in which you really need to include the HTML equivalent of your components' DOM encapsulated in your App Shell HTML, in which case yes, you'd have to list all of the files that contribute uniquely to that component's output as part of the dynamicUrlToDependencies configuration. But just including an insertion point seems to be sufficient for common use cases.

If you have more details about why that wouldn't work for your use case, it would help if you could file a new issue explaining what you're running into, and pointing to a sample repo/live deployment.

@janhoogeveen
Copy link

Thanks very much for your response @jeffposnick

Seems like just loading the template/app shell works fine as is indeed. I kind of forgot that by loading just the shell the JS can fill in everything with the cached JS assets afterwards. Works like a charm in my repo now.

@lili21
Copy link

lili21 commented Jun 1, 2017

@jeffposnick how to handle the cdn path ? specify https://cdn.com/ as webpack publicPath, the cache will be like below

# Request Response
0 https://cdn.com/index.html?_sw-... OK
1 ... OK

But that's not what I want ,and the index.html cache won't work either. Cause the request url of index.html will be https://example.com/index.html rather then https://cdn.com/index.html.

so how to fix this ?

@jeffposnick
Copy link
Contributor

See my response at goldhand/sw-precache-webpack-plugin#79 (comment)

I don't think hosting assets between a CDN and HTML + SW on a different server is a use case that we can easily support.

@piotr-cz
Copy link

piotr-cz commented Jun 23, 2017

Query strings starting with utm_ are not cached by default.

I'm not aware of any way how to configure that in CRA without ejecting so I've just changed the start_url in manifest.json to ./index.html?utm_source=homescreen. I'm using a react-router package so when application loads, /index.html or this segment is immediately being replaced to / anyway.

See this SO question for more details.

@janokary
Copy link

janokary commented Jun 23, 2017

What would be the problem with deifining index at runtimeCaching for example like
`
runtimeCaching: [
{
urlPattern: "/",
handler: "networkFirst"
}

`

@piotr-cz
Copy link

piotr-cz commented Jun 23, 2017

@janokary How can you set runtimeCaching option?

update: oh this is not an CRA issues list but sw-precache, sorry of OT

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants