Skip to content

Commit 185ff54

Browse files
committed
Rough outline of general v12 blog post
1 parent 72fc344 commit 185ff54

File tree

3 files changed

+226
-0
lines changed

3 files changed

+226
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
---
2+
author: rescript-team
3+
date: "2025-11-17"
4+
previewImg: /static/blog/rescript-12-reforging-build-system.webp
5+
articleImg: /static/blog/rescript-12-reforging-build-system.webp
6+
badge: release
7+
title: "Announcing ReScript 12"
8+
description: |
9+
ReScript 12 arrives with a redesigned build toolchain, a modular runtime, and a wave of ergonomic language features.
10+
---
11+
12+
## Introduction
13+
14+
ReScript 12 is now available.
15+
This release completes the multi-year effort to separate the compiler from legacy constraints, refreshes critical developer workflows, and delivers a modern feature set that is grounded in real-world feedback.
16+
The headline upgrades include a rewritten build system, a standalone runtime package, unified operator support, JSX preserve mode, and numerous syntax improvements that make ReScript code easier to write and maintain.
17+
18+
Teams upgrading from ReScript 11 should review the highlighted breaking changes and schedule time for migration.
19+
The new tooling provides focused commands, better diagnostics, and smaller downloads, while the language additions flatten sharp edges that many of you encountered in larger codebases.
20+
21+
## Breaking Changes
22+
23+
### Build system redesign
24+
25+
ReScript 12 ships with the new build system introduced earlier this month in the [Reforging the Build System](./2025-11-04-reforging-build-system.mdx) preview.
26+
The tooling now relies on a modern architecture that tracks dependencies more precisely, avoids unnecessary recompilations, and integrates with incremental workflows.
27+
The old build system remains available through `rescript-legacy`, but active projects should switch to the new commands to benefit from faster feedback loops and clearer output.
28+
29+
### Runtime package split
30+
31+
The compiler no longer embeds runtime modules.
32+
Instead, the runtime lives in the dedicated `@rescript/runtime` npm package, which contains Belt, Stdlib, Js, primitive modules, and supporting artifacts compiled in both ES Module and CommonJS formats.
33+
Earlier versions bundled these files inside the `rescript` package and exposed an optional `@rescript/std` helper.
34+
ReScript 12 removes `@rescript/std`; install `rescript` and `@rescript/runtime` together to keep projects in sync.
35+
Projects that previously published custom runtime shims should revisit their setup to ensure the new package structure remains discoverable.
36+
37+
### Updated bitwise operator surface
38+
39+
Legacy OCaml-style bitwise functions such as `land`, `lor`, and `lsl` are deprecated.
40+
They continue to work in v12 with warnings but will be removed in v13.
41+
ReScript now prefers unified operator syntax: `&&&`, `|||`, `^^^`, and `~~~` cover AND, OR, XOR, and NOT for both `int` and `bigint`.
42+
43+
### API naming alignment
44+
45+
APIs that previously ended with `Exn` now end with `OrThrow`.
46+
Examples include `Option.getOrThrow`, `List.headOrThrow`, `BigInt.fromStringOrThrow`, and `JSON.parseOrThrow`.
47+
The change clarifies that these functions throw JavaScript errors, aligning the naming with the language’s semantics.
48+
The deprecated `*Exn` variants remain available in v12 to ease the transition, and the codemod bundled with the migration tool can perform a mechanical rename.
49+
Be aware that `Result.getOrThrow` now throws a JavaScript `Error`, so update any exception handling logic that depended on OCaml exception names.
50+
51+
### JSX version requirement
52+
53+
JSX v3 has been removed.
54+
ReScript 12 requires JSX v4 configuration in `rescript.json`, using the `"jsx": { "version": 4 }` schema.
55+
ReScript React projects must update their configuration before moving to v12.
56+
Projects attempting to compile with v3 will receive an explicit error, ensuring that your codebase uses the current transform and associated tooling.
57+
58+
### Deprecation of OCaml compatibility helpers
59+
60+
The standard library continues its shift away from OCaml-specific aliases.
61+
Functions such as `succ`, `pred`, `abs_float`, `string_of_int`, `fst`, `raise`, and the `char` type are now deprecated.
62+
The recommended replacements are the JavaScript-aligned counterparts in `Int`, `Float`, `Bool`, `Pair`, and related modules, alongside the `throw` keyword for exceptions.
63+
References to the OCaml composition operators (`|>`, `@@`) now warn and will be removed in v13; the ReScript pipe operator `->` replaces them.
64+
The migration tool highlights deprecated usage, and incremental cleanups are encouraged so your codebase is ready before the next major release.
65+
66+
## New features
67+
68+
### Unified operators
69+
70+
ReScript 12 finalizes the unified operator work introduced [earlier this year](./2025-04-11-introducing-unified-operators.mdx).
71+
Arithmetic, comparison, and bitwise operators now behave consistently across `int` and `bigint`, allowing the compiler to infer the correct specialization from the left operand.
72+
73+
### Expanded bitwise capabilities
74+
75+
In addition to deprecating the OCaml-style helpers, ReScript 12 adds new operator spellings.
76+
JavaScript-style bitwise operators (`&`, `|`, `^`, `~`) and shift operators (`<<`, `>>`, `>>>`) are first-class citizens that compile directly to their JavaScript equivalents.
77+
Combined with the unified F#-style operators, developers can select the syntax that best fits their code policies without sacrificing performance or type safety.
78+
79+
### Dict literals and pattern matching
80+
81+
The language now supports dictionary literals (`dict{"foo": "bar"}`) that compile to plain JavaScript objects.
82+
Dict literals work with variables, multi-line formatting, and optional entries, and they drastically reduce the boilerplate compared to `Dict.fromArray`.
83+
Pattern matching also understands dicts, enabling concise destructuring of JSON payloads and configuration objects.
84+
The compiler emits the same optimized JavaScript while preserving ReScript's type guarantees.
85+
86+
```rescript
87+
let user = dict{"name": "Ada", "role": "engineer"}
88+
89+
switch user {
90+
| dict{"name": name, "role": role} => Console.log2(name, role)
91+
| _ => Console.log("missing user metadata")
92+
}
93+
```
94+
95+
### Nested and inline record types
96+
97+
Nested record definitions and inline record payloads remove the need for auxiliary type declarations.
98+
You can define optional nested structures directly inside records, or attach record payloads to variant constructors without creating standalone types.
99+
The feature supports mutable fields, type parameters, and record spreading, providing better locality for complex domain models with no runtime penalty.
100+
101+
```rescript
102+
type profile = {
103+
name: string,
104+
extra?: {
105+
location: {city: string, country: string},
106+
mutable note: option<string>,
107+
},
108+
}
109+
```
110+
111+
### Variant pattern spreads
112+
113+
Pattern spreads (`| ...SomeVariant as value =>`) allow you to reuse handlers for entire subsets of constructors.
114+
When a variant extends another variant through spreads, you can match the shared constructors in one branch and delegate to helper functions, keeping exhaustive matches concise even as the hierarchy grows.
115+
The compiler enforces subtype relationships and ensures that runtime representations remain compatible.
116+
117+
```rescript
118+
type base = Start | Stop | Pause
119+
type extended = | ...base | Resume
120+
121+
let handle = (event: extended) =>
122+
switch event {
123+
| ...base as core => Console.log2("base", core)
124+
| Resume => Console.log("resuming")
125+
}
126+
```
127+
128+
### JSX preserve mode
129+
130+
Projects that rely on downstream JSX tooling can enable [preserve mode](../docs/manual/v12.0.0/jsx#preserve-mode) via `"jsx": { "version": 4, "preserve": true }`.
131+
The compiler will emit JSX syntax directly instead of transforming elements to `react/jsx-runtime` calls, allowing bundlers such as ESBuild, SWC, or Babel to apply their own transforms.
132+
This mode keeps JSX readable in the output, retains spread props, and maintains compatibility with React Server Components.
133+
React classic mode is no longer supported, so projects must use the JSX v4 transform regardless of preserve mode settings.
134+
When preserve mode is disabled, the compiler continues to output the optimized runtime calls you are accustomed to.
135+
136+
### Function-level directives
137+
138+
The new `@directive` attribute emits JavaScript directive strings at the top of generated functions.
139+
Use it to mark server actions with `'use server'`, memoized handlers with `'use memo'`, or any other directive that your framework requires.
140+
The attribute works on synchronous and asynchronous functions, supports labeled parameters, and removes the need for `%raw` blocks.
141+
Combined with JSX preserve mode, this enables clean integration with [React Server Components](../docs/react/latest/server-components.mdx) and other directive-based runtimes.
142+
143+
### Regex literals
144+
145+
ReScript now understands JavaScript-style regular expression literals (`/pattern/flags`).
146+
They are full equivalents of `%re` expressions, supporting all ECMAScript flags, Unicode character classes, and sticky searches.
147+
The literals compile directly to JavaScript regex objects, so existing APIs like `RegExp.exec` and `RegExp.test` continue to work exactly as before, but with clearer syntax and better editor support.
148+
149+
```rescript
150+
let emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/i
151+
152+
if emailPattern->RegExp.test("contact@rescript-lang.org") {
153+
Console.log("Valid email")
154+
}
155+
156+
switch emailPattern->RegExp.exec("invalid") {
157+
| Some(match) => Console.log(match->RegExp.Result.fullMatch)
158+
| None => Console.log("No match")
159+
}
160+
```
161+
162+
### Experimental `let?` syntax
163+
164+
This release introduces an experimental `let?` syntax for zero-cost unwrapping of `option` and `result` values.
165+
The syntax remains behind an opt-in flag while the community evaluates its ergonomics.
166+
Refer to the forum discussion at https://forum.rescript-lang.org/t/proposing-new-syntax-for-zero-cost-unwrapping-options-results/6227 for the current proposal, examples, and feedback guidelines.
167+
168+
```rescript
169+
type user = {
170+
address?: {
171+
city?: string,
172+
},
173+
}
174+
175+
let userCity = (user: user): option<string> => {
176+
let? Some(address) = user.address
177+
let? Some(city) = address.city
178+
Some(city)
179+
}
180+
```
181+
182+
## Platform and tooling improvements
183+
184+
### Cleaner JavaScript output
185+
186+
The printer now emits compact arrow functions and streamlines anonymous function expressions, making generated JavaScript easier to audit.
187+
These changes preserve semantics while aligning the output with modern JavaScript style.
188+
189+
### Internal architecture updates
190+
191+
The compiler cleans up its internal abstract syntax tree, removes unused OCaml-era nodes, and tracks async and partial function metadata directly on AST nodes.
192+
These changes simplify future feature work and reduce maintenance overhead.
193+
194+
### ESM-first distribution
195+
196+
The `rescript` npm package declares `"type": "module"` and ships ESM code across the CLI.
197+
Import statements replace CommonJS `require` usage, improving compatibility with contemporary bundlers and enabling better tree-shaking.
198+
199+
### OCaml 5.3 toolchain
200+
201+
The compiler and supporting tooling now build on OCaml 5.3.0.
202+
Contributors compiling ReScript from source will need the updated toolchain, and the upgrade brings performance and language runtime improvements from the upstream project.
203+
204+
### Platform-specific binaries
205+
206+
Installer footprints shrink thanks to platform-specific binary packages such as `@rescript/darwin-arm64`, `@rescript/linux-x64`, and `@rescript/win32-x64`.
207+
npm installs only the binary that matches your operating system and architecture, delivering substantially faster installs and smaller cache footprints for CI pipelines.
208+
The primary `rescript` package loads the appropriate binary at runtime and surfaces clear error messages if the matching package is missing.
209+
210+
## Acknowledgments
211+
212+
![ReScript core team during the 2025 Vienna retreat](/static/blog/rescript-retreat-2025.webp)
213+
214+
Thank you to every contributor, tester, and partner who helped shape ReScript 12.
215+
The core team gathered in Vienna earlier this year to map out this release, and your feedback guided every decision.
216+
Community pull requests, bug reports, and experiments across the ecosystem gave us the confidence to complete large refactors and deprecations.
217+
218+
## Reach out
219+
220+
Join the conversation on the community forum if you have migration questions or want to share what you build with ReScript 12.
221+
Businesses that rely on ReScript can contact the association at https://rescript-association.org/contact to explore support, sponsorship, or collaboration.
222+
Funding enables the team to ship features like the new runtime architecture faster, so every contribution, financial or otherwise, helps the language move forward.
223+
224+
We look forward to hearing what you create with ReScript 12.
225+
226+
![The ReScript team at the 2025 retreat in Vienna](/static/blog/rescript-team-2025.webp)
18.6 KB
Loading
424 KB
Loading

0 commit comments

Comments
 (0)