Local storage has stopped working

I have recently updated my ionic development environment to the latest, this is the results of ionic info.
Ionic:

Ionic CLI : 6.11.0 (/home/peter/.node_modules_global/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 5.3.1
@angular-devkit/build-angular : 0.1000.5
@angular-devkit/schematics : 10.0.5
@angular/cli : 10.0.5
@ionic/angular-toolkit : 2.3.0

Cordova:

Cordova CLI : 10.0.0
Cordova Platforms : android 9.0.0
Cordova Plugins : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 4.1.3, (and 12 other plugins)

Utility:

cordova-res : 0.15.1
native-run : 1.0.0

System:

Android SDK Tools : 26.1.1 (/home/peter/.android/android-sdk)
NodeJS : v12.18.2 (/usr/bin/node)
npm : 6.14.7
OS : Linux 5.7

The problem is that now the local storage does not work when I test the app in the browser using ionic serve --browser chromium. It has been working fine for several years before this. I have not tried it on the phone, the phone works fine on the previous version. There is nothing stored on Web SQL or IndexedDB and when I console.log storage the driver is null.

The storage is set on login with:
this.storage.set(‘currentUser’, JSON.parse(JSON.stringify(newUser)));
The storage is queried with:
this.getUserInfo().then((userObj) => { … });
which calls:
public getUserInfo() : any {
return this.storage.get(‘currentUser’);
}
Now this doesn’t work on browser and complains that userObj is undefined.
This is a pain as every time I make a change when running in the browser, I have to login again to see the results of the change.
Any ideas?

1 Like

I have done a few more investigations without much progress.
I tried on a different browser.
I then added more detail to the code:
this.storage.ready().then(() => {
console.log(‘Storage Ready’);
this.storage.set(‘currentUser’, JSON.stringify(newUser));
this.storage.set(‘versionInfo’, this.appConfig.VersionInfo);
console.log(this.storage);
this.storage.length().then((obj) => {
console.log(obj);
});
});
This returns on the console log:
Storage Ready
Storage {_driver: null, _dbPromise: ZoneAwarePromise}_dbPromise: ZoneAwarePromise {__zone_symbol__state: true, __zone_symbol__value: {…}}_driver: nulldriver: (…)proto: Object
0
So after the driver is ready storage is null and after adding some objects the index is 0.

Please, please does anyone have any thoughts on this?

Do you have a sample app up on github? It’s kind of hard to know the issue without one.

No, I do not use github for this. I put all the relevant code in the description. What else do you need to know. As I said the code has worked for some time until the infrastructure was updated.

The only things which might be missing are the app_module:
import { IonicStorageModule } from ‘@ionic/storage’;
IonicStorageModule.forRoot({name:’__name’, driverOrder: [‘indexeddb’, ‘sqlite’, ‘websql’]}),

and the service:
import { Storage } from ‘@ionic/storage’;
constructor(
public http: HttpClient,
public network: Network,
public appConfig: AppConfigService,
private storage: Storage
) { }

I have re-enabled the storage by going back to version 2.2.0 of @ionic/storage, the problem seems to be with the new noop code in version 2.3.0.

I had to examine the code to find the likely problem and then try it. This took me about 2 days of effort that I can ill afford.

How should we adapt our code to make this work on the latest version? Shouldn’t updates include instructions if the code needs changing - this is what I get with linux.

Does anyone have any advice on how to make @ionic/storage 2.3.0 work??

I asked for a sample project that could be used to inspect this.
Please provide one.

I have tested 2.3.0 of storage and it’s working fine for me.

As you probably discovered figuring this part out, that triggers if window.process is defined. So is there a possibility that you’ve got some dependent library in your project that is defining it? If so, can you eliminate that dependency? If not, can you try undefining it? First place I would attempt to do so would be in main.ts right before bootstrapping the app.

I did a search for window.process within the whole of my app directory using the Find in Files… facility in Gedit. The only files that this appears are in node-modules. Most of these are part of a useColors function, exceptions are the isInBrowser function in support-map-support.js, and the resolve function in resolve.js. All of these are part of ‘if’ statements so should not be setting anything.

What code can I use to undefine window.process?

Is there any other way it can be set?

I would expect the following to work:

delete (window as any).process;

I used the following in my main.ts to replicate your problem:

(window as any).process = {};

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));

Combining that with this simple page:

export class HomePage {
  n = 0;

  constructor(private storage: Storage) {
  }

  bump(): void {
    this.storage.ready()
      .then(() => this.storage.get("n"))
      .then(n => n + 1)
      .then(n => this.storage.set("n", n))
      .then(() => this.storage.get("n"))
      .then(n => this.n = n);
  }
}
<ion-content>
  <ion-item>
    <ion-label>n is {{n}}</ion-label>
  </ion-item>
  <ion-button (click)="bump()">bump</ion-button>
</ion-content>

…and I see your symptoms: n becomes blank on the first click of the “bump” button, and never recovers.

All of that being said, the code you have posted is still problematic, and I would urge you to rearchitect it. The primary issue here is that storage writes are not synchronous. I can think of two ways around this: one is to meticulously wait on the promises returned by every set call. That is a massive PITA in my book, and also causes needless performance hiccups.

A better approach, I think, is to use storage only to communicate between app runs, not within one. So only read from storage once, at app startup, or whenever the information is first needed. Write whenever you like. For in-app communication, use mutually injected service providers to share data, not storage.

Thanks.

I tried your fix but it didn’t change anything. I also tried a test app, which worked. I have also searched for the pattern within my app directory without success. So I am sticking with version 2.2.0 for now until I can determine what the root cause actually is.

Actually, the storage is primarily used for user information that enables them to automatically logon to the server where the bulk of the information and processing is. There is a service in-place for exchanging data between pages and the design minimises that information exchange.

With the fault, I have revisited the storage code such that at first access the object is stored as part of the service so the storage is only used at the start when read and when the objects change - which is rarely. The primary setting point is user login.

If you cannot replicate the issue in a new project, it’s not going to be possible to debug. If you end up being able to replicate and can provide a sample project, please do.

On my failing app I managed to look at the value of the process. I have a screen shot but it will not let me upload; I have tried png and jpg without success (from linux). The process object is filled with a bunch of NOOP elements and has been produced by the browser.js function (node-modules.process.browser.js). So the process is undefined, it is just filled with NOOPs. The function suggested to clear the process doesn’t work. I cannot figure out what is calling the browser.js function or why it is being called. There are a number of modules that incorporate it, e.g. www/vendor-es.js. I use mermaid.js within my app, this does incorporate the browser.js function but I have included it in my test app and it has no impact on the process. Why is storage bothered about the process?

Please just provide a demo app that has the same issue. I do not need you to look into further, I can manage that. I need you to provide an example that has the issue you’ve mentioned.

It’s treating the presence of a defined process global as an answer to the question “am I running under Angular server-side rendering?”.

It might help me make a less-pathological repro if you could post the entire package.json from your affected project.

I have the same problem and very much appreciate this discovery about window.process. Well, it turns out that you have to define it if you want to use the AWS Amplify, as told to us by this documentation:
https://docs.amplify.aws/start/getting-started/setup/q/integration/angular

More specifically, this is the relevant code that the AWS Amplify library wants us to add as part of the setup, to src/polyfills.js:

(window as any).global = window;
(window as any).process = {
  env: { DEBUG: undefined },
};

I’ll look into whether i can “eliminate that dependency”, but I’m not sure. In the meantime, I think I can easily create a repro so will try that first.

1 Like

Brilliant! That’s exactly the sort of non-pathological example I was looking for. I would advise you to temporarily pin @ionic/storage at 2.2.0 in your package.json and watch the discussion on this commit, because I suspect the endgame here is for Ionic to change the way it attempts to detect SSR. I came across the SO thread that kygoh posted as a comment there during my detective endeavour here, and it does indeed strike me as a more robust method.

Thanks for the suggestion to roll back one version to 2.2.0. Before reading your suggestion, I did end up reproducing the problem in a minimal app here:

Unfortunately, going to version 2.2.0 did not solve this issue, as you can see in the reproduced repository above, which I’ve updated to go back to version 2.2.0 of @ionic/storage, but which still shows the same issue reported here. To see the issue in action:

  • Run the app in the repo above and check the DEV console - you’ll see result = undefined in DEV console.
  • Now comment out the line that sets window.process in src/polyfills.js and you’ll see result = test-value

The place in the code that prints out result = .. is in app.component.ts.

Not really, I don’t think. Try ~2.2.0, not ^2.2.0.

1 Like