angular: Service worker doesn't support seeking in videos

I’m submitting a…


[x] Bug report  
[x] Feature request (not sure, maybe this is more a feature request?)

Current behavior

If you ng run app:build:production and your pwa comes with a <video> element where you also utilize seeking (setting currentTime depending on your app logic and/or user input) it will not work or only very inconsistently. Most videos will simply run from start and not at the setted currentTime position. This is only the case when videos are delivered/fetched by the service worker. So it works in development mode.

Expected behavior

Videos should start at the setted currentTime.

Minimal reproduction of the problem with instructions

// on template
<video id="myVideo"><source id="myVideoSrc" src="video.mp4" type="video/mp4"></video>

// in page.ts
let videoObject = document.getElementById("myVideo");
videoObject.currentTime = 100;
videoObject.play();

// now build for production
// @angular/pwa has to be installed
> ng run app:build:production

Environment

Angular version: 6.1.2

Browser: Chrome (desktop) version 69

Others:

This seems to be a known problem since service workers don’t know Range requests. However it also looks like very easily fixable if I understand this thread comment correctly: https://bugs.chromium.org/p/chromium/issues/detail?id=575357#c10

A workaround would be a convenient way to completely exclude requests from service worker (not just set strategies for them). But obviously it would be better if we also could cache some videos. For exclusion also this issue may be relevant : https://github.com/angular/angular/issues/21191

_EDIT(gkalpak): Issue summary in https://github.com/angular/angular/issues/25865#issuecomment-634048868._

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 7
  • Comments: 23 (7 by maintainers)

Commits related to this issue

Most upvoted comments

We hit this issue, because requests to video needed to be withCredentials and SW failed over without applying cookies to headers. A workaround was to skip handling request via SW. We used patch-package to maintain this patch. Here is the patch

diff --git a/node_modules/@angular/service-worker/ngsw-worker.js b/node_modules/@angular/service-worker/ngsw-worker.js
index 51c431b..1216506 100755
--- a/node_modules/@angular/service-worker/ngsw-worker.js
+++ b/node_modules/@angular/service-worker/ngsw-worker.js
@@ -1896,6 +1896,10 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ 'Content-Type': 'text/plain' }
          */
         onFetch(event) {
             const req = event.request;
+            //PATCH to prevent caching certain kinds of requests
+            // - PUT requests which breaks files upload
+            // - requests with 'Range' header which breaks credentialed video irequests
+            if (req.method==="PUT" || !!req.headers.get('range')) return;
             // The only thing that is served unconditionally is the debug page.
             if (this.adapter.parseUrl(req.url, this.scope.registration.scope).path === '/ngsw/state') {
                 // Allow the debugger to handle the request, but don't affect SW state in any

No, we don’t need a config option. We just need to teach the SW how to handle range requests (by incorporating code similar to this and potentially making other necessary adjustments).

To sum up (for future reference):

  • The problem is caused by the ServiceWorker’s not handling range requests (i.e. requests with a Range header) correctly. See this blog post for more details.
  • An easy work around is to make the SW ignore affected requests by adding an ngsw-bypass header or query param. This has the downside that it breaks caching of such resources by the SW and so they won’t be available offline.
  • A more involved work around is to manually augment the SW to handle range requests correctly, e.g. using something similar to this code by @philnash.

BTW, Workbox has a module to handle range requests: Workbox Range Requests (source code)

If anyone is interested in trying to incorporate the fix into the SW and submit a pull request, I would be happy to help/review.

Hopefully, this issue gets solved soon. We are using a nasty hack, after building, in the build script we’re adding a line to ignore the video:

sed -i $'/^            const req = event.request;.*/a if (req.headers.get(\'range\')) return;' ./dist/ngsw-worker.js

This way we’re avoiding a new fork from the main repo.

No timeline, no promise, not high in priority. However this issue is open since June 2018

Of course there is a lot of people interested to see a fix in order to have video working with Safari without having to extand manually the ngsw. I’m one of them 😃

Hello, I actually had to update that SW code recently (turned out the caches API didn’t like storing 206 responses), so I’d check the latest from here: https://github.com/philnash/philna.sh/blob/master/sw.js#L49-L100.

Fixing #21191 would indeed provide a workaround for this usecase (but this could be properly fixable on its own as well). Does anyone want to take a stub at incorporating this fix into @angular/service-worker.

My issue was that the videos of my PWA (Angular + NGSW) simply wouldn´t play on iOS using Safari. I finally found the solution in this answer: https://stackoverflow.com/a/58966397/8581106.

The solution for me was to bypass the Angular Service Worker with ?ngsw-bypass=true after the video url. This might not be related to everyones issue in here, however, this issue was linked as a reference to people sharing the same problem as me.

Example:

<video muted preload="metadata" controls playsinline>
     <source src="assets/vid/tutorial_invoice.mp4?ngsw-bypass=true" type="video/mp4">
</video>

As mentioned in https://github.com/angular/angular/issues/25865#issuecomment-421925411, if someone wants to take a stub at incorporating range handling into the SW, I’d be happy to help/review. How do other implementations (e.g. workbox) handle this?

@mordka Thank you for your suggested fix.

I was having a slightly different issue where range requests were breaking audio in Safari due to the SW failing to apply the Content-Range header. I applied the range header patch using patch-package and it fixed the issue.