rescript-lang / bucklescript.github.io

BuckleScript's documentation site
https://bucklescript.github.io
55 stars 87 forks source link

Incorrect advice for ES6 default value import? #46

Open martinraison opened 6 years ago

martinraison commented 6 years ago

Hi, I just hit the error documented here: https://bucklescript.github.io/docs/en/import-export.html#import-an-es6-default-value. I was trying to import this: https://github.com/chenglou/react-spinner

I tried the suggested fix:

[@bs.module "react-spinner"] external spinner : ReasonReact.reactClass = "default";

However it didn't work for me, I kept getting the same error. What worked in the end was this:

[@bs.module] external spinner : ReasonReact.reactClass = "react-spinner";

I suspect (but I'm not sure) this is because the exported value is a class? If we can identify the cause of the problem we can update the documentation.

chenglou commented 6 years ago

Hey! See the message in the doc. Is your project using true es6 or simulated es6 through webpack/babel? The advice only applies to the latter

martinraison commented 6 years ago

Hi, I generated the project with https://github.com/reasonml-community/reason-scripts. That should be simulated es6, right?

chenglou commented 6 years ago

cc @rrdelaney ^ does reason-script/cra detect es6 support and use the real one?

rrdelaney commented 6 years ago

It looks like reason-scripts uses webpack 3, which I think supports native ES Modules. Is the library published as ES6 on npm though? From what I can tell react-spinner uses a UMD setup, so it should be able to be required using either of the above methods.

Angry-Potato commented 6 years ago

@chenglou @rrdelaney I ran into something similar when trying to bind react-native-splash-screen.

In my .js component this is easy:

import SplashScreen from 'react-native-splash-screen';
...
  componentDidMount() {
    SplashScreen.hide();
  }

I tried writing the equivalent in my Reason component (after reading the docs):

[@bs.module "react-native-splash-screen"] 
external hide : unit => unit = "hide";
...
    didMount: _self => hide(),

This transpiles to:

var ReactNativeSplashScreen = require("react-native-splash-screen");
ReactNativeSplashScreen.hide();

Which should work BUT react-native-splash-screen exports default meaning the above hide is actually undefined. If it transpiled to ReactNativeSplashScreen.default.hide() it works fine.

I tried to Reason my way through this with:

type splash = {hide: unit => unit};

[@bs.module "react-native-splash-screen"]
external splashScreen : splash = "default";
...
    didMount: _self => splashScreen.hide(),

but that transpiles to:

var ReactNativeSplashScreen = require("react-native-splash-screen");
...
          /* didMount */(function () {
              return Curry._1(ReactNativeSplashScreen.default[/* hide */0], /* () */0);
            })

which crashes complaining about undefined at 0.

I hassled the people on the Reason discord, they provided me with this solution:

[@bs.module "react-native-splash-screen"] [@bs.scope "default"]
external hide : unit => unit = "hide";
...
hide();

Which totally works!

Maybe this will help you too? I think it should be added to the docs but unsure if the proper place is in the Reason docs or the BuckleScript docs..