sw-precache icon indicating copy to clipboard operation
sw-precache copied to clipboard

Do a better job of explaining dynamicUrlToDependencies

Open jeffposnick opened this issue 8 years ago • 11 comments

dynamicUrlToDependencies important concept for any site that includes server-side rendering and which uses partial templates/includes to produce a final HTML resource. However, it's importance and use cases aren't explained as well as they should be in the documentation.

I think the actual https://github.com/GoogleChrome/sw-precache#dynamicurltodependencies-objectstringarraystring entry can be expanded some, as well as incorporating an explanation of why it's useful into the main text of the docs.

Also, renaming it as part of a major version change could help.

CC: @addyosmani @jpmedley

jeffposnick avatar Aug 24 '16 16:08 jeffposnick

After re-reading our current docs around dynamicUrlToDependencies a few times, I think the current naming is actually fine.

What we could do is expand the paragraph explaining why it's useful to include a few more practical examples. The current Jade one is great. Maybe include a PHP one (it's sadly still super popular on the server) .

addyosmani avatar Sep 09 '16 17:09 addyosmani

Agree on explaining about the benefit of using it and possibly issues if not using it.

wernight avatar Dec 06 '16 15:12 wernight

If I get it correctly, setting a dynamicUrlToDependencies results in that URL being cached (pre-cached?) and only updated if that template changes. It should never be used if that URL contains dynamic content.

wernight avatar Dec 06 '16 15:12 wernight

@jeffposnick @addyosmani related to this, it'd be nice if I could supply my own hash or even have the "dependency" part of this just be a string of HTML. We have a scenario where we're the HTML is mostly static, but a few environment-specific items get changed depending on where it's running.

So the we're generating html on the fly, once... based on an aggregated config object. So, there isn't really a single file somewhere (like a .jade file) that we can point to and say, "any time this changes the content is different." Instead, we generate an HTML string that is essentially "static" for that environment.

I'm not sure how to best support this from an API perspective.

Perhaps something like this?

dynamicUrlToDependencies: {
   //  if it's an array just have it work as it does currently but... if I'm supplying a string
   // assume that it's already a hash?
   '/': someHashStringDerivedFromMyHTMLString
}

I'd be willing to take a stab at sending a PR with this functionality if you think that would be good. Thoughts??

HenrikJoreteg avatar Mar 07 '17 00:03 HenrikJoreteg

or even just:

dynamicUrlToDependencies: {
   //  if it's an array just have it work as it does currently but... if I'm supplying an object
   //  just assume i already did the work of hashing/sizing it.
   '/': {
     size: 1639, // whatever stat.size
     hash: '944c9aef2dfdc2b0f3b00c0b861028af' // whatever derived hash
   }
}

☝️ with this approach there's less magic strings, and you'd still retain "total size" calculations

HenrikJoreteg avatar Mar 07 '17 01:03 HenrikJoreteg

Hi All. I'm having a difficult time understanding dynamicUrlToDependencies in a server-rendered react app, where there are not really any static templates -- the "app shell" / initial markup is a template string, returned from a function.. ie:

function pageTemplate(html, injectedStyles) {
  return `
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <style> ${injectedStyles} </style>
    </head>
    <body>
      <div id="root">${html}</div>
      <script src="https://cdn.com/path/vendorsBundle.js" />
      <script src="https://cdn.com/path/appBundle.js" />
    </body>
  </html>
`
}

//  react app setup, generate markup from react
const html = renderToString(
  <Provider store={store}>
    <RouterContext {...renderProps} />
  </Provider>
);

// load above-the-fold styles into memory
const injectedStyles = fs.readFileSync(path.resolve(__dirname, './assets/AboveFold.css'), 'utf8');

// send the generated markup
res.send(pageTemplate());

.. after this initial render, all routing is done client-side.

In a setup like this, how would you use dynamicUrlToDependencies to cache your "app shell" (presumably the contents of pageTemplate()? )

tconroy avatar Apr 28 '17 17:04 tconroy

@tconroy did you find an answer to this?

dmaevac avatar Aug 31 '17 18:08 dmaevac

Hi @DveMac -- I did not. It seems to be the goals of sw-precache dynamicURLToDependenciesand server-side rendering are diametrically opposed. I ended up rolling my own caching solution without the use of sw-precache.

Quite unfortunate since otherwise liked the library!

tconroy avatar Sep 01 '17 19:09 tconroy

@tconroy ok, thanks! I noticed the description in another issue you opened here describes pretty much exactly what I am trying to achieve too. At the moment I feel like I can still achieve it with this module, but Im probably not seeing the whole picture yet! If you ended up documenting/blogging about your solution I would definitely be interested to read about it.

dmaevac avatar Sep 03 '17 15:09 dmaevac

Sorry, just revisiting this given the recent activity.

The model that tends to work best for this sort of setup is to make your App Shell HTML generic, and then rely on client-side rendering to populate the content specific to the given URL once the App Shell has been initialized. The runtime JavaScript that's needed to do the client-rendering can be precached, meaning it won't necessarily take a network request in order to get content on the screen.

You can see an example of this at https://github.com/GoogleChrome/sw-precache/blob/master/app-shell-demo/, and in particular, the build configuration at https://github.com/GoogleChrome/sw-precache/blob/master/app-shell-demo/gulpfile.babel.js#L129

The alternative would be to set up a mapping of specific URLs to the final rendered HTML during your build process, taking advantage of the changes in https://github.com/GoogleChrome/sw-precache/pull/262 to specify a full string as the dependency rather than a list of files:

{
  dynamicUrlToDependencies: {
    '/page1': pageTemplate(htmlForPage1, injectedStyles),
    '/page2': pageTemplate(htmlForPage2, injectedStyles),
    // etc.
  }
}

That approach will only work if you can ensure that anytime the output of pageTemplate() might change, you have a means of re-running your build process and redeploying your service worker file. Since pageTemplate() is a server-rendered function, you'd presumably want to hook into whatever tooling you're using to deploy updates to your (Express, presumably) backend server, and ensure that your service worker build process is re-run alongside it.

jeffposnick avatar Sep 05 '17 16:09 jeffposnick

Thanks @jeffposnick , I stumbled on https://workboxjs.org and from there found https://github.com/GoogleChrome/application-shell both of which have been super helpful. I managed to knock together a prototype that is on the right track using workbox and taking cues from the application-shell example.

dmaevac avatar Sep 05 '17 16:09 dmaevac