angular-cli: Existing App does not get Service Worker capabilities
Versions
Angular CLI: 1.6.0
Node: 9.2.0
OS: win32 x64
Angular: 5.1.0
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router
... service-worker
@angular/cli: 1.6.0
@angular-devkit/build-optimizer: 0.0.35
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.41
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.0
@schematics/angular: 0.1.10
@schematics/schematics: 0.0.10
typescript: 2.6.2
webpack: 3.10.0
Repro steps
Have an existing app with no PWA capability and apply steps to upgrade it as described in docs.
Observed behavior
Despite the fact it builds with no error and dist
folder has files like ngsw.json
& ngsw-worker.js
as expected, they are not loaded on network request when browsed. (Tested with incognito mode as well)
No service-worker effect at all in app.
Desired behavior
Service Worker added to built app when steps in official docs are applied.
Mention any other details that might be useful
On the same machine, a new app generated with Angular-CLI 1.6.0 with --service-worker
flag. That app loads service worker as expected.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 28
- Comments: 53 (5 by maintainers)
I also had this issue, the culprit seams to be angularFire2. I worked around it by registering the service worker in main.ts.
Service worker won’t run because of ng app is not stable (ApplicationRef.isStable (https://angular.io/api/core/ApplicationRef#members), application is not becoming stable if there is a code which runs intervals (setInteral or Observable.timer and etc. which come from setInterval or setTimeout (related with NgZone.hasPendingMicrotasks)).
As example of such behaviour:
ng new my-project --service-worker
;setInterval(t => { console.log('Ping')}, 500);
Workaround for such behaviour wrap - wrap all timer-code to
this.applicationRef.isStable.subscribe(isStable => { if (isStable) { <code goes here> } })
Full code
@alxhub , I am trying to make my existing app into pwa and for that I am following https://angular.io/guide/service-worker-getting-started. Now, the point is I have ejected ng command and hence using webpack. Upon the running the build command, ngsw.json is not getting created in dist folder although, ngsw-worker.js file is getting created. For your review, I am pasting the snippets below.
angular-cli.json code
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "project": { "name": "core", "ejected": true }, "apps": [ { "root": "src", "outDir": "dist", "assets": [ "assets", "manifest.json", "icons" ], "index": "index.html", "main": "main.ts", "polyfills": "polyfills.ts", "test": "test.ts", "tsconfig": "tsconfig.app.json", "testTsconfig": "tsconfig.spec.json", "prefix": "app", "serviceWorker": true, "styles": [ "styles.css" ], "scripts": [], "environmentSource": "environments/environment.ts", "environments": { "dev": "environments/environment.ts", "prod": "environments/environment.prod.ts" } } ], "e2e": { "protractor": { "config": "./protractor.conf.js" } }, "lint": [ { "project": "src/tsconfig.app.json", "exclude": "**/node_modules/**" }, { "project": "src/tsconfig.spec.json", "exclude": "**/node_modules/**" }, { "project": "e2e/tsconfig.e2e.json", "exclude": "**/node_modules/**" } ], "test": { "karma": { "config": "./karma.conf.js" } }, "defaults": { "styleExt": "css", "component": { } } }
Package.json file{ "name": "kognifai-poseidon-next-core", "version": "0.0.1", "description": "", "main": "index.js", "author": "KDI", "publishConfig": { "registry": "https://kdi.jfrog.io/kdi/api/npm/npm-local/" }, "scripts": { "ng": "ng", "start": "webpack-dev-server --port=4200", "build": "webpack", "test": "karma start ./karma.conf.js", "lint": "ng lint", "e2e": "protractor ./protractor.conf.js", "pree2e": "webdriver-manager update --standalone false --gecko false --quiet", "versionup": "npm-version-up", "pwa": "npm run build --prod && sw-precache --root=dist --config=precache-config.js", "ngsw-config": "node_modules/.bin/ngsw-config dist src/ngsw-config.json", "ngsw-copy": "cp node_modules/@angular/service-worker/ngsw-worker.js dist/", "build-prod-ngsw": "npm run build --prod && npm run ngsw-config && npm run ngsw-copy", "serve-prod-ngsw": "npm run build-prod-ngsw && http-server dist -p 8080" }, "private": false, "dependencies": { "@angular/animations": "^5.0.0", "@angular/common": "^5.0.0", "@angular/compiler": "^5.0.0", "@angular/core": "^5.0.0", "@angular/forms": "^5.0.0", "@angular/http": "^5.0.0", "@angular/platform-browser": "^5.0.0", "@angular/platform-browser-dynamic": "^5.0.0", "@angular/router": "^5.0.0", "@angular/service-worker": "^5.2.3", "core-js": "^2.4.1", "kognifai-design-system": "^0.7.2", "kognifai-poseidon-authenticationservice": "0.1.1", "kognifai-poseidon-settingsservice": "^0.1.2", "lodash": "^4.17.4", "ng-pwa-tools": "0.0.15", "rxjs": "^5.5.2", "uuid": "^3.2.1", "zone.js": "^0.8.14" }, "devDependencies": { "@angular/cli": "^1.5.5", "@angular/compiler-cli": "^5.0.0", "@angular/language-service": "^5.0.0", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/lodash": "^4.14.97", "@types/node": "~6.0.60", "autoprefixer": "^6.5.3", "circular-dependency-plugin": "^3.0.0", "codelyzer": "~3.2.0", "copy-webpack-plugin": "^4.1.1", "css-loader": "^0.28.1", "cssnano": "^3.10.0", "exports-loader": "^0.6.3", "file-loader": "^1.1.5", "html-webpack-plugin": "^2.29.0", "istanbul-instrumenter-loader": "^2.0.0", "jasmine-core": "~2.6.2", "jasmine-spec-reporter": "~4.1.0", "karma": "~1.7.0", "karma-chrome-launcher": "~2.1.1", "karma-cli": "~1.0.1", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", "karma-junit-reporter": "^1.2.0", "karma-phantomjs-launcher": "^1.0.4", "less-loader": "^4.0.5", "npm-version-up": "^0.1.5", "phantomjs-prebuilt": "^2.1.16", "postcss-custom-properties": "^6.2.0", "postcss-loader": "^2.0.8", "postcss-url": "^7.1.2", "protractor": "~5.1.2", "raw-loader": "^0.5.1", "sass-loader": "^6.0.3", "source-map-loader": "^0.2.0", "style-loader": "^0.13.1", "stylus-loader": "^3.0.1", "sw-precache-webpack-plugin": "^0.11.4", "ts-node": "~3.2.0", "tslint": "~5.7.0", "typescript": "~2.4.2", "uglifyjs-webpack-plugin": "1.0.0", "url-loader": "^0.6.2", "webpack": "~3.8.1", "webpack-concat-plugin": "1.4.0", "webpack-dev-server": "~2.9.3" } }
manifest.json`{ “name”: "Poseidon Next, The Complete Solution ", “start_url”: “/”, “orientation”: “any”, “scope”: “/”, “display”: “standalone”,
}`
ngsw-config.json file
`{ “routing”:{ “index”:“/index.html”, “routes”:{ “/”:{ “match”: “exact” }, “/coffee”:{ “match”: “prefix” }
}`
main.ts file
`import { enableProdMode } from ‘@angular/core’; import { platformBrowserDynamic } from ‘@angular/platform-browser-dynamic’;
import { AppModule } from ‘./app/app.module’; import { environment } from ‘./environments/environment’;
if (environment.production) { enableProdMode(); }
platformBrowserDynamic().bootstrapModule(AppModule) // waiting for angular to load bootstrapping and then only loading service worker .then(()=>{ if (‘service-worker’ in navigator){ navigator.serviceWorker.register(‘/ngsw-worker.js’) // navigator.serviceWorker.register(‘/ngsw-worker.js’) } }) .catch(err => console.log(err)); ` app.module.ts file
`import { BrowserModule } from ‘@angular/platform-browser’; import { NgModule } from ‘@angular/core’; import { HttpModule } from ‘@angular/http’; import { FormsModule, ReactiveFormsModule } from ‘@angular/forms’;
import { AppRoutingModule } from ‘./app-routing.module’;
import { AppComponent } from ‘./app.component’; import { LoginComponent } from ‘./login/login.component’; import { HomeComponent } from ‘./home/home.component’; import { AboutComponent } from ‘./about/about.component’; import { NavigationService } from ‘./navigation/navigation.service’; import { HeaderComponent } from ‘./header/header.component’; import { FooterComponent } from ‘./footer/footer.component’; import { SidebarComponent } from ‘./sidebar/sidebar.component’; import { DasboardComponent } from ‘./dasboard/dasboard.component’; import { MainComponent } from ‘./main/main.component’; import { ModuleLoaderService } from ‘./services/module-loader.service’; import { OverlayService } from ‘./services/overlay.service’; import { InitializeService } from ‘./services/initialize.service’; import { CookieService } from ‘./services/cookie.service’; import { SettingsService } from ‘./settings/settings.service’; import { ServiceWorkerModule } from ‘@angular/service-worker’; import { SettingsServiceTestPageComponent } from ‘./settings/test/settingsservice.testpage.component’; import { AuthenticationService } from ‘kognifai-poseidon-authenticationservice/dist/AuthenticationService’; import { AuthenticationServiceTestPageComponent } from ‘./authentication/test/authenticationservice.testpage.component’; import { environment } from ‘…/environments/environment’;
// import { HelloPoseidonModule } from ‘kognifai-poseidon-hello-poseidon’;
@NgModule({ declarations: [ AppComponent, LoginComponent, HomeComponent, AboutComponent, HeaderComponent, FooterComponent, SidebarComponent, MainComponent, DasboardComponent, SettingsServiceTestPageComponent, AuthenticationServiceTestPageComponent ], imports: [ BrowserModule, FormsModule, HttpModule, AppRoutingModule, // ServiceWorkerModule.register(‘/woker-basic.min.js’,{ enabled: environment.production }) ServiceWorkerModule.register(‘/ngsw-worker.js’, {enabled: environment.production}) // HelloPoseidonModule ], providers: [ NavigationService, ModuleLoaderService, SettingsService, AuthenticationService, OverlayService, InitializeService, CookieService ], bootstrap: [AppComponent] }) export class AppModule { } `
Having said that, while running the build command say npm run build-prod-ngsw it gives below error
(node:23044) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Cannot read property ‘startsWith’ of undefined (node:23044) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I have also attached screenshots for your review. Kindly, let me know what is wrong going here?
Thanks, Rahul
This has definitely not been resolved yet. HNY!
I’ve solved this issue with a workaround, what it does is register the service worker and simulate the messages that ServiceWorkerModule sends. I’ve created a little service with this behaviour, you can check it here: https://github.com/Pedro-vk/EthKudos/blob/abb2104e4338e5b7529e7b50838d9ab787c386fc/src/app/shared/service-worker.service.ts
I had the same problem. In my case it was caused by the default route in the app.module.ts
path: '', redirectTo: '/main/0', pathMatch: 'full'
With these settings the ngsw-worker.js didn’t load.
I encountered also this issue on my existing app. So I tried to generate a new app like so
and after a
ng build --prod
it did work as expected, the service worker is registered and visible in the dev tools.Then I tried to generate a new app like so
I then followed the steps described in the guide and it did also work as expected. So I decided to dig deeper in my own app. After removing some code, I was able to get a service worker running and it appeared that it was due to a conflict with Pusher from the
pusher-js
package.I have no ideas what could be the root cause of this interaction between this line of code and the service worker as no errors are thrown in the console neither at compile time nor at runtime, but maybe this experience could help solving this issue.
The last thing I did is moving the assignment in a method that is never called at the startup of the app so I could have both a service worker registered and an instance of Pusher running.
Hi, a quick note, updated to angular 6, firebase 5 and angularfire2 5rc10 and the fix is no longer needed, service workers works out of the box.
Hi @alxhub
First, thanks a lot for your help!
I confirm that I build the project through
ng build --prod
. I then serve the dist folder withhttp-server
as suggested in the guide.I expect to see the SW registered and activated in the “Application” tab of Chrome devtools, but nothing shows up.
From my terminal:
MacBook-Air:testsw sntmrtn$ ng build --prod
Date: 2017-12-09T08:08:45.452Z
Hash: fe12f6c535c8e1842392
Time: 29354ms
chunk {0} polyfills.169c804fcec855447ce7.bundle.js (polyfills) 60.9 kB [initial] [rendered]
chunk {1} main.d0d19976182286b68554.bundle.js (main) 171 kB [initial] [rendered]
chunk {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 0 bytes [initial] [rendered]
chunk {3} inline.92d63502b90fcb9628dd.bundle.js (inline) 1.45 kB [entry] [rendered]
MacBook-Air:testsw sntmrtn$ cd dist/
MacBook-Air:dist sntmrtn$ http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8080
http://192.168.178.27:8080
And the result:
EDIT: It actually works on https, see: https://dist-zobmrubhnx.now.sh/
However, I still did not manage to make it work on my client’s project.
The same here… I find out that service-worker is not registered after I inject
AngularFirestore
fromangularfire2/firestore
to a component or a service.See https://github.com/angular/angularfire2/issues/1347
This costs me few hours to find out what is not working. My service worker dont register in whatever.
The problem is, service worker only worked on HTTPS(secure content)
I struggled with something similar for a long time, but my problem was different. I used
http://0.0.0.0:8000
as my URL, but then the serviceWorker is not present asnavigator.serviceWorker
.I just changed it to
http://localhost:8000
and everything works. It must be because localhost is considered a secure origin.Maybe that will help someone.
Apparently there are cases that prevent PWA work properly in Angular, but they are not clearly stated in documents or any errors get returned while building your app. If you are only dealing with Angular’s own packages you are supposed to be fine, when you are using external libraries (even ones developed by Google’s own people, like AngularFire2) chances are it will fail by default, then you search and patch your code to make it work.
So I believe now it’s rather a problem of properly informing erroneous cases & documentation issue than service worker part of Angular itself. Still it didn’t work for me as is.
@rahulsahay19 , can I know what the fix is?
Apparently its an issue with the latest Angular 8 release. https://github.com/angular/angular/issues/31061
thanks @ChokeBilly! I had similar messed up default route redirect.
Based on https://github.com/angular/angular-cli/issues/8779#issuecomment-397844943, this seems to have been resolved.
@zendizmo In my case, my ngsw-config.json file was not on latest schema. When I took the sample config, then it worked later on moved my changes in there!
@odahcam not a problem. Its fixed. Thanks!
@rahulsahay19 Try to post a question @ http://stackoverflow.com
@Argentan : Thanx. Your solution works in my project. 😃
At least, the service worker is registered in Chrome. But I’m still facing a problem with caching. When I’m going offline (service worker tab) and reload the page, the app is loaded (HTML, CSS) , but the Google icon font is missing. My ngsw-config.json:
"urls": [ "https://fonts.googleapis.com/icon?family=Material+Icons" ]
On a second page reload, the page is empty and the console has no log entry. What is going on? Never thought that it is so hard to get a service worker running and caching. 😉
@sntmrtn thanks for the reproduction!
Can you confirm exactly what steps you’re taking to build and serve the project, where you would expect to see the Service Worker?
As mentioned in the documentation,
ng serve --prod
will not cause a Service Worker to be registered, only a trueng build --prod
will run the SW build step and produce adist
directory with the Service Worker configured. When I build and serve this app (viang build --prod
andhttp-server
), the SW is registered and activated as expected.@alxhub Please see the following repo:
https://github.com/sntmrtn/testsw