Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting loose: false on @babel/plugin-proposal-class-properties breaks fast refresh on React Native #3102

Closed
mrVito opened this issue Sep 4, 2021 · 8 comments

Comments

@mrVito
Copy link

mrVito commented Sep 4, 2021

I'm using React Native 0.65.1 with TypeScript and Decorators for mobx and was following the official guide for enabling decorators.

The guide states that the Babel plugin @babel/plugin-proposal-class-properties must be installed and enabled in babel.config.js like so:

['@babel/plugin-proposal-class-properties', {loose: false}],
// In contrast to MobX 4/5, "loose" must be false!    ^

But doing that breaks the fast refresh on React Native.

Intended outcome:

React Native fast refresh should work as intended.

Actual outcome:

React Native fast refresh does not work at all.
Interesting part here is that setting loose: true on @babel/plugin-proposal-class-properties fixes the fast refresh and most importantly mobx still works just fine. Furthermore removing the @babel/plugin-proposal-class-properties entirely has the same effect - fast refresh works fine and mobx works just fine as well.

My tsconfig.json file looks like this:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "commonjs",
    "lib": ["ESNext"],
    "allowJs": true,
    "jsx": "react-native",
    "noEmit": true,
    "isolatedModules": true,
    "strict": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "skipLibCheck": false,
    "resolveJsonModule": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "useDefineForClassFields": true
  },
  "exclude": [
    "node_modules", "babel.config.js", "metro.config.js", "jest.config.js"
  ]
}

How to reproduce the issue:

  • Create new React Native project via React Native CLI with typescript template: npx react-native init AwesomeTSProject --template react-native-template-typescript;
  • Install mobx and mobx-react;
  • Set "experimentalDecorators": true, and "useDefineForClassFields": true in tsconfig.json file;
  • Add plugins to babel.config.js:
  plugins: [
    ['@babel/plugin-proposal-decorators', {legacy: true}],
    ['@babel/plugin-proposal-class-properties', {loose: false}],
  ],
  • Launch the app in emulator;
  • Touch some ts/tsx files on the project and confirm that fast refresh does not work.

Versions

mobx: 6.3.3
mobx-react: 7.2.0
react: 17.0.2
react-native: 0.65.1
typescript: 3.8.3

Additional notes
I'm confused why mobx decorator documentation requires @babel/plugin-proposal-class-properties to have loose set to false but setting loose to true or entirely removing @babel/plugin-proposal-class-properties doesn't break mobx. Am I missing something here? If loose: false is truly required maybe I have not encountered something that setting it to true breaks?

@mrVito mrVito added the 🐛 bug label Sep 4, 2021
@iChenLei
Copy link
Member

iChenLei commented Sep 4, 2021

I think this issue same with #3100

@urugator
Copy link
Collaborator

urugator commented Sep 4, 2021

I don't think there is much we can do about this.
This plugin/configuration forces class fields being transpiled in a way that's compatible with the standard and it's existing implementation in modern engines. Meaning if you wouldn't transpile your code and you would run it on a modern browser that supports class fields, it would behave the same way as transpiled with this plugin and this configuration.
It's not some kind of mobx quirk. The plugin is a default part of a newer @babel/preset-env (ES2022+) and the loose: false is also already a default - it's kept in the documentation just in case you're using older babel.

doesn't break mobx.

It may, it may not. The implementation assumes that class fields work as defined by ECMAScript standard.
You can try to run tests with loose: true ("useDefineForClassFields": false), but even if passing, there is no guarantee it won't break eventually.

@jeremy-coleman
Copy link
Contributor

It might be from having emit decorator metadata turned on. For whatever reason, that breaks stuff with mobx sometimes . Never have bothered looking into it, but im positive it can cause issues.

@enniel
Copy link

enniel commented Nov 7, 2021

Maybe this solution #3100 (comment) helps you

@stale
Copy link

stale bot commented Jan 8, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the 🚶 stale label Jan 8, 2022
@stale stale bot closed this as completed Apr 16, 2022
guyca added a commit to guyca/Emojiz that referenced this issue Apr 17, 2022
@Kawaljeet-AUI
Copy link

Dropping this here just in case you're using Nx, this is the babel config that worked for me:

  "presets": ["module:metro-react-native-babel-preset"],
  "plugins": [
    ["react-native-reanimated/plugin"],
    ["@babel/plugin-proposal-private-methods", { "loose": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    ["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
  ]
}

babel version: 7.18.6

@mattpatterson94
Copy link

mattpatterson94 commented Sep 8, 2023

@Kawaljeet-AUI I found by adding @babel/plugin-transform-flow-strip-types I can keep false as false and it works as expected.

@guy-shahine
Copy link

guy-shahine commented May 13, 2024

In my case, React Native FlatList was breaking with an error undefined is not an object (evaluating 'props.getItem')

Here's the babel config that worked

overrides: [
    {
      test: (fileName) => !fileName.includes("node_modules"),
      plugins: [
        ["@babel/plugin-proposal-decorators", { legacy: true }],
        ["@babel/plugin-proposal-class-properties"],
        ["@babel/plugin-proposal-private-property-in-object", { loose: false }],
        ["@babel/plugin-proposal-private-methods", { loose: false }],
        ["@babel/plugin-transform-flow-strip-types"], // prevent compile
      ],
    },
  ],
  assumptions: {
    setPublicClassFields: false,
  },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants