Skip to content

Commit 787308b

Browse files
ryyppycknittzth
authored
Prepare 10.1 release (#633)
* Add async/await as keywords in HLJS and codemirror * Add rough async/await doc * Small markdown tweaks * Update async/await * Update promise and async await docs * Improve formatting for Since 10.1 * Add async/await to syntax widget * Add async/await to cheatsheet * Add blogpost * Rename blogpost date * Small text improvement * Remove temporary Demo.mjs import * Improve promise docs note * Expand sentence in promise docs * Improve Promise.all example * Add "the" * Update roadmap page * Update npmjs link * Apply suggestions from code review Co-authored-by: Christoph Knittel <[email protected]> * Apply suggestions from code review * Apply suggestions from code review (zth) Co-authored-by: Gabriel Nordeborn <[email protected]> * Improve roadmap * Address individual feedback * Fix async/await example * More polish * Decorator -> Attribute --------- Co-authored-by: Patrick Ecker <[email protected]> Co-authored-by: Christoph Knittel <[email protected]> Co-authored-by: Gabriel Nordeborn <[email protected]>
1 parent 2c0fbbe commit 787308b

12 files changed

+897
-20
lines changed
+308
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
---
2+
author: rescript-team
3+
date: "2023-02-02"
4+
title: ReScript 10.1
5+
badge: release
6+
description: |
7+
Async/await & better Promise support, JSX v4, and more!
8+
---
9+
10+
## Introduction
11+
12+
We are happy to announce ReScript 10.1!
13+
14+
ReScript is a robustly typed language that compiles to efficient and human-readable JavaScript. It comes with one of the fastest build toolchains and offers first class support for interoperating with ReactJS and other existing JavaScript code.
15+
16+
Use `npm` to install the newest [10.1 release](https://www.npmjs.com/package/rescript/v/10.1.2):
17+
18+
```
19+
npm install rescript
20+
21+
# or
22+
23+
npm install [email protected]
24+
```
25+
26+
This version comes with two major language improvements we've all been waiting for. **async/await support** for an easy way to write asynchronous code in a synchronous manner, and a **new JSX transform** with better ergonomics, code generation and React 18 support.
27+
28+
Alongside the major changes, there have been many bugfixes and other improvements that won't be covered in this post.
29+
30+
Feel free to check the [Changelog](https://github.com/rescript-lang/rescript-compiler/blob/master/CHANGELOG.md#1011) for all the details.
31+
32+
## New `async` / `await` syntax
33+
34+
Async / await has arrived. Similar to its JS counterparts, you are now able to define `async` functions and use the `await` operator to unwrap a promise value. This allows writing asynchronous code in a synchronous fashion.
35+
36+
**Example:**
37+
38+
```res
39+
// Some fictive functionality that offers asynchronous network actions
40+
@val external fetchUserMail: string => promise<string> = "GlobalAPI.fetchUserMail"
41+
@val external sendAnalytics: string => promise<unit> = "GlobalAPI.sendAnalytics"
42+
43+
// We use the `async` keyword to allow the use of `await` in the function body
44+
let logUserDetails = async (userId: string) => {
45+
// We use `await` to fetch the user email from our fictive user endpoint
46+
let email = await fetchUserMail(userId)
47+
48+
await sendAnalytics(`User details have been logged for ${userId}`)
49+
50+
Js.log(`Email address for user ${userId}: ${email}`)
51+
}
52+
```
53+
54+
To learn more about our async / await feature, check out the relevant [manual section](/docs/manual/latest/async-await).
55+
56+
## New `promise` builtin type and `Js.Promise2` module
57+
58+
In previous versions of ReScript, promises were expressed as a `Js.Promise.t<'a>` type, which was a little tedious to type. From now on, users may use the `promise<'a>` type instead.
59+
60+
Quick example of a `.resi` file using the new `promise` type:
61+
62+
```resi
63+
// User.resi
64+
type user
65+
66+
let fetchUser: string => promise<user>
67+
```
68+
69+
Way easier on the eyes, don't you think? Note that the new `promise` type is fully compatible with `Js.Promise.t` (no breaking changes).
70+
71+
Additionally, we also introduced the `Js.Promise2` module as a stepping stone to migrate `Js.Promise` based code to a first-pipe (->) friendly solution. For the daily practise you'll almost always want to use `async` / `await` to handle promises.
72+
73+
(*Sidenote*: We are also well aware that our users want a solution to unify `Belt`, `Js` and `Js.xxx2` and have a fully featured "standard library" instead of adding more `Js.xxx2` modules. Good news is that we have a solution in the pipeline to fix this. `Js.Promise2` was introduced to ease the process later on and is not supposed to be the panacea of promise handling.)
74+
75+
If you are already using a third-party promise library like [ryyppy/rescript-promise](https://github.com/ryyppy/rescript-promise) or similar, there's no need to migrate any existing code. Introduce `async` / `await` gradually in your codebase as you go.
76+
77+
78+
## New JSX v4 syntax
79+
80+
ReScript 10.1 now ships with JSX v4. Here's what's new:
81+
82+
- **Cleaner interop.** Due to recent improvements in the type checker, the `@react.component` transformation doesn't require any `makeProps` convention anymore. `make` functions will now be transformed into a `prop` type and a component function. That's it.
83+
- **Two new transformation modes**. JSX v4 comes with a `classic` mode (= `React.createElement`) and `automatic` mode (= `jsx-runtime` calls). The latter is the new default, moving forward with `rescript/[email protected]` and `React@18`.
84+
- **Allow mixing JSX configurations on the project and module level.** Gradually mix and match JSX transformations and modes without migrating any old code!
85+
- **Pass `prop` types** to `@react.component`. You can now fine tune `@react.component` with your specific prop type needs. Very useful for libraries and frameworks to define component interfaces.
86+
- **Less boilerplate when using `React.Context`**. Check out our [example](/docs/react/latest/migrate-react#reactcontext) for comparison.
87+
- **Revisited props spread operator.** This will allow users to spread records in JSX without sacrificing their sanity. Note that this implementation has harder constraints than its JS counterpart. (requires `rescript/[email protected]` or higher)
88+
- **Better type inference of props.** Type inference when passing e.g. variants that are defined in the same module as the component is much improved. With the earlier JSX version, you'd often need to write code like this in order for the compiler to understand which variant you're passing: `<Button variant=Button.Primary text="Click" />`. With JSX v4, you won't need to tell the compiler where the variant you're passing is located: `<Button variant=Primary text="Click" />`.
89+
90+
Code tells more than words, so here's a non-exhaustive code example to highlight the different JSX features. Make sure to also check out the JS output and play around with the code in our newest playground!
91+
92+
<CodeTab labels={["ReScript", "JS Output"]}>
93+
94+
```res
95+
// Set the jsx configuration per module
96+
@@jsxConfig({version: 4, mode: "automatic"})
97+
98+
module AutomaticModeExample = {
99+
// "automatic" mode will compile jsx to the React 18 compatible
100+
// jsx-runtime calls
101+
@@jsxConfig({version: 4, mode: "automatic"})
102+
103+
@react.component
104+
let make = (~name) => {
105+
<div> {React.string(`Hello ${name}`)} </div>
106+
}
107+
}
108+
109+
module ClassicModeExample = {
110+
// "classic" mode will compile jsx to React.createElement calls
111+
@@jsxConfig({version: 4, mode: "classic"})
112+
113+
@react.component
114+
let make = (~name) => {
115+
<div> {React.string(`Hello ${name}`)} </div>
116+
}
117+
}
118+
119+
module NoAttributeExample = {
120+
// No need for `makeProps` anymore
121+
type props = {name: string}
122+
123+
let make = (props: props) => {
124+
<div> {React.string(`Hello ${props.name}`)} </div>
125+
}
126+
}
127+
128+
module ReactInterfaceExample: {
129+
@react.component
130+
let make: (~name: string, ~age: int=?) => React.element
131+
} = {
132+
@react.component
133+
let make = (~name, ~age=0) => {
134+
<div>
135+
{React.string(
136+
`Hello ${name}, you are ${Belt.Int.toString(age)} years old.`,
137+
)}
138+
</div>
139+
}
140+
}
141+
142+
module PropTypeInjectionExample = {
143+
// Let's assume we have a prop type that we wanna enforce
144+
// as our labeled arguments
145+
type someoneElsesProps = {isHuman: bool}
146+
147+
// Here we tell the `react.component` decorator what props to infer.
148+
// Useful for e.g. NextJS usage, or to create components that should
149+
// comply to certain library component interfaces
150+
@react.component(: someoneElsesProps)
151+
let make = (~isHuman) => {
152+
let msg = switch isHuman {
153+
| true => "hello human"
154+
| false => "hello fellow computer"
155+
}
156+
<div> {React.string(msg)} </div>
157+
}
158+
}
159+
160+
module PropSpreadExample = {
161+
// Note: This will require @rescript/react 0.11 or later
162+
@@jsxConfig({version: 4, mode: "automatic"})
163+
164+
@react.component
165+
let make = () => {
166+
let props = {NoAttributeExample.name: "World"}
167+
168+
<NoAttributeExample {...props} />
169+
}
170+
}
171+
172+
let root =
173+
<div>
174+
<AutomaticModeExample name="Automatic" />
175+
<ClassicModeExample name="Classic" />
176+
<NoAttributeExample name="NoAttribute" />
177+
<ReactInterfaceExample name="Interface" />
178+
<PropTypeInjectionExample isHuman=true />
179+
<PropSpreadExample />
180+
</div>
181+
```
182+
183+
```js
184+
import * as React from "react";
185+
import * as JsxRuntime from "react/jsx-runtime";
186+
187+
function Playground$AutomaticModeExample(props) {
188+
return JsxRuntime.jsx("div", {
189+
children: "Hello " + props.name + ""
190+
});
191+
}
192+
193+
var AutomaticModeExample = {
194+
make: Playground$AutomaticModeExample
195+
};
196+
197+
function Playground$ClassicModeExample(props) {
198+
return React.createElement("div", undefined, "Hello " + props.name + "");
199+
}
200+
201+
var ClassicModeExample = {
202+
make: Playground$ClassicModeExample
203+
};
204+
205+
function make(props) {
206+
return JsxRuntime.jsx("div", {
207+
children: "Hello " + props.name + ""
208+
});
209+
}
210+
211+
var NoAttributeExample = {
212+
make: make
213+
};
214+
215+
function Playground$ReactInterfaceExample(props) {
216+
var age = props.age;
217+
var age$1 = age !== undefined ? age : 0;
218+
return JsxRuntime.jsx("div", {
219+
children: "Hello " + props.name + ", you are " + String(age$1) + " years old."
220+
});
221+
}
222+
223+
var ReactInterfaceExample = {
224+
make: Playground$ReactInterfaceExample
225+
};
226+
227+
function Playground$PropTypeInjectionExample(props) {
228+
var msg = props.isHuman ? "hello human" : "hello fellow computer";
229+
return JsxRuntime.jsx("div", {
230+
children: msg
231+
});
232+
}
233+
234+
var PropTypeInjectionExample = {
235+
make: Playground$PropTypeInjectionExample
236+
};
237+
238+
function Playground$PropSpreadExample(props) {
239+
return JsxRuntime.jsx(make, {
240+
name: "World"
241+
});
242+
}
243+
244+
var PropSpreadExample = {
245+
make: Playground$PropSpreadExample
246+
};
247+
248+
var root = JsxRuntime.jsxs("div", {
249+
children: [
250+
JsxRuntime.jsx(Playground$AutomaticModeExample, {
251+
name: "Automatic"
252+
}),
253+
JsxRuntime.jsx(Playground$ClassicModeExample, {
254+
name: "Classic"
255+
}),
256+
JsxRuntime.jsx(make, {
257+
name: "NoAttribute"
258+
}),
259+
JsxRuntime.jsx(Playground$ReactInterfaceExample, {
260+
name: "Interface"
261+
}),
262+
JsxRuntime.jsx(Playground$PropTypeInjectionExample, {
263+
isHuman: true
264+
}),
265+
JsxRuntime.jsx(Playground$PropSpreadExample, {})
266+
]
267+
});
268+
269+
export {
270+
AutomaticModeExample ,
271+
ClassicModeExample ,
272+
NoAttributeExample ,
273+
ReactInterfaceExample ,
274+
PropTypeInjectionExample ,
275+
PropSpreadExample ,
276+
root ,
277+
}
278+
```
279+
</CodeTab>
280+
281+
### How to migrate to JSX v4?
282+
283+
We provide a full [migration guide](/docs/react/latest/migrate-react) with all the details of an migration.
284+
285+
Make sure to also check out the [rescript-react changelog](https://github.com/rescript-lang/rescript-react/blob/master/CHANGELOG.md) as well.
286+
287+
## What's next?
288+
289+
Our contributors are already one step ahead and are currently working on improvements for the next major v11 release. Things that are currently being explored:
290+
291+
- Make uncurried functions the default. This will be a huge change in terms of how we do interop and will open completely new ways to interact with existing codebases. It will also allow us to improve tooling in ways that wouldn't have been possible in a curried language.
292+
- Explorations for a community "standard library" that goes beyond `Belt` and `Js.*`. This will also involve disabling / removing global "Stdlib" modules that shouldn't be used (e.g. `Array`, `List`, etc).
293+
- New tooling to generate markdown from docstrings (module, type and value level). This will be super simple, but very effective.
294+
- Explorations for a [localized documentation page](https://forum.rescript-lang.org/t/translation-project-rescript-lang-org/4022) (currently in a slowed-down exploration phase, but we will be getting there)
295+
296+
Check out the [v11](https://github.com/rescript-lang/rescript-compiler/issues?q=is%3Aopen+is%3Aissue+milestone%3Av11.0) milestone on our `rescript-lang` repo for more details on future improvements.
297+
298+
## Acknowledgements
299+
300+
As always, we want to thank our [contributors](https://github.com/rescript-lang/rescript-compiler/graphs/contributors?from=2019-11-24&to=2023-02-02&type=c) for building an amazing platform. Special thanks go out to [mununki](https://github.com/mununki) for building the new JSX v4 syntax. Amazing work!
301+
302+
## That's it
303+
304+
We hope you enjoy the newest improvements as much as we do.
305+
306+
In case there's any issues / problems, make sure to report bugs to [rescript-lang/rescript-compiler](https://github.com/rescript-lang/rescript-compiler) (language / syntax / jsx), [rescript-lang/rescript-react](https://github.com/rescript-lang/rescript-react) (React 16 / 18 binding) or [rescript-association/rescript-lang.org](https://github.com/rescript-association/rescript-lang.org) (documentation) repositories.
307+
308+
Also feel free to visit the [ReScript forum](https://forum.rescript-lang.org/) to ask questions and connect with other ReScripters.

data/sidebar_manual_latest.json

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"exception",
2828
"lazy-values",
2929
"promise",
30+
"async-await",
3031
"module",
3132
"import-export",
3233
"attribute",

misc_docs/syntax/language_async.mdx

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
id: "async"
3+
keywords: ["async"]
4+
name: "async"
5+
summary: "This is the `async` keyword."
6+
category: "languageconstructs"
7+
---
8+
9+
**Since 10.1**
10+
11+
Use the `async` keyword to make a function asynchronous. An async function may use the [await](#await) keyword to unwrap a promise value in a seamingly synchronous manner.
12+
13+
### Example
14+
15+
<CodeTab labels={["ReScript", "JS Output"]}>
16+
17+
```res
18+
// Some fictive functionality that offers asynchronous network actions
19+
@val external fetchUserMail: string => promise<string> = "GlobalAPI.fetchUserMail"
20+
@val external sendAnalytics: string => promise<unit> = "GlobalAPI.sendAnalytics"
21+
22+
// We use the `async` keyword to allow the use of `await` in the function body
23+
let logUserDetails = async (userId: string) => {
24+
// We use `await` to fetch the user email from our fictive user endpoint
25+
let email = await fetchUserMail(userId)
26+
27+
await sendAnalytics(`User details have been logged for ${userId}`)
28+
29+
Js.log(`Email address for user ${userId}: ${email}`)
30+
}
31+
```
32+
33+
```js
34+
async function logUserDetails(userId) {
35+
var email = await GlobalAPI.fetchUserMail(userId);
36+
await GlobalAPI.sendAnalytics("User details have been logged for " + userId + "");
37+
console.log("Email address for user " + userId + ": " + email + "");
38+
}
39+
```
40+
41+
</CodeTab>
42+
43+
### References
44+
45+
- [Async / Await](/docs/manual/latest/async-await)

0 commit comments

Comments
 (0)