diff --git a/changes/jsoo-6-5-0.internal.md b/changes/jsoo-6-5-0.internal.md new file mode 100644 index 00000000000..341f4a5e319 --- /dev/null +++ b/changes/jsoo-6-5-0.internal.md @@ -0,0 +1 @@ +- Upgrade js_of_ocaml and wasm_of_ocaml to 6.5.0 for a smaller, faster-building playground compiler. diff --git a/dune-project b/dune-project index dafd9675b9a..2611ce4bdd8 100644 --- a/dune-project +++ b/dune-project @@ -47,12 +47,12 @@ (and (<> :os "win32") :with-test - (= 6.4.1))) + (= 6.5.0))) (wasm_of_ocaml-compiler (and (<> :os "win32") :with-test - (= 6.4.1))))) + (= 6.5.0))))) (package (name analysis) diff --git a/packages/playground/scripts/generate_cmijs.mjs b/packages/playground/scripts/generate_cmijs.mjs index 84cb6349fca..614f3d99b8d 100644 --- a/packages/playground/scripts/generate_cmijs.mjs +++ b/packages/playground/scripts/generate_cmijs.mjs @@ -54,8 +54,54 @@ function buildCmij(pkgDir, pkgName) { fs.mkdirSync(outputFolder, { recursive: true }); const cmijFile = path.join(outputFolder, "cmij.js"); - const inputFiles = fs.readdirSync(libOcamlFolder).filter(isCmij).join(" "); - exec(`js_of_ocaml build-fs -o ${cmijFile} -I ${libOcamlFolder} ${inputFiles}`); + const files = fs + .readdirSync(libOcamlFolder) + .filter(isCmij) + .map(basename => { + const bytes = fs.readFileSync(path.join(libOcamlFolder, basename)); + return ` a("/static/${basename}", "${jsBytesLiteral(bytes)}");\n`; + }); + + // The same pseudo filesystem file as `js_of_ocaml build-fs` writes. The + // compiler bundle creates the files when it is loaded after it + // (jsoo_create_file), or picks them up when loaded before it (jsoo_fs_tmp). + // We write it ourselves because since js_of_ocaml 6.5.0, build-fs encodes + // the contents in base64, which compresses much worse, and decodes them + // with a runtime primitive that a standalone file cannot reach. + fs.writeFileSync( + cmijFile, + `(function (c) { + "use strict"; + function a(name, content) { + if (c.jsoo_create_file) c.jsoo_create_file(name, content); + else { + if (!c.jsoo_fs_tmp) c.jsoo_fs_tmp = []; + c.jsoo_fs_tmp.push({ name, content }); + } + } +${files.join("")}})(globalThis); +`, + ); +} + +/** + * The contents of a JavaScript string literal with one character per byte, + * which is how js_of_ocaml represents bytes. + * + * @param {Buffer} bytes + * @return {string} + */ +function jsBytesLiteral(bytes) { + let s = ""; + for (let i = 0; i < bytes.length; i++) { + const b = bytes[i]; + if (b === 0x22 || b === 0x5c) s += `\\${String.fromCharCode(b)}`; + else if (b >= 0x20 && b < 0x7f) s += String.fromCharCode(b); + else if (b === 0 && !(bytes[i + 1] >= 0x30 && bytes[i + 1] <= 0x39)) + s += "\\0"; + else s += `\\x${b.toString(16).padStart(2, "0")}`; + } + return s; } /** diff --git a/rescript.opam b/rescript.opam index 808a8041511..cea2b62ff55 100644 --- a/rescript.opam +++ b/rescript.opam @@ -22,8 +22,8 @@ depends: [ "ounit2" {with-test & = "2.2.7"} "odoc" {with-doc} "ocaml-lsp-server" {with-dev-setup & >= "1.23.0"} - "js_of_ocaml" {os != "win32" & with-test & = "6.4.1"} - "wasm_of_ocaml-compiler" {os != "win32" & with-test & = "6.4.1"} + "js_of_ocaml" {os != "win32" & with-test & = "6.5.0"} + "wasm_of_ocaml-compiler" {os != "win32" & with-test & = "6.5.0"} ] build: [ ["dune" "subst"] {dev}