Hey! I’m not using the plugin, but happy to share our set-up as comparison which just calls ReScript and then Vite.
Going to be a bit rude and just paste some code here since this isn’t in a public repo, sorry.
Package.json
We use nodemon for automatic reloading of changed server code. Vite builds a client bundle and a server bundle for SSR. The app also uses ReScript Relay though I’ve removed that from the examples here. It’s mostly and extra build and dev script. We use npm-run-all to run scripts serially or in parallel (that library is named npm but works with yarn too which we use).
Of note is type: module to make things work with mjs files.
{
"name": "my-app",
"version": "0.1.0",
"type": "module",
"scripts": {
"postinstall": "rescript clean",
"build": "cross-env NODE_ENV=production run-s build:*",
"build:rescript": "rescript build",
"build:vite": "run-s build:vite:*",
"build:vite:client": "vite build --outDir dist/client --ssrManifest --manifest",
"build:vite:server": "vite build --outDir dist/server --ssr src/entry.server.mjs",
"start": "cross-env NODE_ENV=production node -r dotenv-expand/config Server.mjs",
"dev": "run-s build:rescript && run-p dev:*",
"dev:rescript": "rescript build -w",
"dev:vite": "nodemon -r dotenv-expand/config -w Server.mjs -w .env Server.mjs"
},
"dependencies": {
"@rescript/react": "^0.10.3",
"@ryyppy/rescript-promise": "^2.1.0",
"cross-env": "^7.0.3",
"dotenv": "^16.0.1",
"dotenv-expand": "^8.0.3",
"express": "^4.17.3",
"node-fetch": "^3.2.4",
"patch-package": "^6.4.7",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"rescript": "^9.1.4",
"rescript-webapi": "^0.6.1"
},
"devDependencies": {
"@vitejs/plugin-react": "^1.3.1",
"binode": "^1.0.5",
"nodemon": "^2.0.16",
"npm-run-all": "^4.1.5",
"vite": "^2.9.5"
}
}
bsconfig.json
I think the bsconfig.json file is pretty standard. Do note we’re compiling to mjs. I’d have liked to compile to .bs.mjs to be able to differentiate between custom JS modules and ones that are generated by ReScript. Unfortunately the compiler has extensions as enum and not free-form string.
{
"name": "my-app",
"namespace": false,
"reason": { "react-jsx": 3 },
"refmt": 3,
"bs-dependencies": [
"@rescript/react",
"rescript-webapi",
"@ryyppy/rescript-promise"
],
"ppx-flags": [],
"sources": [
{ "dir": "src", "subdirs": true },
{ "dir": ".", "files": ["Server.res"] }
],
"package-specs": {
"module": "es6",
"in-source": true
},
"suffix": ".mjs",
"warnings": {
"number": "-3",
"error": "+101+8"
}
}
vite.config.js
To make things work here I had to change the rollup and esbuild output to also be es6. I believe this was specifically needed to make Node.js happy. The client doesn’t care, but there was an unbundled file (Server.res) which was invoked by Node.js directly, compiled by ReScript, which would then try to import CJS files, which broke. So making everything ESM fixed that.
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
],
build: {
target: 'esnext',
rollupOptions: {
output: {
format: "esm"
}
}
},
// Prevent ReScript messages from being lost when we run all things at the same time.
clearScreen: false,
})
Hope that helps anyone trying to get this working (perhaps you can spot the difference between this and a set-up using the ReScript plugin).