You are currently looking at the v11.0 docs, which are still a work in progress. If you miss anything, you may find it in the older v10.0 docs here.
Configuration
rescript.json
(or bsconfig.json
in versions prior ReScript 11) is the single, mandatory build meta file needed for rescript
.
The complete configuration schema is here. We'll non-exhaustively highlight the important parts in prose below.
name, namespace
name
is the name of the library, used as its "namespace". You can activate namespacing through "namespace": true
in your rescript.json
. Namespacing is almost mandatory; we haven't turned it on by default yet to preserve backward-compatibility.
Explanation: by default, your files, once used as a third-party dependency, are available globally to the consumer. E.g. if you have an Util.re
and the consumer also has a file of the same name, they will clash. Turning on namespace
avoids this by wrapping all your own project's files into an extra module layer; instead of a global Util
module, the consumer will see you as MyProject.Util
. The namespacing affects your consumers, not yourself.
Aka, in ReScript, "namespace" is just a fancy term for an auto-generated module that wraps all your project's files (efficiently and correctly, of course!) for third-party consumption.
We don't do folder-level namespacing for your own project; all your own file names must be unique. This is a constraint that enables several features such as fast search and easier project reorganization.
Note: the rescript.json
name
should be the same as the package.json
name
, to avoid confusing corner-cases. However, this means that you can't use a camelCased names such as MyProject
, since package.json
and npm forbid you to do so (some file systems are case-insensitive). To have the namespace/module as MyProject
, write "name": "my-project"
. ReScript will turn that into the camelCased name correctly.
Note on custom namespacing: if for some reason, you need a namespace that is different from what your name
will produce, you can directly send a string to the namespace
option. For example, if your package is a binding named bs-some-thing
, you can use "namespace": "some-thing"
to get SomeThing
namespace instead of BsSomeThing
.
sources
Your source files need to be specified explicitly (we don't want to accidentally drill down into some unrelated directories). Examples:
JSON{
"sources": ["src", "examples"]
}
JSON{
"sources": {
"dir": "src",
"subdirs": ["page"]
}
}
JSON{
"sources": [
"examples",
{
"dir": "src",
"subdirs": true // recursively builds every subdirectory
}
]
}
You can mark your directories as dev-only (for e.g. tests). These won't be built and exposed to third-parties, or even to other "dev" directories in the same project:
JSON{
"sources": {
"dir": "test",
"type": "dev"
}
}
You can also explicitly allow which modules can be seen from outside. This feature is especially useful for library authors who want to have a single entry point for their users.
Here, the file src/MyMainModule.res
is exposed to outside consumers, while all other files are private.
JSON{
"sources": {
"dir": "src",
"public": ["MyMainModule"]
}
}
bs-dependencies, bs-dev-dependencies
List of ReScript dependencies. Just like package.json
's dependencies, they'll be searched in node_modules
.
Note that only sources marked with "type":"dev"
will be able to resolve modules from bs-dev-dependencies
.
pinned-dependencies
Since 8.4: List of pinned dependencies. A pinned dependency will always be rebuilt whenever you build a toplevel package (e.g. your main app) with rescript
.
This is useful for working on multiple independent ReScript packages simultaneously. More usage details can be found in our dedicated pinned dependencies page.
external-stdlib
Since 9.0: This setting allows depending on an externally built stdlib package (instead of a locally built stdlib runtime). Useful for shipping packages that are only consumed in JS or TS without any dependencies to the ReScript development toolchain.
More details can be found on our external stdlib page.
js-post-build
Hook that's invoked every time a file is recompiled. Good for JS build system interop, but please use it sparingly. Calling your custom command for every recompiled file slows down your build and worsens the building experience for even third-party users of your lib.
Example:
JSON{
"js-post-build": {
"cmd": "/path/to/node ../../postProcessTheFile.js"
}
}
Note that the path resolution for the command (node
in this case) is done so:
/myCommand
is resolved into/myCommand
package/myCommand
is resolved intonode_modules/package/myCommand
./myCommand
is resolved intomyProjectRoot/myCommand
myCommand
is just called asmyCommand
, aka a globally available executable. But note that ReScript doesn't read into your shell's environment, so if you put e.g.node
, it won't find it unless you specify an absolute path. Alternatively, add#!/usr/local/bin/node
to the top of your script to directly call it without prependingnode
.
The command itself is called from inside lib/bs
.
package-specs
Output to either CommonJS (the default) or ES6 modules. Example:
JSON{
"package-specs": {
"module": "commonjs",
"in-source": true
}
}
"module": "es6-global"
resolvesnode_modules
using relative paths. Good for development-time usage of ES6 in conjunction with browsers like Safari and Firefox that support ES6 modules today. No more dev-time bundling!"in-source": true
generates output alongside source files. If you omit it, it'll generate the artifacts intolib/js
. The output directory is not configurable otherwise.
This configuration only applies to you, when you develop the project. When the project is used as a third-party library, the consumer's own rescript.json
package-specs
overrides the configuration here, logically.
suffix
Since 11.0: The suffix can now be freely chosen. However, we still suggest you stick to the convention and use one of the following:
".js
".mjs"
".cjs"
".res.js"
".res.mjs"
".res.cjs"
Design Decisions
Generating JS files with the .res.js
suffix means that, on the JS side, you can do const myReScriptFile = require('./TheFile.res.js')
. The benefits:
It's immediately clear that we're dealing with a generated JS file here.
It avoids clashes with a potential
TheFile.js
file in the same folder.It avoids the need of using a build system loader for ReScript files. This + in-source build means integrating a ReScript project into your pure JS codebase basically doesn't touch anything in your build pipeline at all.
uncurried
Since 11.0: While we strongly encourage all users to use uncurried mode, it is still possible to opt out. Just set "uncurried"
to false
to get the old behavior back:
JSON{
"uncurried": false
}
More details can be found in the blogpost about "Uncurried Mode".
warnings
Selectively turn on/off certain warnings and/or turn them into hard errors. Example:
JSON{
"warnings": {
"number": "-44-102",
"error": "+5"
}
}
Turn off warning 44
and 102
(polymorphic comparison). Turn warning 5
(partial application whose result has function type and is ignored) into a hard error.
The warning numbers are shown in the build output when they're triggered. See Warning Numbers for the complete list.
bsc-flags
Extra flags to pass to the compiler. For advanced usages.
Environment Variables
We heavily disrecommend the usage of environment variables, but for certain cases, they're justified.
Error Output Coloring: NINJA_ANSI_FORCED
This is mostly for other programmatic usage of rescript
where outputting colors is not desired.
When NINJA_ANSI_FORCED
is set to 1
: rescript
produces color.
When NINJA_ANSI_FORCED
is set to 0
: rescript
doesn't produce color.
When NINJA_ANSI_FORCED
is not set: rescript
might or might not produce color, depending on a smart detection of where it's outputted.
Note that the underlying compiler will always be passed
-color always
. See more details in this issue.