https://github.com/bloodyowl/rescript-react-starter-kit
An opinionated starter kit for ReScript React
https://github.com/bloodyowl/rescript-react-starter-kit
react rescript
Last synced: 12 months ago
JSON representation
An opinionated starter kit for ReScript React
- Host: GitHub
- URL: https://github.com/bloodyowl/rescript-react-starter-kit
- Owner: bloodyowl
- License: mit
- Created: 2021-02-27T22:45:35.000Z (about 5 years ago)
- Default Branch: main
- Last Pushed: 2021-06-19T11:27:46.000Z (over 4 years ago)
- Last Synced: 2025-03-18T10:21:18.674Z (12 months ago)
- Topics: react, rescript
- Language: ReScript
- Homepage: https://bloodyowl.github.io/rescript-react-starter-kit/
- Size: 1.98 MB
- Stars: 57
- Watchers: 3
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: HISTORY.md
- Funding: .github/FUNDING.yml
- License: MIT-LICENSE
Awesome Lists containing this project
- awesome-list - rescript-react-starter-kit
README
# ReScript React Starter Kit
> An opinionated starter kit for ReScript React

## What's inside
### Familiar standard library
The configuration automatically gives you [Belt](https://rescript-lang.org/docs/manual/latest/api/belt) and [ReScriptJs.Js](https://github.com/bloodyowl/rescript-js) in scope.
This makes your code always default to JavaScript APIs if available, while giving you good manipulation functions for ReScript-specific types (like `Option` & `Result`)
This means that by default, the following code:
```rescript
let x = [1, 2, 3]
->Array.map(x => x * 2)
->Array.forEach(Console.log)
```
will compile to the following JS (no additional runtime cost!):
```js
[1, 2, 3]
.map(function (x) {
return x << 1;
})
.forEach(function (prim) {
console.log(prim);
});
```
If you need a specific data-structure from Belt, you can prefix with `Belt`'s scope:
```rescript
let x = Belt.Map.String.fromArray([("a", 1), ("b", 2)])
```
### Ready-to-go requests
This starter kit gives you three building blocks to handle API calls from the get go.
#### AsyncData
[AsyncData](https://github.com/bloodyowl/rescript-asyncdata) is a great way to represent asynchronous data in React component state. It's a variant type that can be either `NotAsked`, `Loading` or `Done(payload)`, leaving no room for the errors you get when managing those in different state cells.
#### Future
Promises don't play really well with React's effect cancellation model, [Future](https://github.com/bloodyowl/rescript-future) gives you a performant equivalent that has built-in cancellation and leaves error management to the [Result](https://rescript-lang.org/docs/manual/latest/api/belt/result) type.
#### Request
[Request](https://github.com/bloodyowl/rescript-request) gives you a simple API to perform API calls in a way that's easy to store in React component state.
### Dev server
Once your project grows, having the compiler output files and webpack watching it can lead to long waiting times. Here, the development server waits for BuckleScript to be ready before it triggers a compilation.
The dev server supports basic **live reload**.
### Testing library
With [ReScriptTest](https://github.com/bloodyowl/rescript-test), you get a light testing framework that plays nicely with React & lets you mock HTTP call responses.
The assertion part is on your side, the library simply runs and renders the tests.
```rescript
open ReactTest
testWithReact("Robots renders", container => {
let (future, resolve) = Deferred.make()
let fetchRobotsTxt = () => future
act(() => ReactDOM.render(, container))
Assert.elementContains(container, "Loading")
act(() => resolve(Ok({ok: true, status: 200, response: Some("My mock response")})))
Assert.elementContains(container, "My mock response")
})
```
Check the example output in [this repo's GitHub Actions](https://github.com/bloodyowl/rescript-react-starter-kit/actions)
### Styling with Emotion
With [some zero-cost bindings to Emotion](https://github.com/bloodyowl/rescript-react-starter-kit/blob/main/src/shared/Emotion.res), you get CSS-in-ReScript right away.
```rescript
module Styles = {
open Emotion
let actionButton = css({
"borderStyle": "none",
"background": "hotpink",
"fontFamily": "inherit",
"color": "#fff",
"fontSize": 20,
"padding": 10,
"cursor": "pointer",
"borderRadius": 10,
"alignSelf": "center",
})
let disabledButton = cx([actionButton, css({"opacity": "0.3"})])
}
```
## Routing
Provide a `PUBLIC_PATH` environment variable (defaults to `/`), the boilerplate takes care of the rest. Manage your routing using the `Router` & `` modules.
## Titles & metadata
Call `