Skip to content

Service worker registration failed in Safari angular 8 #31061

Closed

Description

@naturalfreak

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"
}
}

Activity

  1. added this to the needsTriage milestone on Jun 14, 2019
  2. Squidy06 commented on Jun 17, 2019

    @Squidy06

    @naturalfreak did you find a solution?

  3. naturalfreak commented on Jun 18, 2019

    @naturalfreak
    Author

    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

  4. hassanasad commented on Jun 18, 2019

    @hassanasad

    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
    
  5. gkalpak commented on Jun 19, 2019

    @gkalpak
    Member

    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.
  6. H--o-l commented on Jun 19, 2019

    @H--o-l
    Contributor

    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!

  7. gkalpak commented on Jun 19, 2019

    @gkalpak
    Member

    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.

  8. H--o-l commented on Jun 19, 2019

    @H--o-l
    Contributor

    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.

  9. gkalpak commented on Jun 19, 2019

    @gkalpak
    Member

    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?

  10. H--o-l commented on Jun 19, 2019

    @H--o-l
    Contributor

    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.

  11. H--o-l commented on Jun 19, 2019

    @H--o-l
    Contributor

    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* () {
  12. H--o-l commented on Jun 19, 2019

    @H--o-l
    Contributor

    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 ?

  13. gkalpak commented on Jun 19, 2019

    @gkalpak
    Member

    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 😁)?

  14. H--o-l commented on Jun 19, 2019

    @H--o-l
    Contributor

    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!

  15. naturalfreak commented on Jun 19, 2019

    @naturalfreak
    Author

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

  16. added a commit that references this issue on Jun 24, 2019
    f470e69
  17. hassanasad commented on Aug 5, 2019

    @hassanasad

    @kara Service worker using Safari is not working in Angular 8.2.0 anymore. The POST requests are giving Gateway 504 errors.

    UPDATE:
    This is the error i am getting

    [Error] Fetch API cannot load MY_API_URL due to access control checks.
    [Error] Failed to load resource: Request header field Cache-Control is not allowed by Access-Control-Allow-Headers.
    

    2nd UPDATE:
    Turns out the error was coming in Safari due to some server side configuration. Its not a regression in Angular 8.2.0

  18. H--o-l commented on Aug 6, 2019

    @H--o-l
    Contributor

    @hassanasad Thanks for your comment.

    An aswer that is mine only, I'm not part of the Angular team:

    Your bug does not seem related to this issue which is closed, because the bug was found and fixed.

    If you have an issue configuring your service worker for the first time, you should ask on stackoverflow.
    If you have notice a regression, or have found a bug (you have to be pretty sure), please open a new issue.
    When opening a new issue, all details needed to be able to assist you will be asked and organized, that is why it's important to open a seperate issue.

    Finally, seen your error I think it's:

    • Not related to Safari. Saying so is misleading. Test on other navigator before assuming it.
    • Not related to Angular but HTTP tech. Search on stackoverflow first.
    • Related to server configuration. A begining of answer may be here https://stackoverflow.com/a/32501365/5234260

    It's not against you, and you are right to ask when you have issue.
    But first be sure to have debug a bit, and search already existing answers on Internet a lot.
    Otherwise you may not receive answer at all.

  19. hassanasad commented on Aug 6, 2019

    @hassanasad

    @H--o-l Thanks for your thoughtful reply. Yes you are right. We have found the issue and resolved it and initially it felt like a regression but after doing intense debugging it appears to have been an error occurring due to some library updates on Server Side.

    It was indeed a bug that was only showing up in Safari when the ServiceWorker was trying to send a POST request to server and being denied access. Everything was working fine on Chrome and Firefox.
    Safari was adding Pragma and Cache-control headers with the service worker request which were being denied on the server because they weren't in the allowed headers list. I cannot seem to understand why we are unable to reproduce this error using Postman.
    Anyways - Yes, what appeared to have been a regression was NOT actually a regression (but it was indeed quite weird issue to debug)

  20. angular-automatic-lock-bot commented on Sep 15, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  21. locked and limited conversation to collaborators on Sep 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: service-workerIssues related to the @angular/service-worker package

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions