diff --git a/.gitignore b/.gitignore index ce60ae7fe7..dc6053a44d 100644 --- a/.gitignore +++ b/.gitignore @@ -154,4 +154,5 @@ playground/packages/ playground/stdlib/ playground/*.cmj playground/*.cmi +playground/.netrc playground/compiler.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21e11bcd65..c5db55b8a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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** @@ -307,11 +307,23 @@ 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? + +JSOO offers an `build-fs` subcommand that takes a list of `.cmi` and `.cmj` files and creates a `cmij.js` file that can be loaded by the JS runtime **after** the `compiler.js` bundle has been loaded (either via a `require()` call in Node, or via `` directive in an HTML file). Since we are shipping our playground with third party modules like `RescriptReact`, we created a utility directory `packages/playground-bundling` that comes with a utility script to do the `cmij.js` file creation for us. 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 diff --git a/playground/playground_test.js b/playground/playground_test.js index fa8a325c9b..6e7b5d7ec7 100644 --- a/playground/playground_test.js +++ b/playground/playground_test.js @@ -1,5 +1,5 @@ require("./compiler.js") -require("./@rescript/react/cmij.js") +require("./packages/@rescript/react/cmij.js") let compiler = rescript_compiler.make() @@ -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 --'); } diff --git a/playground/upload_bundle.sh b/playground/upload_bundle.sh new file mode 100755 index 0000000000..da91e4c164 --- /dev/null +++ b/playground/upload_bundle.sh @@ -0,0 +1,51 @@ +#/usr/bin/sh + +# This script will publish the compiler.js bundle / packages cmij.js files to our KeyCDN server. +# The target folder on KeyCDN will be the compiler.js' version number. +# This script requires `curl` / `openssl` to be installed. + +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 + + + +