Skip to content

Commit bb7b40c

Browse files
authored
Merge pull request #3972 from ryyppy/jsoo-406
Upgrade repl.js to 4.06.1
2 parents e2ccc53 + 5ce8936 commit bb7b40c

File tree

6 files changed

+472
-329
lines changed

6 files changed

+472
-329
lines changed

CONTRIBUTING.md

Lines changed: 127 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,10 @@ help!
142142
Each new PR should include appropriate testing.
143143

144144
Currently all tests are located in the `jscomp/test` directory and you should
145-
either add / update test files according to your changes to the compiler.
145+
either add / update test files according to your changes to the compiler.
146146

147147
There are currently two formats for test files:
148+
148149
1. Proper mocha test files with executed javascript test code
149150
2. Plain `.ml` files which are only supposed to be compiled to JS (without any logic validation)
150151

@@ -178,19 +179,140 @@ This is usually the file you want to create to test certain compile behavior
178179
without running the JS code formally as a test, i.e. if you add a new type
179180
alias to a specific module and you just want to make sure the compiler handles
180181
the types correctly (see
181-
[`jscomp/test/empty_obj.ml`](jscomp/test/empty_obj.ml) as an example).
182+
[`jscomp/test/empty_obj.ml`](jscomp/test/empty_obj.ml) as an example).
182183

183184
- Create your test file `jscomp/test/my_file_test.ml`. Make sure to end the
184185
file name with `_test.ml`.
185186

186-
- Build the `.js` artifact: `node scripts/ninja.js config && node
187-
scripts/ninja.js build`
187+
- Build the `.js` artifact: `node scripts/ninja.js config && node scripts/ninja.js build`
188188
- Verify the output, check in the `jscomp/test/my_file_test.ml` and `jscomp/test/my_file_test.js` to
189189
version control. The checked in `.js` file is essential for verifying
190190
regressions later on.
191191
- Eventually check in other relevant files changed during the rebuild (depends on
192192
your compiler changes)
193193

194+
## Contributing to the BS Playground Bundle
195+
196+
> Note: These instructions are designed for building the 4.06 based version of BuckleScript (BS v6)
197+
198+
The "BuckleScript Playground bundle" is the BS compiler compiled to JavaScript, including all necessary dependency files (stdlib / belt etc).
199+
It is useful for building tools where you want to compile and execute arbitrary Reason / OCaml in the browser.
200+
201+
The BuckleScript 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
202+
bytecode to compile to JavaScript and is part of the bigger OCaml ecosystem. Before we can compile anything, we need to install the required
203+
tools (requires [`opam`](https://opam.ocaml.org/doc/Install.html) to be installed):
204+
205+
```
206+
# Create the right switch, if not created yet (first install)
207+
opam switch create 4.06.1
208+
209+
# Makes sure to be on the right switch
210+
opam switch 4.06.1
211+
eval `opam config env`
212+
213+
opam install js_of_ocaml.3.5.1
214+
```
215+
216+
### Building the bundle
217+
218+
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`.
219+
A full clean build can be done like this:
220+
221+
```
222+
# We create a target directory for storing the bundle / stdlib files
223+
mkdir playground && mkdir playground/stdlib
224+
225+
# We build the BuckleScript source code and also the bytecode for jsoo_main.ml
226+
node scripts/ninja.js config && node scripts/ninja.js build
227+
228+
# Now we run the repl.js script pointing to our playground directory (note how it needs to be relative to the repl.js file)
229+
BS_PLAYGROUND=../playground node scripts/repl.js
230+
```
231+
232+
**You should now find following files:**
233+
234+
- `playground/exports.js` -> This is the BuckleScript compiler, which binds the BuckleScript API to the `window` object
235+
- `playground/stdlib/*.js` -> All the BuckleScript runtime files
236+
237+
You can now use the `exports.js` file either directly by using a `<script src="/path/to/exports.js"/>` inside a html file, use a browser bundler infrastructure to optimize it, or you can even use it with `nodejs`:
238+
239+
```
240+
$ node
241+
> require("./exports.js");
242+
undefined
243+
> let compile_result = ocaml.compile(`Js.log Sys.ocaml_version`); // You can change the code here
244+
undefined
245+
> eval(compile_result);
246+
4.06.2+BS
247+
undefined
248+
```
249+
250+
### Playground JS bundle API
251+
252+
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)):
253+
254+
- `window.ocaml`:
255+
- `compile(code: string)`: Compiles given code
256+
- `shake_compile(code: string)`: Compiles given code with tree-shaking
257+
- `compile_super_errors(code: string)`: Compiles given code and outputs `super_errors` related messages on `console.error`
258+
- `compile_super_errors_ppx_v2(code: string)`: Compiles given code with the React v2 syntax
259+
- `compile_super_errors_ppx_v3(code: string)`: Compiles given code with the React v3 syntax
260+
- `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)
261+
262+
For each compile every successful operation will return `{js_code: string}`.
263+
On compile errors, the returned object will be `{js_error_msg: string}`.
264+
265+
### Working on the Playground JS API
266+
267+
Whenever you are modifying any files in the BuckleScript compiler, or in the `jsoo_main.ml` file, you'll need to rebuild the source and recreate the JS bundle.
268+
269+
```
270+
node scripts/ninja.js config && node scripts/ninja.js build
271+
BS_PLAYGROUND=../playground node scripts/repl.js
272+
```
273+
274+
**.cmj files in the Web**
275+
276+
A `.cmj` file contains compile information and JS package information of
277+
BuckleScript build artifacts (your `.re / .ml` modules) and are generated on
278+
build (`scripts/ninja.js build`).
279+
280+
A `.cmi` file is an [OCaml originated file
281+
extension](https://waleedkhan.name/blog/ocaml-file-extensions/) and contains all
282+
interface information of a certain module without any implementation.
283+
284+
In this repo, these files usually sit right next to each compiled `.ml` / `.re`
285+
file. The structure of a `.cmj` file is defined in
286+
[js_cmj_format.ml](jscomp/core/js_cmj_format.ml). You can run a tool called
287+
`./jscomp/bin/cmjdump.exe [some-file.cmj]` to inspect the contents of given
288+
`.cmj` file.
289+
290+
`.cmj` files are required for making BuckleScript compile modules (this includes
291+
modules like ReasonReact). BuckleScript includes a subset of modules by default,
292+
which can be found in `jscomp/stdlib-406` and `jscomp/others`. You can also find
293+
those modules listed in the `jsoo` call in `scripts/repl.js`. As you probably
294+
noticed, the generated `playground` files are all plain `.js`, so how are the `cmj` /
295+
`cmi` files embedded?
296+
297+
`repl.js` calls an executable called `cmjbrowser.exe` on every build, which is a
298+
compile artifact from `jscomp/main/jscmj_main.ml`. It is used to serialize `cmj`
299+
/ `cmi` artifacts into two files called `jscomp/core/js_cmj_datasets.ml` and
300+
`jscomp/core/js_cmi_datasets.ml`. These files are only linked for the browser
301+
target, where BuckleScript doesn't have access to the filesystem. When working
302+
on BS, you'll see diffs on those files whenever there are changes on core
303+
modules, e.g. stdlib modules or when the ocaml version was changed. We usually
304+
check in these files to keep it in sync with the most recent compiler
305+
implementation. JSOO will pick up those files to encode them into the `exports.js`
306+
bundle.
307+
308+
For any other dependency needed in the playground, such as `ReasonReact`, you
309+
will be required to serialize your `.cmi` / `.cmt` files accordingly from binary
310+
to hex encoded strings so that BS Playground's `ocaml.load` function can
311+
load the data. Right now we don't provide any instructions inside here yet, but
312+
[here's how the official ReasonML playground did
313+
it](https://github.com/reasonml/reasonml.github.io/blob/source/website/setupSomeArtifacts.js#L65).
314+
315+
194316
## Contributing to the Documentation
195317

196318
See https://github.com/BuckleScript/bucklescript.github.io
@@ -281,7 +403,7 @@ Since BuckleScript is distributed under the terms of the [LGPL Version 3](LICENS
281403
are licensed under the same terms. In order for us to be able to accept your contributions,
282404
we will need explicit confirmation from you that you are able and willing to provide them under
283405
these terms, and the mechanism we use to do this is called a Developer's Certificate of Origin
284-
[DCO](DCO.md). This is very similar to the process used by the Linux(R) kernel, Samba, and many
406+
[DCO](DCO.md). This is very similar to the process used by the Linux(R) kernel, Samba, and many
285407
other major open source projects.
286408

287409
To participate under these terms, all that you must do is include a line like the following as the

jscomp/core/js_cmi_datasets.ml

Lines changed: 138 additions & 134 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)