rescript-stdlib-cli v0.3.2
The ultimate answer to Belt vs Js in ReScript
Probably every developer that comes to ReScript stumbles upon a dilemma about which module from the standard library they should use to work with JavaScript API.
- Should I take the Js module with a familiar design for JavaScript developers and runtime-free bindings? 🧐
- Or should I take the more powerful Belt? 🤔
- Wait, I heard something about rescript-js! Maybe it’s what I need? 😅
Those are pretty familiar thoughts, right? I’ve seen a lot of discussions about which one you should use, but there were never solid answers, and the result was either “it depends” or “I personally like one over another because of X”.
My lovely Carla colleague Daggala has written a very detailed article about the problem, so I won’t repeat her and continue.
Problem 2: Multiple sources of truth
No matter what we choose, sometimes we still need to use another module. It’s because some functions which exist in Js
don’t exist in Belt
and vise-versa.
But it might happen that a function doesn’t exist in both of the modules, eg infamous padStart. At Carla, we used to solve the problem by creating a lot of StringExtra
, OptionExtra
, and WhateverExtra
modules to add missing helper functions.
This leads to another problem when developers don’t know where they can find the desired helper:
- Will it be in
Belt
that we agreed to use as default, or the helper doesn’t exist there, and I should useJs
instead, or maybeStringExtra
?
A few times, we even end up using Pervasives
by mistake.
Solution
I will not create intrigue and say that the solution is to group everything in a vendored standard library and enforce its usage across the codebase. Opening an opportunity to reuse any existing module like Js
, Belt
, or RescriptJs
; and extend them for project-specific needs.
The enforcing part is even more crucial because if we don't have it automated, developers will continue using all different modules instead of the single Stdlib.res
we vendored.
I've created a CLI that anyone can easily use to achieve these two parts. For now, it only has the lint
command, but I'm going to add init
and migrate
for easier adoption.
Create vendored standard library
TBD. You can use the CLI library repository as a reference.
Linting
The linting script I've mentioned above does a straightforward thing - It checks all project files and detects the usage of prohibited modules.
By default, prohibited modules are Js
, Belt
, and ReScriptJs
. In future versions, the linter will also complain on private modules like Js_Dict
, including the ones prefixed with Stdlib_
.
Opening a prohibited module with a bs-flag
will also cause an error.
To start using the linter in your project, install rescript-stdlib-cli
as a dev dependency. Let's also add an npm run script for convenience.
npm install -D rescript-stdlib-cli
npm pkg set scripts.lint:stdlib="rescript-stdlib-cli lint"
As a result, we should get a package.json
like this:
{
"name": "your-awesome-project",
"scripts": {
+ "lint:stdlib": "rescript-stdlib-cli lint"
},
"dependencies": {
"stdlib": "file:stdlib"
},
"devDependencies": {
+ "rescript-stdlib-cli": "*"
}
}
The only thing is left to run:
npm run lint:stdlib
Migration guide
TBD. Here I'll describe how to migrate a big codebase to the desired solution painlessly.