rescript-lang / rescript-compiler

The compiler for ReScript.
https://rescript-lang.org
Other
6.65k stars 442 forks source link

Support react-native platform-specific extension #1436

Open saschatimme opened 7 years ago

saschatimme commented 7 years ago

From the react-native docs:

For example, say you have the following files in your project:

BigButton.ios.js BigButton.android.js You can then require the component as follows:

const BigButton = require('./BigButton');

This works since react-native ships a custom javascript bundler by default.

It would be good to have the possibility to generate such file names with bucklescript. Probably some sort of name mangling would be necessary.

bobzhang commented 7 years ago

how is it different from ButtonIos ad ButtonAndroid?

saschatimme commented 7 years ago

The React Native packager (now extracted as metro-bundler) has as a hardcoded resolution rule to check for the name[.platform].js pattern: https://github.com/facebook/metro-bundler/blob/74e78ee43f73d0452dcce0db0887f055cf7abbee/packages/metro-bundler/src/node-haste/lib/parsePlatformFilePath.js#L30

rafayepes commented 7 years ago

how is it different from ButtonIos ad ButtonAndroid?

It only bundles the one that matches your platform. It can be achieved for react-native-web with webpack as well. It a common system in the RN ecosystem to to build platform-specfic components.

So the alternative I guess that would be to add static-if's that open the right module based on platform. But will be something very manual and cumbersome.

bobzhang commented 6 years ago

How do you achieve that producing Button.ios.js and Button.android.js at the same time?

MoOx commented 6 years ago

I am facing the same issue. It's even blocking me with .web.js (RNW + webpack resolve option)

(eg https://github.com/facebookincubator/create-react-app/blob/a1c5b8f7054ac0ac708a498c2a6308f3ed1cb8f0/packages/react-scripts/config/webpack.config.dev.js#L93)

I saw that BS accept a option "suffix": ".whatever.js" to generate but that's clearly not possible if you have to deal with several suffix at the same time. I would like to have a single command that could compile my File.js and my File.platform.js to 2 files, not one (because as I am writing it's compiling each file, but is writting those at the same place).

MoOx commented 6 years ago

Just an idea (I have in my case used a workaround using some webpack config since I have an issue with .web.js): using Platform.select might help to require the right file. See https://facebook.github.io/react-native/docs/next/platform-specific-code.html#docsNav for more info (Platform is available via bs-react-native)

MoOx commented 5 years ago

How do you achieve that producing Button.ios.js and Button.android.js at the same time?

Currently we have the following behavior

@bobzhang How I see it what should happen is the following

Maybe it's not the ultimate solution, but at least we are not completely dropping everything after the first dot, ignoring silently the first intention. At least if the solution needs more reflexion, we could throw an error if there is multiple dots in the filename?

vknez commented 4 years ago

I am experiencing similar challenges, and @MoOx's suggestions would help.

I have a TypeScript + ReasonML React Native app that is compiled for 3 platforms: iOS, Android, and web. Quite often I need to make a distinction whether I'm requiring a component on web or native, and before introducing ReasonML I had the following approach (pretty common in React Native):

I create two platform-specific files: MyComponent.native.tsx and MyComponent.web.tsx (native could be further split into ios|android). Then from the index.ts I do import { MyComponent} from "./MyComponent";. React Native correctly chooses which file to use for the import.

My current alternative is to use JS (TS) wrapper components (with names mentioned above) on top of Reason files (MyComponentNative.re, MyComponentWeb.re), in order to be able to use those platform-specific extensions and import the specific bs.js component. This is not a big deal if those components are used only from the JavaScript world, but I need them in Reason as well (eg. a component that is the same on all platforms, but uses MyComponent).

MoOx commented 4 years ago

Reminder for those looking for this, best quick workaround

Since reason-react 0.7 & zero cost bindings, the import/export step is not painful.

But an official solution would be nice, but that could involve validating interfaces or all Thing.*.re & I understand that this requires work.

ryyppy commented 3 years ago

I think this is fixed now. Closed.

MoOx commented 3 years ago

How is interpreted the suffix? I mean can we have 2 modules with the same interface? What js filename will have Module.ios.res & Module.android.res? Is this working if we want to use <Module /> ?

ryyppy commented 3 years ago

@MoOx right now you can...

editor-support extracts the module name Foo.ios and Foo.android, so you can't really access those modules in other modules. You'd need to create a FooCommon or something

Should I reopen the issue?

MoOx commented 3 years ago

Yes because currently React Native allows different implementation of a same component for different platform (I mentioned iOS and Android but it can be web, Windows, macOS...). Components should have a similar interfaces. I said "React Native" but actually it's more a bundler specificity ((metro (iOS/android/etc)+webpack(for the web))) that allow to ask "build this as {platform}" so {platform} will be used. For ReScript to allow generated Module.{platform}.js files (I guess {platform}.bs.js is acceptable as Metro (via sourceExts) and wepack can handle extensions tweaks) it means someone that we should be have a validation between 2 modules that have similar names in addition to accepting Module as name to be able to resolve it from other modules. This might means like Metro and webpack, we should have a least (in addition to modification of rescript itself) a new option to whitelist accepted {platform} (otherwise every whatever.suffix.js will be assumed to be a module that need to have {suffix} as a platform if you see what I mean. That is probably something that rescript doesn't do at all yet so it might need somehow dedicated development if this is something accepted.

In short what should be done:

Note: Maybe there is already something similar that check if .resi matches .res - for this I guess it's the compiler and not the syntax layer that handle this, so OCaml itself?

stale[bot] commented 1 year ago

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.

Freddy03h commented 1 year ago

😞

fhammerschmidt commented 1 year ago

Yes, this is still an issue and should be reopened IMO. Except if we really won't fix it which I do not hope for.

cc @cristianoc @ryyppy @cknitt

Freddy03h commented 1 year ago

@fhammerschmidt thank you!

The issue was very well explained by @MoOx, for now it's still unusable…