Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,5 @@ playground/packages/
playground/stdlib/
playground/*.cmj
playground/*.cmi
playground/.netrc
playground/compiler.js
22 changes: 18 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ Whenever you are modifying any files in the ReScript compiler, or in the `jsoo_p

```sh
node scripts/ninja.js config && node scripts/ninja.js build
PLAYGROUND=../playground node scripts/repl.js
node scripts/repl.js
```

**.cmj files in the Web**
Expand All @@ -307,11 +307,25 @@ A `.cmi` file is an [OCaml originated file extension](https://waleedkhan.name/bl

In this repo, these files usually sit right next to each compiled `.ml` / `.res` file. The structure of a `.cmj` file is defined in [js_cmj_format.ml](jscomp/core/js_cmj_format.ml). You can run a tool called `./jscomp/bin/cmjdump.exe [some-file.cmj]` to inspect the contents of given `.cmj` file.

`.cmj` files are required for making ReScript compile modules (this includes modules like ReasonReact). ReScript includes a subset of modules by default, which can be found in `jscomp/stdlib-406` and `jscomp/others`. You can also find those modules listed in the `jsoo` call in `scripts/repl.js`. As you probably noticed, the generated `playground` files are all plain `.js`, so how are the `cmj` / `cmi` files embedded?
`.cmj` files are required to compile modules (this includes modules like RescriptReact). ReScript includes a subset of modules by default, which can be found in `jscomp/stdlib-406` and `jscomp/others`. You can also find those modules listed in the `jsoo` call in `scripts/repl.js`. As you probably noticed, the generated `playground` files are all plain `.js`, so how are the `cmj` / `cmi` files embedded?

`repl.js` calls an executable called `cmjbrowser.exe` on every build, which is a compile artifact from `jscomp/main/jscmj_main.ml`. It is used to serialize `cmj` / `cmi` artifacts into two files called `jscomp/core/js_cmj_datasets.ml`. These files are only linked for the browser target, where ReScript doesn't have access to the filesystem. When working on ReScript, you'll see diffs on those files whenever there are changes on core modules, e.g. stdlib modules or when the ocaml version was changed. We usually check in these files to keep it in sync with the most recent compiler implementation. JSOO will pick up those files to encode them into the `compiler.js` bundle.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first few sentences are outdated. cmjbrowser doesn't exist anymore and I currently have no idea how the builtin_datasets files are created. For now I will keep the outdated infos.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would only keep info that is strictly necessary.


For any other dependency needed in the playground, such as `RescriptReact`, you will be required to serialize your `.cmi` / `.cmt` files accordingly from binary to hex encoded strings so that ReScript Playground's `ocaml.load` function can load the data. We use `jsoo`'s builtin functionality to create `cmij.js` files for that. Check out `packages/playground-bundling/scripts/generate_cmijs.js` for details.

### Publishing the Playground Bundle on our KeyCDN

> Note: If you want to publish from your local machine, make sure to set the `KEYCDN_USER` and `KEYCDN_PASSWORD` environment variables accordingly (credentials currently managed by @ryyppy). Our CI servers / GH Action servers are already pre-configured with the right env variable values.

`repl.js` calls an executable called `cmjbrowser.exe` on every build, which is a compile artifact from `jscomp/main/jscmj_main.ml`. It is used to serialize `cmj` / `cmi` artifacts into two files called `jscomp/core/js_cmj_datasets.ml`. These files are only linked for the browser target, where ReScript doesn't have access to the filesystem. When working on BS, you'll see diffs on those files whenever there are changes on core modules, e.g. stdlib modules or when the ocaml version was changed. We usually check in these files to keep it in sync with the most recent compiler implementation. JSOO will pick up those files to encode them into the `compiler.js` bundle.
Our `compiler.js` and third-party packages bundles are hosted on [KeyCDN](https://www.keycdn.com) and uploaded via FTPS.

After a successful bundle build, run our upload script to publish the build artifacts to our server:

```
playground/upload_bundle.sh
```

For any other dependency needed in the playground, such as `ReasonReact`, you will be required to serialize your `.cmi` / `.cmt` files accordingly from binary to hex encoded strings so that BS Playground's `ocaml.load` function can load the data. Right now we don't provide any instructions inside here yet, but [here's how the official ReasonML playground did it](https://github.com/reasonml/reasonml.github.io/blob/source/website/setupSomeArtifacts.js#L65).
The script will automatically detect the ReScript version from the `compiler.js` bundle and automatically create the correct directory structure on our CDN ftp server.

## Contribute to the API Reference

Expand Down
4 changes: 3 additions & 1 deletion playground/playground_test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require("./compiler.js")
require("./@rescript/react/cmij.js")
require("./packages/@rescript/react/cmij.js")

let compiler = rescript_compiler.make()

Expand All @@ -9,6 +9,8 @@ let result = compiler.rescript.compile(`

if(result.js_code != "") {
console.log('-- Playground test output --');
console.log(`ReScript version: ${compiler.rescript.version}`);
console.log('----');
console.log(result.js_code);
console.log('-- Playground test complete --');
}
48 changes: 48 additions & 0 deletions playground/upload_bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#/usr/bin/sh

SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd -P)

# Get the actual version from the compiled playground bundle
VERSION=$(cd $SCRIPT_DIR; node -e 'require("./compiler.js"); console.log(rescript_compiler.make().rescript.version)')

if [ -z "${KEYCDN_USER}" ]; then
echo "KEYCDN_USER environment variable not set. Make sure to set the environment accordingly."
exit 1
fi

if [ -z "${KEYCDN_PASSWORD}" ]; then
echo "KEYCDN_PASSWORD environment variable not set. Make sure to set the environment accordingly."
exit 1
fi

KEYCDN_SRV="ftp.keycdn.com"
NETRC_FILE="${SCRIPT_DIR}/.netrc"


# To make sure to not leak any secrets in the bash history, we create a NETRC_FILE
# with the credentials provided via ENV variables.
if [ ! -f "${NETRC_FILE}" ]; then
echo "No .netrc file found. Creating file '${NETRC_FILE}'"
echo "machine ${KEYCDN_SRV} login $KEYCDN_USER password $KEYCDN_PASSWORD" > "${NETRC_FILE}"
fi

PACKAGES=( "@rescript/react")

echo "Uploading compiler.js file..."
curl --ftp-create-dirs -T "${SCRIPT_DIR}/compiler.js" --ssl --netrc-file $NETRC_FILE ftp://${KEYCDN_SRV}/v${VERSION}/compiler.js

echo "---"
echo "Uploading packages cmij files..."
for dir in ${PACKAGES[@]};
do
SOURCE="${SCRIPT_DIR}/packages/${dir}"
TARGET="ftp://${KEYCDN_SRV}/v${VERSION}/${dir}"

echo "Uploading '$SOURCE/cmij.js' to '$TARGET/cmij.js'..."

curl --ftp-create-dirs -T "${SOURCE}/cmij.js" --ssl --netrc-file $NETRC_FILE "${TARGET}/cmij.js"
done