-
Notifications
You must be signed in to change notification settings - Fork 829
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
Safari 12 .mp4 support #1663
Comments
Sorry for the delay in getting back to you about this. I've got a couple of questions:
If you could share your actual Workbox config or final service worker file, that would answer most of the questions. Thanks! |
Webpack config (I don’t use any additional workbox plugins): config.plugins.push(new WorkboxPlugin.GenerateSW({
importWorkboxFrom: 'local',
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: true,
navigateFallback: '/index.html',
navigateFallbackWhitelist: [/^\/issues/, /^\/about/],
runtimeCaching: [{
urlPattern: /\/(ajax|media)\//,
handler: 'networkFirst',
options: {
cacheName: 'content-cache'
}
}]
})); The videos have paths like The service worker file is generated by workbox. I’ve copy-pasted it into this Gist if you want to take a look at it. My site’s |
There's unfortunately a lot of nuance needed to get this fully working with any service worker implementation. Workbox can help, in that the logic needed to honor Here's an example of a setup that I confirmed works in Safari 12: https://gist.github.com/jeffposnick/814b13353f16b8171999febfeb8b7938 (I'd normally use RawGit to host this sort of example with a live demo, but now that it's retired, you're better off making a copy and running it from a local web server.) There are a number of "gotchas" called out in the comments, and for the same of completeness, I'm outlining them here:
These best practices are generally applicable outside of the Safari 12 context, but I'm guessing that other browsers are more flexible about dealing with unexpected video response bodies. We should definitely get this all written up for a section at https://developers.google.com/web/tools/workbox/guides/advanced-recipes |
This might be a naive question (and likely is as I am not the most experienced with service workers), but, in your example is the |
So that's what I initially thought last night, but after trying this out a bit more this morning, I (re)learned that attempting to cache a HTTP 206 response leads to a rejection—there was actually an earlier issue about this; see #1644. Getting a complete copy of the vide file in the cache is still important if you want to use I'm working on some better guidance/recipe that would use runtime caching to populate the cache with a full response when there's a cache miss (while also passing the Stay tuned for that. |
Relevant article (published today): Service workers: beware Safari's range request. |
@jeffposnick - We are running into this issue also. any update on the guidance/recipe will be greatly appreciated :) |
I also ran into this problem and I'm happy to finally find somebody else sharing that problem. In my case (strategy cacheFirst) it seems not to work (event with the rangeRequest plugin), when the video is not in the cache yet, so it's forwarded to the server as a full request and answered as a full request. Is it possible to answer the range request that the video tag in Safari with a partial response while still asking the full file from the server so not to poison the cache with said partial response? |
Sorry for the lack of updates. I got a chance to try out a few scenarios today. Here's the current set of recommendations I could offer w.r.t. Workbox interaction, across all browsers. It would be great if folks could sanity check this with their own deployments, and then I could transfer the recommendations over to the Workbox documentation, and/or make some changes to the Workbox runtime (as appropriate). First, I'd suggest that folks read @jakearchibald's "I discovered a browser bug" as background, as it explains some of what appears to be going on (and it's interesting!). Second, take a look at the status of the "Range headers correctly preserved" web platform test, which @domenic was good enough to dig up for me. Unfortunately, all browsers are currently marked as Third (and this was something that I didn't realize), Fourth, optionally but to prevent some noise, you should make sure that Workbox doesn't attempt to cache HTTP 206 (partial content) responses received from the network. Calling Fifth, and following from the fourth point, you have to explicitly cache the full video file ahead of time, via either precaching or a call to So... taken all together, here are the important parts:
|
#1804 is a discussion around explicitly checking for
to that recipe. |
Thank you very much @jeffposnick ! Could you please provide an example for |
@xcv58, it's up to you when you'd want to run this code (in response to the user pressing a "add to cache" button next to a thumbail, in the service worker's
And then just make sure to use the same |
I've written up a summary at google/WebFundamentals#7050 and we'll use that as the official place to refer folks to when they run into similar issues. (I wish it were easier, but...) |
Using rangeRequest as a child options fails.
|
There's only "out of the box" support for a few plugins when using workbox/packages/workbox-build/src/lib/runtime-caching-converter.js Lines 49 to 54 in e15877f
For more involved runtime caching scenarios, you'll need to switch to either |
GoogleChrome/workbox#1663 gatsbyjs/gatsby#10151 To make this even worse, the problem is only encountered on the built hosted website rather than locally
See GoogleChrome/workbox#1663 and gatsbyjs/gatsby#10151 . Despite being same-origin, crossOrigin=anonymous needs to be set for Safari
In case it's useful for anyone still having issues with this, Safari Tech Preview (96) just shipped with:
|
Following these recommendations to make cache videos work on Safari https://developers.google.com/web/tools/workbox/guides/advanced-recipes GoogleChrome/workbox#1663 (comment)
Hey @jeffposnick I'm still facing the issue of videos not loading from cache in Safari (both macOS & iOS) in my package.json (scripts section) "scripts": {
"build-sw": "node ./src/sw-build.js",
"start": "react-scripts start",
"build": "GENERATE_SOURCEMAP=false react-scripts build && npm run build-sw",
"test": "react-scripts test",
"eject": "react-scripts eject"
} sw-build.js const workboxBuild = require('workbox-build');
const buildSW = () => {
workboxBuild
.injectManifest({
swSrc: 'src/sw-template.js', // sw template file
swDest: 'build/service-worker.js', // same name as sw used by serviceWorker.js
globDirectory: 'build',
maximumFileSizeToCacheInBytes: 8000000,
globPatterns: ['**\/*.{json,js,css,html,png,jpg,mp4}',], // precaching
})
.then(({ count, size, warnings }) => {
warnings.forEach(console.warn);
console.log(`${count} files will be precached, totaling ${size} bytes.`);
})
.catch(console.error);
};
buildSW(); sw-template.js if (typeof importScripts === 'function') {
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.3/workbox-sw.js');
if (workbox) {
console.log('Workbox is loaded');
workbox.core.skipWaiting();
/* injection point for manifest files. */
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
workbox.routing.registerRoute(
({ url }) => url.pathname.endsWith('.mp4'),
new workbox.strategies.CacheFirst({
plugins: [
new workbox.rangeRequests.RangeRequestsPlugin(),
],
}),
'GET'
);
}
} serviceWorker.js (only excerpt, unchanged created by create-react-app) // ...
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
// ...
}
// ... My Basically what happens is that my site initially works fine and videos are playing (because loaded from network). As soon as I refresh the page or visit a page that has already been loaded into cache the video no longer appears (blank screen). When debugging, this is the response that is received from service worker: Is there anything you can see that I am doing wrong? |
Since your call to
Alternatively, instead of using
If you go with this second approach, it's up to your to properly version your |
Thank you for the quick response. I've tried your first approach, literally copy pasting it to test it & I've added logs to confirm that the code is actually run, which it is. I'm also getting the default success message from the service worker "Content is cached for offline use." - nevertheless, it still does not work. The even though the strategy now is Status code: 200 I believe that the bytes=0-1 is the issue, but isn't that what the RangeRequestsPlugin should handle? Anything else you can think of that might be the issue here? Really puzzled here. |
Yes, the Are you able to share the URL for a version of your site with the above service worker deployed? I might be able to help more if I could debug something live. |
After some more input from @jeffposnick I finally got it working - it appears the devil was in the detail. I had to change my service worker to this: console.log('Starting Workbox...');
if (typeof importScripts === 'function') {
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.3/workbox-sw.js');
if (workbox) {
console.log('Yay - Workbox is loaded');
workbox.core.skipWaiting();
// Your .mp4 file will likely have a WB_REVISION parameter appended to it
// when stored in the precache. This plugin will normalize the cach key:
const cacheKeyWillBeUsed = ({ request }) => {
const url = workbox.precaching.getCacheKeyForURL(request.url);
return new Request(url, { headers: request.headers });
};
workbox.routing.registerRoute(
({ url }) => url.pathname.endsWith('.mp4'),
new workbox.strategies.CacheFirst({
cacheName: workbox.core.cacheNames.precache,
plugins: [
{ cacheKeyWillBeUsed },
new workbox.rangeRequests.RangeRequestsPlugin(),
],
})
);
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
console.log('Done');
} else {
console.log('Workbox could not be loaded. No Offline support');
}
} The important part is the Also important: |
precaching plugin see: GoogleChrome/workbox#1663
Hi, @jeffposnick is there anyway to tell the Adding @PhilJay rules to the e.skipWaiting(), e.clientsClaim(), e.precacheAndRoute([ /* ... */ ]), e.registerRoute(/* ... */) which prevents me to test the solution. |
No, that's not possible using Something like /~https://github.com/cra-template/pwa/blob/master/packages/cra-template-pwa/template/src/service-worker.js is a good starting point that could be customized/re-ordered if you go that route. |
Thank you for the pointers to InjectManifest. It's a bit more manual work that I have anticipated so as a temporary workaround I'll just exclude mp4 (might help someone else landing here). They are loaded with a file-loader and the following webpack name option: exclude: [/\.map$/, /^manifest.*\.js$/, /\.mp4(?::(\d+))?/], |
Struggled for 2 days to make this work, but finally got it. My problem was the order of the methods, and the name of the cache. Matchoptions should maybe be turned off? I'm not sure what this does, but I think it enables the rangerequest for all resources. In my case that is good since it includes mp3 as well then. @jeffposnick Maybe you should add the below to the docs (https://developers.google.com/web/tools/workbox/guides/advanced-recipes?authuser=0#cached-av). This really confused me: I left the "your-cache-name-here" in place since I'm so new to service workers and even caches. Also crossorigin="anonymous" does not seem to be necessary (in recent Safari versions at least: https://developers.google.com/web/tools/workbox/guides/advanced-recipes?authuser=0#cached-av) This is for workbox 4.3.1 in a Vue2 app.
|
is there any news on this ? |
Someone can help me with This is my config and the video is working in all browsers, except iOS Safari (without SW the video plays well, or just excluding with
|
To support service worker range requests, as discussed: GoogleChrome/workbox#1663 (comment)
Library Affected:
workbox-sw
Browser & Platform:
Safari 12
Issue or Feature Request Description:
No matter what strategy I use within Workbox, I cannot get a .mp4 to play via Safari that is cached with a service worker with a file served from AWS S3. I even wrote my own strategy using IndexedDb (one that converted to
ArrayBuffer
to get around known Safari issues with storage and one that didn't, https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/indexeddb-best-practices) to no avail.I did remove the service worker to prove it worked and it played just fine. Images, JSON, and other text based content seemed to work just fine. I don't have any other video types to easily test with.
This does appear to be a known issue with Safari, per https://bugs.webkit.org/show_bug.cgi?id=184447, but they are basically claiming you need to fix it. Also, this is possibly a hole in the fetch spec to begin with, per whatwg/fetch#747, but the gist of it there seems to also be "you have to fix it". I did try adding the header they wanted in my custom strategy, but that also didn't work (although, granted, this is my first service worker, so I may have done something wrong). I'm also not sure if Workbox is eating my headers I am adding (although I can see the header on the response in the network tab, so I have to assume it is not).
Somewhat amusingly, if you right click on the video element and say "Download", it downloads almost immediately and works, implying it's pulling from cache.
In summation, I'm not 100% sure there is work that can be done, but raising awareness of the issue within workbox to see if there is a simple fix that can potentially be implemented for the strategies for this somewhat acute issue.
The text was updated successfully, but these errors were encountered: