Minimongo transpile bug with Meteor 3.3 on iOS and Android

I’m getting this strange, intermittent bug in Minimongo after upgrading from Meteor 2.16 to 3.3.

It seems that the Minimongo code is being transpiled in order to avoid using async calls on iOS and Android. The web version isn’t transpiled.

I’ve traced it as below. query is undefined, so the highlighted statement throws “Cannot read properties of undefined” when running query.dirty:

In the original code, this is impossible since query is used to iterate over this.queries in a for-of loop:

async insertAsync(doc, callback) {
    doc = EJSON.clone(doc);
    const id = this.prepareInsert(doc);
    const queriesToRecompute = [];

    // trigger live queries that match
    for (const qid of Object.keys(this.queries)) {
      const query = this.queries[qid];

      if (query.dirty) {
        continue;
      }

In the case I traced above, qid is 80, but this.queries only has entries for 81 and 82.

So the transpiler seems to be injecting this somehow, but it gets mixed up.

I suspect that Cordova might be doing the transpiling, probably to support older mobile browsers without async / promises support.

I expect that this would affect anybody using collections on the client side on mobile devices.

Has anybody experienced something similar? Any ideas or suggestions would be appreciated.

1 Like

do you have some reproducible example? is it hapenening in a hello world cordova app?

I’ll see what I can do about reproducing it.

However, it’s definitely the case that Cordova builds are being transpiled to avoid async / promises. I checked the insert method (vs the insertAsync in the previous post) and it doesn’t have any of that weird while(1)-case stuff.

Surely modern Cordova builds should be able to use async code by now? I wonder if raising the minimum iOS or Android version will switch it over to native async.

If so, then the problem is solved since the bug can’t happen when using the for-of loop.

2 Likes

I think it might be Meteor doing the transpiling.

I found a reference to “@babel/plugin-transform-async-to-generator” in meteor/npm-packages/babel-preset-meteor/package.json

Does anyone know how to tweak these settings for Cordova builds?

2 Likes

With some LLM help, I figured out that adding

if (arch === "web.cordova")
      features.modernBrowsers = true;

to packages/babel-compiler/babel-compiler.js stops Meteor from polyfilling the asyncs for Cordova. This is probably something that should be changed for everyone - I’ll submit a pull request.

However, this didn’t solve my problem :confused:

I thought about it a bit more. I pretty sure it’s a Meteor bug: the for-of loop iterates a static list (Object.keys(this.queries)), but in the body of the loop keys can be removed from this.queries directly or elsewhere (when the code pauses due to await), so trying to lookup a key from the static list can give you an undefined

This will probably fix the problem:

if (!query || query.dirty) {
  continue;
}

I think I’ll submit an issue on Github for this. I’ll link it here.

1 Like

Furthermore, I suspect calls to insertAsync in packages/minimongo/local_collection.js should be queued. Otherwise multiple invocations can trip over each other by modifying this.queries

1 Like

I created an issue for this: insertAsync in Minimongo local_collection.js is buggy · Issue #13864 · meteor/meteor · GitHub

1 Like

status report: discussion moved to github