Skip to content

Commit 9130124

Browse files
committed
Add all relevant changes from previous 2020 bundle API
For reference on the previous work in 2020, refer to rescript-lang#4518
1 parent b525837 commit 9130124

File tree

6 files changed

+881
-152
lines changed

6 files changed

+881
-152
lines changed

CONTRIBUTING.md

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,17 @@ This is usually the file you want to create to test certain compile behavior wit
145145
- Verify the output, check in the `jscomp/test/my_file_test.ml` and `jscomp/test/my_file_test.js` to version control. The checked in `.js` file is essential for verifying regressions later on.
146146
- Eventually check in other relevant files changed during the rebuild (depends on your compiler changes).
147147

148-
## Contribute to the BS Playground Bundle
148+
## Contribute to the ReScript Playground Bundle
149149

150150
> Note: These instructions are designed for building the 4.06 based version of ReScript (ReScript v6).
151151
152152
The "Playground bundle" is the BS compiler compiled to JavaScript, including all necessary dependency files (stdlib / belt etc). It is useful for building tools where you want to compile and execute arbitrary Reason / OCaml in the browser.
153153

154-
The ReScript source code is compiled with a tool called [JSOO (js_of_ocaml)](https://ocsigen.org/js_of_ocaml/3.5.1/manual/overview), which uses OCaml bytecode to compile to JavaScript and is part of the bigger OCaml ecosystem. Before we can compile anything, we need to install the required tools (requires [`opam`](https://opam.ocaml.org/doc/Install.html) to be installed):
154+
The ReScript source code is compiled with a tool called [JSOO (js_of_ocaml)](https://ocsigen.org/js_of_ocaml/3.6.0/manual/overview), which uses OCaml bytecode to compile to JavaScript and is part of the bigger OCaml ecosystem.
155+
156+
We actually ship a bytecode version of `js_of_ocaml`, so you actually don't need to install any third party dependencies. This is usually for basic usage if you don't care about the compilation speed or a fast feedback loop (e.g. CI).
157+
158+
For faster compilation times, we recommend to install a proper `jsoo` executable:
155159

156160
```sh
157161
# Create the right switch, if not created yet (first install)
@@ -161,18 +165,25 @@ opam switch create 4.06.1
161165
opam switch 4.06.1
162166
eval `opam config env`
163167

164-
opam install js_of_ocaml.3.5.1
168+
opam install js_of_ocaml.3.6.0
169+
```
170+
171+
Additionally, make sure to adapt the `scripts/repl.js` file to use the `js_of_ocaml` binary instead (otherwise you'll continue using the slower bytecode version):
172+
173+
```diff
174+
- e(`${OCAMLRUN} ${JSOO} compile jsc.byte ${jsooFlag}-o exports.js`);
175+
+ e(`js_of_ocaml compile jsc.byte ${jsooFlag}-o exports.js`);
165176
```
166177

167-
### Build the Bundle
178+
### Building the Bundle
168179

169-
The entry point of the JSOO bundle is located in `jscomp/main/jsoo_main.ml` and the script for running JSOO can be found in `scripts/repl.js`. A full clean build can be done like this:
180+
The entry point of the JSOO bundle is located in `jscomp/main/jsoo_refmt_main.ml` and the script for running JSOO can be found in `scripts/repl.js`. A full clean build can be done like this:
170181

171182
```
172183
# We create a target directory for storing the bundle / stdlib files
173184
mkdir playground && mkdir playground/stdlib
174185
175-
# We build the ReScript source code and also the bytecode for jsoo_main.ml
186+
# We build the ReScript source code and also the bytecode for jsoo_refmt_main.ml
176187
node scripts/ninja.js config && node scripts/ninja.js build
177188
178189
# Now we run the repl.js script pointing to our playground directory (note how it needs to be relative to the repl.js file)
@@ -181,7 +192,7 @@ BS_PLAYGROUND=../playground node scripts/repl.js
181192

182193
_Troubleshooting: if ninja build step failed with `Error: cannot find file '+runtime.js'`, make sure `ocamlfind` is installed with `opam install ocamlfind`._
183194

184-
**You should now find following files:**
195+
After a successful compilation, you will find following files in your project:
185196

186197
- `playground/exports.js` -> This is the ReScript compiler, which binds the ReScript API to the `window` object.
187198
- `playground/stdlib/*.js` -> All the ReScript runtime files.
@@ -191,31 +202,28 @@ You can now use the `exports.js` file either directly by using a `<script src="/
191202
```
192203
$ node
193204
> require("./exports.js");
194-
undefined
195-
> let compile_result = ocaml.compile(`Js.log Sys.ocaml_version`); // You can change the code here
196-
undefined
197-
> eval(compile_result);
205+
> let compiler = rescript_compiler.make()
206+
> let result = compiler.rescript.compile(`Js.log(Sys.ocaml_version)`);
207+
> eval(result);
198208
4.06.2+BS
199-
undefined
200209
```
201210

202211
### Playground JS bundle API
203212

204-
As soon as the bundle is loaded, you will get access to following functions (as seen in [`jsoo_main.ml`](jscomp/main/jsoo_main.ml)):
213+
As soon as the bundle is loaded, you will get access to the functions exposed in [`jsoo_refmt_main.ml`](jscomp/refmt/jsoo_refmt_main.ml). Best way to check out the API is by inspecting a compiler instance it either in node, or in the browser:
205214

206-
- `window.ocaml`:
207-
- `compile(code: string)`: Compiles given code
208-
- `shake_compile(code: string)`: Compiles given code with tree-shaking
209-
- `compile_super_errors(code: string)`: Compiles given code and outputs `super_errors` related messages on `console.error`
210-
- `compile_super_errors_ppx_v2(code: string)`: Compiles given code with the React v2 syntax
211-
- `compile_super_errors_ppx_v3(code: string)`: Compiles given code with the React v3 syntax
212-
- `load_module(cmi_path: string, cmi_content: string, cmj_name: string, cmj_content: string)`: Loads a module into the compiler (see notes on `cmj` / `cmi` below)
215+
```
216+
$ node
217+
require('./exports.js')
218+
219+
> let compiler = rescript_compiler.make()
220+
> console.log(compiler)
221+
```
213222

214-
For each compile every successful operation will return `{js_code: string}`. On compile errors, the returned object will be `{js_error_msg: string}`.
215223

216224
### Working on the Playground JS API
217225

218-
Whenever you are modifying any files in the ReScript compiler, or in the `jsoo_main.ml` file, you'll need to rebuild the source and recreate the JS bundle.
226+
Whenever you are modifying any files in the ReScript compiler, or in the `jsoo_refmt_main.ml` file, you'll need to rebuild the source and recreate the JS bundle.
219227

220228
```sh
221229
node scripts/ninja.js config && node scripts/ninja.js build

jscomp/main/jsoo_common.ml

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,70 @@
1+
(*
2+
* This module extracts most JSOO externals from the upstream jsoo `js.ml` file.
3+
* See: https://github.com/ocsigen/js_of_ocaml/blob/master/lib/js_of_ocaml/js.ml
4+
*)
15
module Js = struct
26
module Unsafe = struct
37
type any
48
external inject : 'a -> any = "%identity"
59
external get : 'a -> 'b -> 'c = "caml_js_get"
610
external set : 'a -> 'b -> 'c -> unit = "caml_js_set"
711
external pure_js_expr : string -> 'a = "caml_pure_js_expr"
12+
external fun_call : 'a -> any array -> 'b = "caml_js_fun_call"
813
let global = pure_js_expr "joo_global_object"
914
type obj
1015
external obj : (string * any) array -> obj = "caml_js_object"
1116
end
1217
type (-'a, +'b) meth_callback
1318
type 'a callback = (unit, 'a) meth_callback
19+
1420
external wrap_callback : ('a -> 'b) -> ('c, 'a -> 'b) meth_callback = "caml_js_wrap_callback"
1521
external wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback = "caml_js_wrap_meth_callback"
22+
1623
type + 'a t
24+
1725
type js_string
1826
external string : string -> js_string t = "caml_js_from_string"
1927
external to_string : js_string t -> string = "caml_js_to_string"
28+
29+
type 'a js_array
30+
external array : 'a array -> 'a js_array = "caml_js_from_array"
31+
32+
external bool : bool -> bool t = "caml_js_from_bool"
33+
external to_bool : bool t -> bool = "caml_js_to_bool"
34+
35+
type number
36+
external number_of_float : float -> number t = "caml_js_from_float"
37+
external float_of_number : number t -> float = "caml_js_to_float"
38+
2039
external create_file : js_string t -> js_string t -> unit = "caml_create_file"
2140
external to_bytestring : js_string t -> string = "caml_js_to_byte_string"
2241
end
2342

43+
module Sys_js = struct
44+
external set_channel_output' :
45+
out_channel -> (Js.js_string Js.t -> unit) Js.callback -> unit
46+
= "caml_ml_set_channel_output"
47+
48+
let set_channel_flusher (out_channel : out_channel) (f : string -> unit) =
49+
let f' : (Js.js_string Js.t -> unit) Js.callback =
50+
Js.wrap_callback (fun s -> f (Js.to_bytestring s))
51+
in
52+
set_channel_output' out_channel f'
53+
end
54+
2455
let mk_js_error (loc: Location.t) (msg: string) =
2556
let (_file,line,startchar) = Location.get_pos_info loc.Location.loc_start in
2657
let (_file,endline,endchar) = Location.get_pos_info loc.Location.loc_end in
2758
Js.Unsafe.(obj
28-
[|
29-
"js_error_msg",
30-
inject @@ Js.string (Printf.sprintf "Line %d, %d:\n %s" line startchar msg);
31-
"row" , inject (line - 1);
32-
"column" , inject startchar;
33-
"endRow" , inject (endline - 1);
34-
"endColumn" , inject endchar;
35-
"text" , inject @@ Js.string msg;
36-
"type" , inject @@ Js.string "error"
37-
|]
38-
)
59+
[|
60+
"js_error_msg",
61+
inject @@ Js.string (Printf.sprintf "Line %d, %d:\n %s" line startchar msg);
62+
"row" , inject (line - 1);
63+
"column" , inject startchar;
64+
"endRow" , inject (endline - 1);
65+
"endColumn" , inject endchar;
66+
"text" , inject @@ Js.string msg;
67+
"type" , inject @@ Js.string "error"
68+
|]
69+
)
70+

jscomp/main/jsoo_common.mli

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,57 @@
11
(**
2-
This module is shared between different JSOO / Playground based modules
2+
This module is shared between different JSOO / Playground based modules
33
*)
44
module Js :
5-
sig
6-
module Unsafe :
75
sig
8-
type any
9-
external inject : 'a -> any = "%identity"
10-
external get : 'a -> 'b -> 'c = "caml_js_get"
11-
external set : 'a -> 'b -> 'c -> unit = "caml_js_set"
12-
external pure_js_expr : string -> 'a = "caml_pure_js_expr"
13-
val global : 'a
14-
type obj
15-
external obj : (string * any) array -> obj = "caml_js_object"
6+
module Unsafe :
7+
sig
8+
type any
9+
external inject : 'a -> any = "%identity"
10+
external get : 'a -> 'b -> 'c = "caml_js_get"
11+
external set : 'a -> 'b -> 'c -> unit = "caml_js_set"
12+
external pure_js_expr : string -> 'a = "caml_pure_js_expr"
13+
external fun_call : 'a -> any array -> 'b = "caml_js_fun_call"
14+
val global : 'a
15+
type obj
16+
external obj : (string * any) array -> obj = "caml_js_object"
17+
end
18+
19+
type (-'a, +'b) meth_callback
20+
type 'a callback = (unit, 'a) meth_callback
21+
22+
external wrap_callback : ('a -> 'b) -> ('c, 'a -> 'b) meth_callback
23+
= "caml_js_wrap_callback"
24+
external wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback
25+
= "caml_js_wrap_meth_callback"
26+
27+
type +'a t
28+
29+
type js_string
30+
external string : string -> js_string t = "caml_js_from_string"
31+
external to_string : js_string t -> string = "caml_js_to_string"
32+
33+
type 'a js_array
34+
external array : 'a array -> 'a js_array = "caml_js_from_array"
35+
36+
external bool : bool -> bool t = "caml_js_from_bool"
37+
external to_bool : bool t -> bool = "caml_js_to_bool"
38+
39+
type number
40+
external number_of_float : float -> number t = "caml_js_from_float"
41+
external float_of_number : number t -> float = "caml_js_to_float"
42+
43+
external create_file : js_string t -> js_string t -> unit
44+
= "caml_create_file"
45+
external to_bytestring : js_string t -> string = "caml_js_to_byte_string"
46+
1647
end
17-
type (-'a, +'b) meth_callback
18-
type 'a callback = (unit, 'a) meth_callback
19-
external wrap_callback : ('a -> 'b) -> ('c, 'a -> 'b) meth_callback
20-
= "caml_js_wrap_callback"
21-
external wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback
22-
= "caml_js_wrap_meth_callback"
23-
type +'a t
24-
type js_string
25-
external string : string -> js_string t = "caml_js_from_string"
26-
external to_string : js_string t -> string = "caml_js_to_string"
27-
external create_file : js_string t -> js_string t -> unit
28-
= "caml_create_file"
29-
external to_bytestring : js_string t -> string = "caml_js_to_byte_string"
48+
49+
module Sys_js :
50+
sig
51+
val set_channel_flusher : out_channel -> (string -> unit) -> unit
52+
(** Set a callback to be called when an out_channel flush its buffer.
53+
[set_channel_flusher chan cb] install the callback [cb] for [chan] out_channel.
54+
[cb] will be called with the string to flush. *)
3055
end
3156

3257
(*

0 commit comments

Comments
 (0)