What's the easiest way to enable React fast-refresh with uppercase component names?

I’m struggling to get React fast-refresh to work with Vite nicely. The issue seems to come down to fast-refresh requiring compnent names to be capitalized as discussed here.

I couldn’t figure out any clean way to output JS that has the component name capitalized. The component decorator outputs the component this way:

// App.res
@react.component
let make = () => { ...

// generated App.mjs
var make = App;

export {
  make ,
  
}

Then this is imported in the generated parent JS as

import * as App from "./App.mjs";
...
ReactDom.render(React.createElement(App.make, {}), root);

fast-refresh (at least with vite and @vitejs/plugin-react) won’t recognize this as a React component since the component name is essentially make so any change to code will trigger a full page reload.

Just for testing purposes, manually renaming make to Make in the generated JS will indeed enable fast-refresh.

So my question is, is there a simple way to generate upper case components in JS or is there another workaround for this?

Using modules seems to be one way, i.e. defining the React component as

module Component = {
  @react.component
  let make = () => {

Then of course you need to use the submodule name everytime you use the component:

ReactDOM.render(<App.Component />, root)

The other way seems to be importing the component into a JS file and then re-exporting as default, like it’s done in the nextjs template. However, based on my testing this is not viable for nested React components since you would always need the JS file for every child component.

Anything I’m misunderstanding here? Using submodules is the best solution I could think of.

Hi @tomjon how did you go with this?

Another possible solution would be to export default from your module. E.g.

let make = () => {React.string("Hello")}
let default = make

Then perhaps you can import as:

import App from "./App.mjs";

Would that work?

Also, if the component is being consumed by JS and not ReScript, then I believe you can remove the @react.component decorator.

Fast Refresh requires the function name to be defined (no anonymous functions), and it must be pascal cased.

It seems component naming is no longer an issue with Rescript and Fast Refresh, but the Rescript compiler would re-compile all files and this triggers a hot reload for all files, including non component files which will always force a full reload with Fast Refresh.

UPDATE: Managed to fix the issue. Warnings (in this case unused variable warning) caused the Rescript file to be re-saved or something (triggering a React Refresh reload).

1 Like