|
| 1 | +--- |
| 2 | +title: "Migrate to v12" |
| 3 | +description: "Instructions on upgrading to ReScript 12" |
| 4 | +canonical: "/docs/manual/migrate-to-v12" |
| 5 | +section: "Overview" |
| 6 | +order: 4 |
| 7 | +--- |
| 8 | + |
| 9 | +# Migrate to ReScript 12 |
| 10 | + |
| 11 | +If you encounter any missing information or issues during migration, please [open an issue](https://github.com/rescript-lang/rescript-lang.org/issues/new?template=documentation_issue.md) or, even better, [send a pull request](https://github.com/rescript-lang/rescript-lang.org/) to help improve this guide. |
| 12 | + |
| 13 | +## Recommended Migration |
| 14 | + |
| 15 | +### Prerequisites |
| 16 | + |
| 17 | +- ReScript V11 project. |
| 18 | +- Uncurried mode must be enabled (i.e. you have not opted-out from it). |
| 19 | +- Your project must not contain any OCaml source code anymore, as support for `.ml` files is removed in this version. However there are ways to convert OCaml syntax with an older ReScript compiler version ([see below](#converting-generated-ml-files)). |
| 20 | +- Minimum supported Node.js version is 20.11.0. |
| 21 | + |
| 22 | +### Standard Library Changes |
| 23 | + |
| 24 | +In V12, the new standard library ships with the compiler, so you can uninstall and remove the `@rescript/core` dependency from your `rescript.json` |
| 25 | + |
| 26 | +```console |
| 27 | +$ npm remove @rescript/core |
| 28 | +``` |
| 29 | + |
| 30 | +```diff |
| 31 | + { |
| 32 | + "bs-dependencies": [ |
| 33 | +- "@rescript/core" |
| 34 | + ] |
| 35 | + } |
| 36 | +``` |
| 37 | + |
| 38 | +Also remove auto opening of `RescriptCore`. |
| 39 | + |
| 40 | +```diff |
| 41 | + { |
| 42 | + "bsc-flags": [ |
| 43 | +- "-open RescriptCore", |
| 44 | + ] |
| 45 | + } |
| 46 | +``` |
| 47 | + |
| 48 | +if you had `@rescript/std` installed, remove it as well: |
| 49 | + |
| 50 | +```shell |
| 51 | +npm uninstall @rescript/std |
| 52 | +``` |
| 53 | + |
| 54 | +this is replaced by `@rescript/runtime`, which is a installed as a dependency of `rescript` now. |
| 55 | + |
| 56 | +## Replacements |
| 57 | + |
| 58 | +Some typical name changes include: |
| 59 | + |
| 60 | +- `Error.t` -> `JsError.t` |
| 61 | +- `raise(MyException("error"))` -> `throw(MyException("error"))` |
| 62 | +- `Js.Exn.Error` exception -> `JsExn` |
| 63 | +- `Error.make` -> `JsExn.make` |
| 64 | +- `Error.raise` -> `JsExn.raise` |
| 65 | +- `Error.message` -> `JsExn.message` |
| 66 | +- `Bool.fromStringExn("true")` -> `Bool.fromStringOrThrow("true")` |
| 67 | +- `Int.Bitwise.lsl` -> `Int.shiftLeft` |
| 68 | + |
| 69 | +Tip: You can use the migration tool to automatically replace these with the new functions. |
| 70 | + |
| 71 | +```shell |
| 72 | +npx rescript-tools migrate-all <root> |
| 73 | + |
| 74 | +# preview the changes via |
| 75 | +rescript-tools migrate <file> [--stdout] |
| 76 | +``` |
| 77 | + |
| 78 | +### Bitwise operations |
| 79 | + |
| 80 | +v11: |
| 81 | + |
| 82 | +```res |
| 83 | +let w = lnot(a) // bitwise NOT |
| 84 | +let x = lxor(a, b) // bitwise XOR |
| 85 | +let y = land(a, b) // bitwise AND |
| 86 | +let z = lor(a, b) // bitwise OR |
| 87 | +``` |
| 88 | + |
| 89 | +v12: |
| 90 | + |
| 91 | +```res |
| 92 | +let w = ~~~a // bitwise NOT |
| 93 | +let x = a ^^^ b // bitwise XOR |
| 94 | +let y = a &&& b // bitwise AND |
| 95 | +let z = a ||| b // bitwise OR |
| 96 | +``` |
| 97 | + |
| 98 | +### Shift operations |
| 99 | + |
| 100 | +v11: |
| 101 | + |
| 102 | +```res |
| 103 | +let x = lsl(a, b) // logical left shift |
| 104 | +let y = lsr(a, b) // logical right shift |
| 105 | +let z = asr(a, b) // unsigned right shift |
| 106 | +``` |
| 107 | + |
| 108 | +v12: |
| 109 | + |
| 110 | +```res |
| 111 | +let x = a << b // logical left shift |
| 112 | +let y = a >> b // logical right shift |
| 113 | +let z = a >>> b // unsigned right shift |
| 114 | +``` |
| 115 | + |
| 116 | +### JSX children spread |
| 117 | + |
| 118 | +v11: |
| 119 | + |
| 120 | +```res |
| 121 | +<div> ...children </div> |
| 122 | +``` |
| 123 | + |
| 124 | +v12: |
| 125 | + |
| 126 | +```res |
| 127 | +<div> children </div> |
| 128 | +``` |
| 129 | + |
| 130 | +### Attributes |
| 131 | + |
| 132 | +v11: |
| 133 | + |
| 134 | +```res |
| 135 | +@bs.as("foo") |
| 136 | +@bs.send |
| 137 | +@bs.new |
| 138 | +@raises |
| 139 | +@genType.as |
| 140 | +``` |
| 141 | + |
| 142 | +v12: |
| 143 | + |
| 144 | +```res |
| 145 | +@as("foo") |
| 146 | +@send |
| 147 | +@new |
| 148 | +@throws |
| 149 | +@as |
| 150 | +``` |
| 151 | + |
| 152 | +- `@meth` and `@bs.send.pipe` are removed. |
| 153 | + |
| 154 | +### Assert |
| 155 | + |
| 156 | +v11: |
| 157 | + |
| 158 | +```res |
| 159 | +assert 1 == 2 |
| 160 | +``` |
| 161 | + |
| 162 | +v12: |
| 163 | + |
| 164 | +```res |
| 165 | +assert(1 == 2) // Now a regular function call |
| 166 | +``` |
| 167 | + |
| 168 | +## Configuration |
| 169 | + |
| 170 | +Rename `bsconfig.json` to `rescript.json` and update these configuration options: |
| 171 | + |
| 172 | +- `bs-dependencies` → `dependencies` |
| 173 | +- `bs-dev-dependencies` → `dev-dependencies` |
| 174 | +- `bsc-flags` → `compiler-flags` |
| 175 | + |
| 176 | +### jsx |
| 177 | + |
| 178 | +- Set `version` to `4` (lower versions are not supported) |
| 179 | +- Remove `mode` option (automatically set to `automatic`) |
| 180 | + |
| 181 | +## Build System Changes |
| 182 | + |
| 183 | +The build system has been completely rewritten in v12.0.0. |
| 184 | + |
| 185 | +In v11, we had: |
| 186 | + |
| 187 | +```shell |
| 188 | +# build |
| 189 | +rescript build |
| 190 | + |
| 191 | +# watch build |
| 192 | +rescript build -w |
| 193 | + |
| 194 | +# format |
| 195 | +rescript format -all |
| 196 | +``` |
| 197 | + |
| 198 | +in v12, this becomes: |
| 199 | + |
| 200 | +```shell |
| 201 | +# build |
| 202 | +rescript |
| 203 | + |
| 204 | +# watch build |
| 205 | +rescript watch |
| 206 | + |
| 207 | +# format |
| 208 | +rescript format |
| 209 | +``` |
| 210 | + |
| 211 | +## Converting generated `.ml` files |
| 212 | + |
| 213 | +**Note**: This setup is an escape hatch. It keeps legacy generators like `atdgen` working but it also forces you to maintain two compiler versions. Whenever possible migrate such things to modern ReScript tooling such as [Sury](https://github.com/DZakh/sury/). |
| 214 | + |
| 215 | +Some projects still rely on tools such as `atdgen` that emit `.ml` files. ReScript 12 cannot compile those files directly, so you must keep using ReScript 11 **only** to convert the generated `.ml` files back to `.res` files before you run the v12 build. |
| 216 | + |
| 217 | +1. Keep ReScript 12 as the sole compiler dependency in your main project (i.e. `devDependencies.rescript` stays at `^12.0.0`). |
| 218 | + |
| 219 | +2. Install ReScript 11 in a dedicated subfolder (so its binaries never replace the v12 ones in `node_modules/.bin`). A simple option is to store it under a subfolder, e.g. `tools` (if you're using workspaces, keep this folder out of the root workspace list so hoisting can't swap the v12 shims): |
| 220 | + |
| 221 | +`cd` into `tools` and run `npm create rescript-app` and select the basic template and a v11 version of ReScript. You can name it `rescript-11` for instance. |
| 222 | + |
| 223 | +3. `cd` back into the root of your project and add a helper script that references the compiler from that folder (adapt the path accordingly): |
| 224 | + |
| 225 | + ```json |
| 226 | + { |
| 227 | + "scripts": { |
| 228 | + "convert-ml": "tools/rescript-11/node_modules/.bin/rescript convert src/*.ml" |
| 229 | + } |
| 230 | + } |
| 231 | + ``` |
| 232 | + |
| 233 | +4. Execute the helper script to convert your `.ml` files to `.res` files: |
| 234 | + |
| 235 | +```console |
| 236 | +npm run convert-ml |
| 237 | +``` |
| 238 | + |
| 239 | +## List of all breaking changes |
| 240 | + |
| 241 | +Below is a consolidated excerpt of all the breaking changes from the compiler changelog. |
| 242 | + |
| 243 | +### Language & syntax |
| 244 | + |
| 245 | +- Tag functions named `j` or `js` are no longer reserved, so add your own implementation whenever a tagged template expects them. https://github.com/rescript-lang/rescript-compiler/pull/6817 |
| 246 | +- `lazy` syntax was removed; use the `Lazy` module instead. https://github.com/rescript-lang/rescript-compiler/pull/6342 |
| 247 | +- All legacy `@bs.*` attributes (e.g. `@bs.as`, `@bs.send`) and `@bs.open` were removed; use their prefix-free successors (`@as`, `@send`, `@open`, …). https://github.com/rescript-lang/rescript-compiler/pull/6643 https://github.com/rescript-lang/rescript-compiler/pull/6629 |
| 248 | +- `@bs.send.pipe` was removed; rewrite bindings to use `@send`. https://github.com/rescript-lang/rescript-compiler/pull/6858 https://github.com/rescript-lang/rescript-compiler/pull/6891 |
| 249 | +- OCaml `.ml` files are no longer supported anywhere: `.ml` parsing/formatting went away and the `rescript convert` CLI was removed, so convert legacy files to `.res` before upgrading. https://github.com/rescript-lang/rescript-compiler/pull/6848 https://github.com/rescript-lang/rescript-compiler/pull/6852 https://github.com/rescript-lang/rescript-compiler/pull/6860 |
| 250 | +- Some global names and old keywords are no longer automatically prefixed during JS emission; update any code that was relying on the mangled names. https://github.com/rescript-lang/rescript-compiler/pull/6831 |
| 251 | +- JSX v3 and the `-bs-jsx-mode` option were removed and JSX children spreads are no longer valid; JSX v4 semantics are now the only supported mode. https://github.com/rescript-lang/rescript-compiler/pull/7072 https://github.com/rescript-lang/rescript/pull/7327 https://github.com/rescript-lang/rescript/pull/7869 |
| 252 | + |
| 253 | +### Standard library & runtime |
| 254 | + |
| 255 | +- OCaml compatibility layers in the stdlib and primitives were removed/deprecated. https://github.com/rescript-lang/rescript-compiler/pull/6984 |
| 256 | +- Deprecated modules `Js.Vector` and `Js.List` were deleted. https://github.com/rescript-lang/rescript-compiler/pull/6900 |
| 257 | +- The legacy `js_cast.res` helpers were removed; migrate to explicit externals. https://github.com/rescript-lang/rescript-compiler/pull/7075 |
| 258 | +- `JsError` and related modules were renamed/cleaned up under `JsExn`. https://github.com/rescript-lang/rescript/pull/7408 |
| 259 | +- `BigInt.fromFloat` now returns `option` and exposes `BigInt.fromFloatOrThrow`, and the `Exn`-suffixed helpers across `Bool`, `BigInt`, `JSON`, `Option`, `Null`, `Nullable`, `Result`, and `List` now end with `OrThrow`. https://github.com/rescript-lang/rescript/pull/7419 https://github.com/rescript-lang/rescript/pull/7518 https://github.com/rescript-lang/rescript/pull/7554 |
| 260 | +- `Result.getOrThrow` throws a JS `Error` (instead of `Not_found`), and `Result.equal` / `Result.compare` now provide a comparison function for `Error` values. https://github.com/rescript-lang/rescript/pull/7630 https://github.com/rescript-lang/rescript/pull/7933 |
| 261 | +- `Iterator.forEach` now emits `Iterator.prototype.forEach`. https://github.com/rescript-lang/rescript/pull/7506 |
| 262 | +- `Date.make` uses `~day` instead of `~date`. https://github.com/rescript-lang/rescript/pull/7324 |
| 263 | +- Plain `int` multiplication is implemented as a regular int32 operation instead of `Math.imul`. https://github.com/rescript-lang/rescript/pull/7358 |
| 264 | +- The `List` API was cleaned up—several functions were renamed or removed (see the PR for the exact surface). https://github.com/rescript-lang/rescript/pull/7290 |
| 265 | +- `String.getSymbol` / `String.setSymbol` were removed; only `String.getSymbolUnsafe` remains on strings. https://github.com/rescript-lang/rescript/pull/7571 https://github.com/rescript-lang/rescript/pull/7626 |
| 266 | +- `String.charCodeAt` now returns `option<int>` and exposes `String.charCodeAtUnsafe` for unchecked access. https://github.com/rescript-lang/rescript/pull/7877 |
| 267 | +- `Intl.*.supportedLocalesOf` bindings now return `array<string>` and the non-portable `Intl.PluralRules.selectBigInt` / `selectRangeBigInt` were removed. https://github.com/rescript-lang/rescript/pull/7995 |
| 268 | + |
| 269 | +### Build system & CLI |
| 270 | + |
| 271 | +- The new Rust-based `rewatch` build system now powers the `rescript` command. The old Ninja-based builder system moved behind `rescript legacy`, and `--compiler-args` became the `compiler-args` subcommand. https://github.com/rescript-lang/rescript/pull/7551 https://github.com/rescript-lang/rescript/pull/7593 https://github.com/rescript-lang/rescript/pull/7928 |
| 272 | +- `rescript format` was reimplemented in Rust, its options now use the `--check` / `--stdin` long-form spelling, and the `--all` flag was removed because every tracked file (non-dev by default) is formatted automatically. https://github.com/rescript-lang/rescript/pull/7603 https://github.com/rescript-lang/rescript/pull/7752 |
| 273 | +- The `rescript dump` command was removed; call `bsc` directly if you need to inspect `.cmi` files. https://github.com/rescript-lang/rescript/pull/7710 |
| 274 | + |
| 275 | +### Configuration & platform |
| 276 | + |
| 277 | +- The minimum supported Node.js version is now 20.11.0. https://github.com/rescript-lang/rescript/pull/7354 |
| 278 | +- The `experimental-features` key in `rescript.json` now uses kebab-case to match the other config fields. https://github.com/rescript-lang/rescript/pull/7891 |
| 279 | +- The legacy `-bs-super-errors` flag was removed. https://github.com/rescript-lang/rescript-compiler/pull/6814 |
0 commit comments