Prog blog

How to fix video Safari issue in Angular

How to fix video Safari issue in Angular

I started to add videos showing the operation of some of the solutions I describe on my blog. Something came to see how the entry about Web share button works on Safair. And it turned out that the video is not loading :/. After a long investigation, it turned out that Angular Service Worker has a bug in itself and does not send the header Range when responding to requests for video in the Safair browser. Below I describe a workaround I found on github.

A list of steps to workaround the problem.

  1. Install a patch-package.

npm i patch-package

  1. Add a patch-package to postinstall.

./package.json

{ 
  "scripts": {
    "postinstall": "patch-package"
  }
}
  1. Add a patch for the @angular/service-worker package.

    ./patches/@angular+service-worker+8.2.14.patch

    diff --git a/node_modules/@angular/service-worker/ngsw-worker.js b/node_modules/@angular/service-worker/ngsw-worker.js
    index 0d185a8..f4fc756 100755
    --- a/node_modules/@angular/service-worker/ngsw-worker.js
    +++ b/node_modules/@angular/service-worker/ngsw-worker.js
    @@ -1925,6 +1925,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 requests
    +            if (req.method==="PUT" || !!req.headers.get('range')) return;
                const scopeUrl = this.scope.registration.scope;
                const requestUrlObj = this.adapter.parseUrl(req.url, scopeUrl);
                if (req.headers.has('ngsw-bypass') || /[?&]ngsw-bypass(?:[=&]|$)/i.test(requestUrlObj.search)) {
  2. Run npm install

After these steps you can enjoy working videos on safari. The patch cares in such a way that for requests where you need the Range Service Worker does not try to cache them (in other words, it works like a ngsw-baypass).