How can I recover initialized plugins after a crash during development?


#1

I am working with Ionic 3.2.1 with lazy-loading and the SQLite-plugin on a real Android device (not emulated).

I initialize the plugin once platform.ready has fired

platform.ready().then(() => {
	console.log('platform.ready');
	this.rootPage = 'FirstPage';// lazy-loaded
	// this is where I bootstrap my plugin into a service
	// I need to make sure it is ready, so no injection allowed
	this.historyService.bootstrap(sqlite);
});

I am still developing and parts of my application may crash the whole app. When I fix the offending line or setup some debugging lines and save, the live-reload kicks in. The bad part comes when the app tries to run again. The app is in a page where the plugins should have been initialized already, but because they aren’t, I just get hit with the obvious

TypeError: Cannot read property 'executeSQL' of undefined

I don’t know of a way to hook my plugin initialization when recovering from a crash. Does anybody else have this issue or a way around it. If a guard can be used like ionViewCanEnter, can anybody give me some pointers on how to use it?

I can still develop, I just have to go the extra step to activate chrome:screencasting that grants me the refresh button. When I hit it, the whole process starts again and my app bootstraps from the start while jumping back to the first page. This is eating a lot of time and doesn’t always work the first time around.


#2

I think this is a fundamentally flawed design. Use the DI system provided; don’t do end runs around it with the way you are setting up historyService.


#3

So, when the app crashes, and live-reload reboots it doesn’t actually have to start from the beginning??

…I’m feeling quite dumb right now…

This will save me time. Get back to you tomorrow with the full details.


#4

I’ve never used this “live-reload” you’re speaking of, but whatever it is, I would not pervert the fundamental structure of the app to try to accommodate it.


#5

?

So you do not use the livereload option of IonicCLI during development? (maybe I’ve framed the issue in the wrong manner?)

ionic cordova run android --livereload --consolelogs --address <n.n.n.n>

Maybe you only work on the browser? but still… ionic serve is launched in livereload mode by default and you should be seeing your pages reload upon saving.

You make it sound like it’s heresy when it’s on of the most widely spreadout features while developing with Angular (even in the AngularJS days). I used it while I was developing the app on Ionic2 before I upgraded and switched to lazy-loading. However, on the desktop there is no native plugins so it really didn’t matter. Now that I am testing directly on a phone, there is no such luck.

Either way, simply injecting SQLite into the page’s constructor does not work. After a livereload event occurs (I made a change in a file and saved it), the last active page attempts to load before the plugins are available which means that I’m still getting a Cannot read property ‘executeSql’ of undefined


#6

You haven’t shown much code, so I can’t say anything more concrete, but wherever you are calling executeSql, that is the place to ensure that things have been properly initialized.

What I’m saying is heresy is fighting against the DI system provided by Angular with that bootstrap() method. historyService must be capable of initializing itself properly.


#7

Then I suppose that my HistoryService must have some way of knowing when platform.ready has come to pass?

This would mean that my services (that depend on plugins) have to defer their operations until plugins are ready. I would have to include in my services’ initialization routine a “subscription” to platform.ready (and very likely to platform.resume as well), which means that every method on these services has to become an observable due to the fact that the services have no way of knowing when they will be ready beforehand.

I think there could be a better way of doing this, or at least I hope so. If not, then I’ll have to inject Platform as well and set it all up in the constructor.

As for some code, there is not much to it, it doesn’t need much either. It just needs two lazily-loaded components: an initial component where the app starts (for AppComponent.rootPage) and a second component that actually uses the plugins during initialization. And for testing it, all that is required is that the app be running with the livereload option on a device, navigating to the second component and then triggering a livereload by making a change and saving the file. The app will attempt to reload on the component it was on and die when it can’t use the plugins it depends on.

I’m starting to set up a blank project with the minimum parts needed and I’ll try out your solution. I’ll get back to you as soon as I can (maybe tomorrow)

edit

or maybe, the component should be the one that knows when the app is ready (much like AppComponent does in every example) and delay any use of the service to give time for some bootstrapping?

Oh, I’m easily confused… sorry if this just an entanglement


#8

Either an Observable or a Promise, yes. In general, I have all my services’ methods return some sort of future, in part to allow for situations like this.

Another idiom you can use is to have your services themselves expose ready Promises (that may be dependent on Platform.ready()). So if service B needs service A, but not necessarily any plugins, but service A does need plugins, then B can wait on a.ready instead of having to inject a Platform that it doesn’t independently need.