Skip to content
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

Service worker registration failed in Safari angular 8 #31061

Closed
naturalfreak opened this issue Jun 14, 2019 · 14 comments

Comments

Projects
None yet
6 participants
@naturalfreak
Copy link

commented Jun 14, 2019

I updated my application from angular v7 to angular v8 and I have some problems with service workers with Safari. I have same error when enter in www.angular.io

[Error] Service worker registration failed with: TypeError: TypeError: Type error run (polyfills-es2015.75c15c263061f321fee9.js:1:1925) (anonymous function) (polyfills-es2015.75c15c263061f321fee9.js:1:12750) runTask (polyfills-es2015.75c15c263061f321fee9.js:1:2544) _ (polyfills-es2015.75c15c263061f321fee9.js:1:8987) promiseReactionJob

Safari Version 12.1.1 (14607.2.6.1.1)
MacOs Mojave v10.14.5
Node v10.16.0

My package.json

{
"dependencies": {
"@angular/animations": "^8.0.1",
"@angular/cdk": "^8.0.1",
"@angular/common": "^8.0.1",
"@angular/compiler": "^8.0.1",
"@angular/core": "^8.0.1",
"@angular/forms": "^8.0.1",
"@angular/material": "^8.0.1",
"@angular/platform-browser": "^8.0.1",
"@angular/platform-browser-dynamic": "^8.0.1",
"@angular/platform-server": "^8.0.1",
"@angular/pwa": "^0.800.3",
"@angular/router": "^8.0.1",
"@angular/service-worker": "^8.0.1",
"@nguniversal/express-engine": "^8.0.0-rc.1",
"@nguniversal/module-map-ngfactory-loader": "^8.0.0-rc.1",
"compression": "^1.7.4",
"tslib": "^1.10.0",
"rxjs": "~6.4.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.800.3",
"@angular/cli": "^8.0.3",
"@angular/compiler-cli": "^8.0.1",
"@angular/language-service": "^8.0.1",
"@types/express-useragent": "^0.2.21",
"@types/jasmine": "^3.3.13",
"@types/jasminewd2": "^2.0.6",
"@types/node": "^12.0.8",
"codelyzer": "^5.1.0",
"express": "^4.17.1",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "^5.4.2",
"ts-loader": "^6.0.2",
"ts-node": "^7.0.1",
"tslint": "^5.17.0",
"typescript": "~3.4.5",
"webpack-cli": "^3.3.4"
}
}

@ngbot ngbot bot added this to the needsTriage milestone Jun 14, 2019

@Squidy06

This comment has been minimized.

Copy link

commented Jun 17, 2019

@naturalfreak did you find a solution?

@naturalfreak

This comment has been minimized.

Copy link
Author

commented Jun 18, 2019

No, I tested it in new project with enabled service workers and I faced same issue. But safari loads both module and nomodule scripts.

bug

@hassanasad

This comment has been minimized.

Copy link

commented Jun 18, 2019

I can report similar issue - Its not working on my existing project, i created a new one following the steps mentioned here https://angular.io/guide/service-worker-getting-started and its giving same Rejected promise issue. TypeError: TypeError: Type error

Safari 12.1.1 (14607.2.6.1.1)

NG versions

Angular CLI: 8.0.3
Node: 12.4.0
OS: darwin x64
Angular: 8.0.1
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router, service-worker

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.800.3
@angular-devkit/build-angular     0.800.3
@angular-devkit/build-optimizer   0.800.3
@angular-devkit/build-webpack     0.800.3
@angular-devkit/core              8.0.3
@angular-devkit/schematics        8.0.3
@angular/cli                      8.0.3
@angular/pwa                      0.800.3
@ngtools/webpack                  8.0.3
@schematics/angular               8.0.3
@schematics/update                0.800.3
rxjs                              6.4.0
typescript                        3.4.5
webpack                           4.30.0
@gkalpak

This comment has been minimized.

Copy link
Member

commented Jun 19, 2019

Sorry, I don't have access to Safari 😞
After spending quite some time trying to debug this on SauceLabs, I finally gave up (because SauceLabs seems to be behaving strangely - sometimes giving the error and sometimes not 🤷‍♂).

If someone with native access to Safari 12 could debug this further and provide more info, I would be happy to help.

Things I would try out:

  • Replace ngsw-worker.js with the v7 ngsw-worker.js (and leave everything else the same).
  • Replace the @angular/service-worker code in main-es2015.js with the v7 code.
  • Depending on the outcome of the above, try apply specific changes from the v8 versions and see what causes it to break.
  • Try to build the app with optimization turned off in angular.json.
  • Try to build the app with optimization turned on but buildOptimizer turned off in angular.json.
@H--o-l

This comment has been minimized.

Copy link
Contributor

commented Jun 19, 2019

Hey @gkalpak.
I'm just in front of the error in a Safari v11.1.2.

I try the v7 ngsw-worker.js and I can confirm it register without error, while the v8.0.1 do not register.

I'm not sure to understand the flowing line, can you give us more details?

Replace the @angular/service-worker code in main-es2015.js with the v7 code.

I will try the rest, thanks!

@gkalpak

This comment has been minimized.

Copy link
Member

commented Jun 19, 2019

Thx, @H--o-l. So, are you saying that just by replacing ngsw-worker.js with the v7 version it starts working (while leaving everything else unchanged, including leaving @angular/service-worker to v8)?

If that's the case, then it shouldn't be hard to identify the issue, because the changes in ngsw-worker.js between v7 and v8 are minimal.

@H--o-l

This comment has been minimized.

Copy link
Contributor

commented Jun 19, 2019

Thx, @H--o-l. So, are you saying that just by replacing ngsw-worker.js with the v7 version it starts working (while leaving everything else unchanged, including leaving @angular/service-worker to v8)?

Yes exactly

If that's the case, then it shouldn't be hard to identify the issue, because the changes in ngsw-worker.js between v7 and v8 are minimal.

Great suggestion.
Maybe I found the line:
If I apply the following patch to the ngsw-worker.js file, I do not have the issue anymore,

--- save_dist/fr/ngsw-worker.js	2019-06-19 17:27:35.497808706 +0200
+++ dist/fr/ngsw-worker.js	2019-06-19 17:52:49.570376274 +0200
@@ -19,7 +19,8 @@
         constructor(scope) {
             // Suffixing `ngsw` with the baseHref to avoid clash of cache names
             // for SWs with different scopes on the same domain.
-            const baseHref = this.parseUrl(scope.registration.scope).path;
+            // const baseHref = this.parseUrl(scope.registration.scope).path;
+            const baseHref = '/';
             this.cacheNamePrefix = 'ngsw:' + baseHref;
         }
         /**

It register but goes in SAFE_MODE or EXISTING_CLIENT_ONLY with:

Driver state: SAFE_MODE (Initialization failed due to error: Type Error [native code]

In Chrome the same service worker works fine.

@gkalpak

This comment has been minimized.

Copy link
Member

commented Jun 19, 2019

That's strange. I wonder if Safari doesn't like cche names that include /.
Could you try (a) to replace / with _ and (2) log more info about the error?

@H--o-l

This comment has been minimized.

Copy link
Contributor

commented Jun 19, 2019

I have a better diff, that make more sense.
My assumption is that safari does not like that the second argument of parseUrl() is missing.

--- ./ngsw-worker.js	2019-06-19 18:18:25.303115707 +0200
+++ ../../save_dist/fr/ngsw-worker.js	2019-06-19 18:19:02.182301878 +0200
@@ -18,7 +18,7 @@
         constructor(scope) {
             // Suffixing `ngsw` with the baseHref to avoid clash of cache names
             // for SWs with different scopes on the same domain.
-            const baseHref = this.parseUrl(scope.registration.scope, scope.registration.scope).path;
+            const baseHref = this.parseUrl(scope.registration.scope).path;
             this.cacheNamePrefix = 'ngsw:' + baseHref;
         }
         /**
@@ -356,8 +356,7 @@
             this.metadata = this.db.open(`${this.prefix}:${this.config.name}:meta`);
             // Determine the origin from the registration scope. This is used to differentiate between
             // relative and absolute URLs.
-            this.origin =
-                this.adapter.parseUrl(this.scope.registration.scope, this.scope.registration.scope).origin;
+            this.origin = this.adapter.parseUrl(this.scope.registration.scope).origin;
         }
         cacheStatus(url) {
             return __awaiter(this, void 0, void 0, function* () {

With that change the service worker is in the NORMAL state, and works offline.

@H--o-l

This comment has been minimized.

Copy link
Contributor

commented Jun 19, 2019

Sorry the diff was inverted:

--- ../../save_dist/fr/ngsw-worker.js	2019-06-19 18:19:02.182301878 +0200
+++ ./ngsw-worker.js	2019-06-19 18:18:25.303115707 +0200
@@ -18,7 +18,7 @@
         constructor(scope) {
             // Suffixing `ngsw` with the baseHref to avoid clash of cache names
             // for SWs with different scopes on the same domain.
-            const baseHref = this.parseUrl(scope.registration.scope).path;
+            const baseHref = this.parseUrl(scope.registration.scope, scope.registration.scope).path;
             this.cacheNamePrefix = 'ngsw:' + baseHref;
         }
         /**
@@ -356,7 +356,8 @@
             this.metadata = this.db.open(`${this.prefix}:${this.config.name}:meta`);
             // Determine the origin from the registration scope. This is used to differentiate between
             // relative and absolute URLs.
-            this.origin = this.adapter.parseUrl(this.scope.registration.scope).origin;
+            this.origin =
+                this.adapter.parseUrl(this.scope.registration.scope, this.scope.registration.scope).origin;
         }
         cacheStatus(url) {
             return __awaiter(this, void 0, void 0, function* () {
@H--o-l

This comment has been minimized.

Copy link
Contributor

commented Jun 19, 2019

Could you try (a) to replace / with _ and (2) log more info about the error?

Ok, I change / and _ and log all the /ngsw/state trace :

NGSW Debug Info:

Driver state: SAFE_MODE (Initialization failed due to error: Type error
[native code]
parseUrl@https://toto/ngsw-worker.js:51:35
AssetGroup@https://toto/ngsw-worker.js:360:48
PrefetchAssetGroup
https://toto/ngsw-worker.js:1377:54
map@[native code]
AppVersion@https://toto/ngsw-worker.js:1370:64
https://toto/ngsw-worker.js:2234:63
forEach@[native code]
https://toto/ngsw-worker.js:2229:47
generatorResume@[native code]
fulfilled@https://toto/ngsw-worker.js:1786:66
promiseReactionJob@[native code])
Latest manifest hash: none
Last update check: 29s762u



=== Idle Task Queue ===
Last update tick: 5s245u
Last update run: 14s696u
Task queue:


Debug log:

Can you tell me if #31061 (comment) seems like a good lead to you ?

@gkalpak

This comment has been minimized.

Copy link
Member

commented Jun 19, 2019

Wow, that's awesome. Great sleuthing, @H--o-l 👏
It seems indeed to be the case that Safari chokes when the second argument is undefined (or even ''), even though according to MDN:

A USVString representing the base URL to use in case url is a relative URL. If not specified, it defaults to ''.

But it is fine, when the second argument is not provided at all:

new URL('https://angular.io/')  // OK
new URL('https://angular.io/', undefined)  // TypeError

So, I guess we could work-around that by changing Adapter#parseUrl() like this:

 parseUrl(url: string, relativeTo?: string): {origin: string, path: string, search: string} {
-  const parsed = new URL(url, relativeTo);
+  const parsed = !relativeTo ? new URL(url) : new URL(url, relativeTo);
   return {origin: parsed.origin, path: parsed.pathname, search: parsed.search};
 }

@H--o-l, would you like to submit a PR with that fix (after verifying that it does indeed work 😁)?

H--o-l added a commit to H--o-l/angular that referenced this issue Jun 19, 2019

fix(service-worker): registration failed on Safari
Since Angular v8, `parseUrl()` is called without `relativeTo`, thus `new URL()`
is called with `relativeTo = undefined`.

Safari does not like it and the service worker registration failed:
```js
new URL('https://angular.io/')  // OK
new URL('https://angular.io/', undefined)  // TypeError
```

Closes angular#31061

H--o-l added a commit to H--o-l/angular that referenced this issue Jun 19, 2019

fix(service-worker): registration failed on Safari
Since Angular v8, `parseUrl()` is called with `relativeTo`, thus `new URL()`
is called with `relativeTo = undefined`.

Safari does not like it and the service worker registration failed:
```js
new URL('https://angular.io/')  // OK
new URL('https://angular.io/', undefined)  // TypeError
```

Closes angular#31061

H--o-l added a commit to H--o-l/angular that referenced this issue Jun 19, 2019

fix(service-worker): registration failed on Safari
Since Angular v8, `parseUrl()` is called without `relativeTo`, thus `new URL()`
is called with `relativeTo = undefined`.

Safari does not like it and the service worker registration failed:
```js
new URL('https://angular.io/')  // OK
new URL('https://angular.io/', undefined)  // TypeError
```

Closes angular#31061
@H--o-l

This comment has been minimized.

Copy link
Contributor

commented Jun 19, 2019

Thanks a lot @gkalpak for the final kick & diff!
It works great in my environment for what I see.

I opened the PR, I let you tell me there you think about it.
Thanks again!

H--o-l added a commit to H--o-l/angular that referenced this issue Jun 19, 2019

fix(service-worker): registration failed on Safari
Since Angular v8, `parseUrl()` is called without `relativeTo`, thus `new URL()`
is called with `relativeTo = undefined`.

Safari does not like it and the service worker registration failed:
```js
new URL('https://angular.io/')  // OK
new URL('https://angular.io/', undefined)  // TypeError
```

Closes angular#31061
@naturalfreak

This comment has been minimized.

Copy link
Author

commented Jun 19, 2019

Thanks @gkalpak, I tested these modifications and everything works as expected in my projects.

H--o-l added a commit to H--o-l/angular that referenced this issue Jun 20, 2019

fix(service-worker): registration failed on Safari
Since Angular v8, `parseUrl()` is called without `relativeTo`, thus `new URL()`
is called with `relativeTo = undefined`.

Safari does not like it and the service worker registration failed:
```js
new URL('https://angular.io/')  // OK
new URL('https://angular.io/', undefined)  // TypeError
```

Closes angular#31061

H--o-l added a commit to H--o-l/angular that referenced this issue Jun 20, 2019

fix(service-worker): registration failed on Safari
Since Angular v8, and commit [b3dda0e], `parseUrl()` can be called without
`relativeTo`, thus `new URL()` can be called with `relativeTo = undefined`.

Safari does not like it and the service worker registration failed:
```js
new URL('https://angular.io/')  // OK
new URL('https://angular.io/', undefined)  // TypeError
```

[b3dda0e]: angular@b3dda0e

Closes angular#31061

H--o-l added a commit to H--o-l/angular that referenced this issue Jun 24, 2019

fix(service-worker): registration failed on Safari
Since Angular v8, and commit b3dda0e, `parseUrl()` can be called without
`relativeTo`, thus `new URL()` can be called with `relativeTo = undefined`.

Safari does not like it and the service worker registration fails:
```js
new URL('https://angular.io/') // OK
new URL('https://angular.io/', undefined) // TypeError
```

Closes angular#31061

kara added a commit that referenced this issue Jun 24, 2019

fix(service-worker): registration failed on Safari (#31140)
Since Angular v8, and commit b3dda0e, `parseUrl()` can be called without
`relativeTo`, thus `new URL()` can be called with `relativeTo = undefined`.

Safari does not like it and the service worker registration fails:
```js
new URL('https://angular.io/') // OK
new URL('https://angular.io/', undefined) // TypeError
```

Closes #31061

PR Close #31140

@kara kara closed this in a5dd4ed Jun 24, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.