Initial context: converting the base CRA template from JS -> ReScript.
I’m trying to get the CRA hot reload to work with ReScript. Unfortunately it breaks when I extract an “external module” declaration from raw JavaScript.
The initial “Pseudo-port” of the .js files to .res files works fine, and the auto-reload continues to work fine. Once I extract an external module, however, it breaks.
This works:
%%raw(`import logo from './logo.svg';`)
This breaks auto-reload (though works with manual reload):
Note that the client still seems to detect “a change” and you see a network request on save, but the page itself does not change until you do a full reload on the page.
Any ideas and/or thoughts on how to proceed?
Thank you in advance,
Wil
P.S. For additional context, I’m following along with the following blog post:
What bs-platform version? And I assume you’re outputting to ES6? See [this page]. Generally speaking, have your js output open side by side and nudge your externals into whatever output you’d like to see.
I can’t help, but I can say I wrote the article and haven’t had any trouble with it. My first guess is that there is a race condition if cra reloads when it sees a file change before rescript has finished compiling. My machine is highly spec’d and rescript might be fast enough to beat cra for me. Another possibility is that rescript is not changing the output js file, so cra has nothing to reload. Checking what is happening in the compiled js output might help narrow it down.
Sorry for the delayed response. Per my yarn.lock file this is bs-platform@9.0.2.
I have since moved on, and while I no longer have simple replication instructions, I do regularly see a similar issue. What I do to “fix” the problem is close all .res files, manually delete the .bsb.lock file, and then re-open a .res file. I then get prompted to start a build and things work swimmingly, usually for the duration of my VS Code session. This is a pretty regular issue when I start VS Code however. Perhaps the .bsb.lock file is not being cleaned up when VS Code closes?
It would be nice if the VS Code extension had a command that simulated that and essentially forced a restart/rebuild of the internal state. Does one exist already perhaps?
I’m also having an issue with ReScript generated files hot reloading in a CRA app.
Even broke it down to a very minimal example:
Here is Example.tsx and in it is the following:
function Example () {
console.log("Example re-render")
return <div>Hello World. Update? 3</div>
}
export default Example
An adjacent ReScript file for testing purposes:
@genType @react.compoent
let make = () => {
Js.Console.log("Greeting Re-render")
<div> {"Hello from ReScript."->React.string} </div>
}
@genType
let greeting = make
@genType let default = greeting
Finally my index.tsx:
// import App from "./App.bs";
import ReactDOM from "react-dom";
import React from "react";
import reportWebVitals from "./reportWebVitals";
import Example from './Example';
import Greeting from './Greeting.gen';
ReactDOM.render(<React.StrictMode><Example /> <Greeting /></React.StrictMode>, document.getElementById("root"))
reportWebVitals();
Reproduction
Refresh the browser
Edit Example.tsx and change the message, then save the file
It reloads as expected
Edit the Greeting.res and change the message, then save the edits
It does not reload, a message is received by the websocket listener but nothing beyond that.
Try to edit the message of Example.tsx and then save the file
It does not reload. Once I update my Greeting.res file and make changes to Example.tsx it stops reloading.
If I refresh the browser, I can make any number of changes to Example.tsx and it consistently reloads until I edit Greeting.res.
Turned out to be that in this case, though I am still having issues with the actual project I’m working on so maybe I’ve got similar typos somewhere along the way?
If it’s messed up somewhere and it tries to hot reload, it will break all other reloads for previously working component updates.
Just lost half the day trying to track it down, fortunately I did find out the cause and a workaround.
The problem is caused by the resulting JS exports:
// make is your react component
var x = 5; // minimal example but in your reproduction repo it would be the logo external binding
export {
make,
x
}
For some reason when there is more than one export, CRA cannot hot reload changes to that component. The same happens if using export const
I found a workaround but it’s not ideal long-term. Create a .resi file to ensure only the make function is exported:
Create an App.resi
let make: {.} => React.element
I don’t like this as I already have many React components, and I’ll have to edit these files anytime a prop changes if I decide hot-reloading is worth it.
I guess you are breaking the rules of “Fast Refresh” which state that a module should only export React components, otherwise the mechanism cannot reliably refresh.
Unfortunately this is not a bug and we need to hide all the exports that are not React components by using an interface file. Or you hide other stuff with the %%private extension, which is pretty adhoc.
Is there a way to use %%private to hide an external that is imported? That was the reason I encountered this issue:
@module(“./App.module.scss”) external styles: {..} = “default”;
@react.component
let make = () => {
<div className={styles[“root”]}>
I don’t really want to expose styles here
</div>
}
Just doing that already creates two exports and breaks hot reloading.
%%private(@module("./App.module.scss") external styles: {..} = "default")
@react.component
let make = () => {
<div className={styles["root"]}>
{React.string("I don’t really want to expose styles here")}
</div>
}
JS Output:
var React = require("react");
var AppModuleScss = require("./App.module.scss").default;
var styles = AppModuleScss;
function Playground(Props) {
return React.createElement("div", {
className: styles.root
}, "I don\xe2\x80\x99t really want to expose styles here");
}
var make = Playground;
exports.make = make;
The repo I’m working on is using 9.0.2. The Playground has 9.1.2, but seems to still work when dropping it back to 9.0.2 so perhaps this is a special case by the Playground? Is there a workaround this to get it compiling through the CLI?
Edit: This was one of the first solutions I tried before posting:
Nevermind. I got it working! The original reproduction repo was using the bsb command and the bs-platform, where now we should be using the rescript package. Once I switched to rescript@9.1.3 that syntax compiled just fine!