mobxjs / serializr

Serialize and deserialize complex object graphs to and from JSON and Javascript classes
MIT License
766 stars 52 forks source link

Importing from barrel index.ts causes "No modelSchema" error when using decorators #134

Closed cervengoc closed 4 years ago

cervengoc commented 4 years ago

Hi,

We are structuring our react-native application into view models and views, separating view models into directories based on features. In each directory we are using a barrel index.ts file which re-exports all the stuff from each file.

Consider the following example, given that the alias @app is configured to point to src/

src/viewmodels/parent-child/Parent.ts

import { Child } from "@app/viewmodels/parent-child"

export class Parent {
  @serializable
  name: string = "";

  @serializable(list(object(Child))
  children: Child[] = [];
}
src/viewmodels/parent-child/Child.ts

export class Child {
  @serializable
  age: number = 20;
}
src/viewmodels/parent-child/index.ts

export * from "./Parent";
export * from "./Child";

Now when we try to run this code, serializr throws a No modelSchema error pointing to the call to object(Child). As far as I could investigate, the issues lies in importing from barrel and not directly from Child.ts, as the barrel contains Parent.ts exports as well.

According to my best knowledge this should not cause such an issue as the real materialized import contains only { Child }. I understand that under the hood the index.ts executes as well so it may cause this.

Is this the expected behavior? If yes, what options do we have if any? We'd like to use these kind of barrels as it's kind of a best practice AFAIK.

Thank you in advance for your help.

mweststrate commented 4 years ago

You will have to make sure that your barrel file doesn't distort loading order, that is, that Child module is loaded before Parent, otherwise object(Child) will execute with an undefined Child. See https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de on how you can control loading order in javascript

On Wed, Jul 22, 2020 at 12:33 PM Zoltán Tamási notifications@github.com wrote:

Hi,

We are structuring our react-native application into view models and views, separating view models into directories based on features. In each directory we are using a barrel index.ts file which re-exports all the stuff from each file.

Consider the following example.

src/viewmodels/parent-child/Parent.ts

import { Child } from "@app/viewmodels/parent-child"

export class Parent { @serializable name: string = "";

@serializable(list(object(Child)) children: Child[] = []; }

src/viewmodels/parent-child/Child.ts

export class Child { @serializable age: number = 20; }

src/viewmodels/parent-child/index.ts

export from "./Parent"; export from "./Child";

Now when we try to run this code, serializr throws a No modelSchema error pointing to the call to object(Child). As far as I could investigate, the issues lies in importing from barrel and not directly from Child.ts, as the barrel contains Parent.ts exports as well.

According to my best knowledge this should not cause such an issue as the real materialized import contains only { Child }. I understand that under the hood the index.ts executes as well so it may cause this.

Is this the expected behavior? If yes, what options do we have if any? We'd like to use these kind of barrels as it's kind of a best practice AFAIK.

Thank you in advance for your help.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mobxjs/serializr/issues/134, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAN4NBDACKJJX54MITPVJUDR43E67ANCNFSM4PETSFBQ .

cervengoc commented 4 years ago

Hi @mweststrate, thank you for your quick reply.

That's a good article, thanks for sharing it. The problem at us lies in auto-generating these barrels with barrelsby. Currently barrelsby does not take dependency graph into account when generating barrels.

We came to the conclusion that within the same layer (service, view model, view) we'll use relative imports when we can, and across layers we'll use barrels. This way we'll have the appropriate control within a layer and still have nice imports between each layers.