realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.78k stars 574 forks source link

Electron Issue: Class Integration Not Working with Vite #4184

Open sama12386 opened 2 years ago

sama12386 commented 2 years ago

How frequently does the bug occur?

All the time

Description

When using Vite with Electron as discussed in #4175, Realm does not integrate with TypeScript classes when passed in as object definitions.

If I pass in a class object into the schema property of a Realm.Configuration object, I would expect that the Realm.Result of a query against that collection would return a list of that object type, allowing the use of instance methods of that class.

Given the following class:

//Dog.ts
import * as Realm from 'realm';

export default class Dog extends Realm.Object {

  _id!: Realm.BSON.ObjectId;
  _name!: string;

  // Use a generate function instead of a constructor to avoid problems stemming from extending Realm.Object
  static generate(name: string) {
    return {
      _id: new Realm.BSON.ObjectId(),
      _name: name,
    };
  }

  // To use a class as a Realm object type, define the object schema on the static property "schema".
  static schema = {
    name: 'Dog',
    primaryKey: '_id',
    properties: {
      _id: 'objectId',
      _name: 'string',
    },
  };

  getNameAllUppercase() {
    return this._name.toUpperCase();
  }
}

If I run the following (and there's at least one Dog), I should get an instance of Dog:

const firstDog = realm.objects(Dog)[0];

Instead, I get {_id: undefined, _name: undefined, Symbol(_external): {…}}

Stacktrace & log output

If I instead pass in [Dog.schema] into the Realm.Configuration object, the following error is thrown when trying to get the Dog collection:

runtime-core.esm-bundler.js:6800 Uncaught Error: Constructor was not registered in the schema for this Realm
    at Proxy.logFirstDog (RealmView.vue:34)
    at _createElementVNode.onClick._cache.<computed>._cache.<computed> (RealmView.vue:7)
    at callWithErrorHandling (runtime-core.esm-bundler.js:6737)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:6746)
    at HTMLButtonElement.invoker (runtime-dom.esm-bundler.js:357)

Can you reproduce the bug?

Yes, always

Reproduction Steps

Please let me know if you need anything else. Thank you!

Version

10.10.1

What SDK flavour are you using?

MongoDB Realm (i.e. Sync, auth, functions)

Are you using encryption?

No, not using encryption

Platform OS and version(s)

macOS & Windows

Build environment

No response

kraenhansen commented 2 years ago

First of all. Thanks a lot for the reproduction!

I see you're getting an error message (Constructor was not registered in the schema for this Realm) from within the lib/browser part of our codebase. This part of the codebase is intended for consumption only via the legacy React Native chrome debugger, which explains that you're not able to read properties off the objects.

I don't know exactly why this is happening, but I suspect that because of contextIsolation our code inferring the environment skips over electron and falls back to this path of the code: https://github.com/realm/realm-js/blob/master/lib/utils.js#L126-L131

I suspect that you need to externalize the realm package to get it working with Vite, but I havn't (yet) been able to confirm this as a solution:

  1. Either via the Rollup externals https://rollupjs.org/guide/en/#external set via https://vitejs.dev/config/#build-rollupoptions
  2. Or perhaps via https://vitejs.dev/config/#optimizedeps-exclude

I'll try to experiment a bit more, but I think it's safe to say that we're generally not playing nicely in a project with bundlers.

sama12386 commented 2 years ago

@kraenhansen I wanted to drop by this issue again and see if there's been any movement on this issue, or on getting Realm to work with bundlers. Thank you!