Skip to content

Commit

Permalink
Publish a proper dual ESM/CJS package, with Node.js and browser support
Browse files Browse the repository at this point in the history
  • Loading branch information
sandhose committed Nov 19, 2024
1 parent fceea46 commit 51fccce
Show file tree
Hide file tree
Showing 14 changed files with 1,102 additions and 325 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
},
rules: {
camelcase: ["error", { properties: "never" }],
Expand Down
3 changes: 0 additions & 3 deletions babel.config.cjs

This file was deleted.

34 changes: 34 additions & 0 deletions index.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const wasm = require("./pkg/matrix_sdk_crypto_wasm_bg.cjs");
const moduleUrl = require.resolve("./pkg/matrix_sdk_crypto_wasm_bg.wasm");

let mod;
async function loadModule() {
if (mod) return mod;

if (typeof WebAssembly.compileStreaming === "function") {
mod = await WebAssembly.compileStreaming(fetch(moduleUrl));
return mod;
}

// Fallback to fetch and compile
const response = await fetch(moduleUrl);
if (!response.ok) {
throw new Error(`Failed to fetch wasm module: ${moduleUrl}`);
}
mod = await WebAssembly.compile(response);
return mod;
}

module.exports = {
// Re-export everything from the wasm module bindings
...wasm,

async initAsync() {
const module = await loadModule();
const instance = new WebAssembly.Instance(module, {
"./matrix_sdk_crypto_wasm_bg.js": wasm,
});
wasm.__wbg_set_wasm(instance.exports);
instance.exports.__wbindgen_start();
},
};
33 changes: 31 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,31 @@
export * from "./pkg/matrix_sdk_crypto_wasm.js";
export { default as initAsync } from "./pkg/matrix_sdk_crypto_wasm.js";
export * from "./pkg/matrix_sdk_crypto_wasm_bg.js";
import * as wasm from "./pkg/matrix_sdk_crypto_wasm_bg.js";

const moduleUrl = new URL("./pkg/matrix_sdk_crypto_wasm_bg.wasm", import.meta.url);

let mod;
async function loadModule() {
if (mod) return mod;

if (typeof WebAssembly.compileStreaming === "function") {
mod = await WebAssembly.compileStreaming(fetch(moduleUrl));
return mod;
}

// Fallback to fetch and compile
const response = await fetch(moduleUrl);
if (!response.ok) {
throw new Error(`Failed to fetch wasm module: ${moduleUrl}`);
}
mod = await WebAssembly.compile(response);
return mod;
}

export async function initAsync() {
const mod = await loadModule();
const instance = new WebAssembly.Instance(mod, {
"./matrix_sdk_crypto_wasm_bg.js": wasm,
});
wasm.__wbg_set_wasm(instance.exports);
instance.exports.__wbindgen_start();
}
24 changes: 24 additions & 0 deletions node.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const fs = require("node:fs");
const path = require("node:path");
const wasm = require("./pkg/matrix_sdk_crypto_wasm_bg.cjs");

const filename = path.join(__dirname, "pkg/matrix_sdk_crypto_wasm_bg.wasm");

// In Node environments, we need to load the WASM module synchronously, as
// the test suite in matrix-js-sdk don't call `initAsync`
const bytes = fs.readFileSync(filename);
const mod = new WebAssembly.Module(bytes);
const instance = new WebAssembly.Instance(mod, {
"./matrix_sdk_crypto_wasm_bg.js": wasm,
});
wasm.__wbg_set_wasm(instance.exports);
instance.exports.__wbindgen_start();

module.exports = {
// Re-export everything from the wasm module bindings
...wasm,

async initAsync() {
// NO OP, as we load the WASM module synchronously in Node environments.
},
};
25 changes: 17 additions & 8 deletions node.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
export * from "./pkg/matrix_sdk_crypto_wasm.js";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
export * from "./pkg/matrix_sdk_crypto_wasm_bg.js";
import * as wasm from "./pkg/matrix_sdk_crypto_wasm_bg.js";

import { initSync } from "./pkg/matrix_sdk_crypto_wasm.js";
const filename = fileURLToPath(new URL("./pkg/matrix_sdk_crypto_wasm_bg.wasm", import.meta.url));

import { readFile } from "node:fs/promises";
// In Node environments, we need to load the WASM module synchronously, as
// the test suite in matrix-js-sdk don't call `initAsync`
const bytes = readFileSync(filename);
const mod = new WebAssembly.Module(bytes);
const instance = new WebAssembly.Instance(mod, {
"./matrix_sdk_crypto_wasm_bg.js": wasm,
});
wasm.__wbg_set_wasm(instance.exports);
instance.exports.__wbindgen_start();

export const initAsync = async () => {
const bytes = await readFile("./pkg/matrix_sdk_crypto_wasm_bg.wasm");
const module = await WebAssembly.compile(bytes);
initSync({ module });
};
export async function initAsync() {
// NO OP, as we load the WASM module synchronously in Node environments.
}
29 changes: 21 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,38 @@
],
"exports": {
".": {
"node": "./node.js",
"node": {
"require": "./node.cjs",
"import": "./node.js"
},
"require": "./index.cjs",
"import": "./index.js",
"types": "./index.d.ts"
}
},
"files": [
"index.js",
"index.cjs",
"index.d.ts",
"node.js",
"pkg/matrix_sdk_crypto_wasm.js",
"pkg/matrix_sdk_crypto_wasm.js",
"node.cjs",
"pkg/matrix_sdk_crypto_wasm.d.ts",
"pkg/matrix_sdk_crypto_wasm_bg.js",
"pkg/matrix_sdk_crypto_wasm_bg.cjs",
"pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts",
"pkg/matrix_sdk_crypto_wasm_bg.wasm"
],
"devDependencies": {
"@babel/cli": "^7.25.9",
"@babel/core": "^7.26.0",
"@babel/plugin-transform-modules-commonjs": "^7.25.9",
"@tsconfig/node-lts": "^22.0.0",
"@types/node": "^22.9.0",
"eslint": "^8.55.0",
"fake-indexeddb": "^4.0",
"prettier": "^2.8.3",
"typedoc": "^0.22.17",
"typescript": "4.7",
"fake-indexeddb": "^6.0.0",
"prettier": "^3.3.3",
"typedoc": "^0.26.11",
"typescript": "5.6.3",
"vitest": "^2.1.5",
"wasm-pack": "^0.13.1"
},
Expand All @@ -57,5 +69,6 @@
"test": "vitest run && yarn run wasm-pack test --node",
"doc": "typedoc --tsconfig .",
"prepack": "npm run build && npm run test"
}
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
23 changes: 18 additions & 5 deletions scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,24 @@
# Build the JavaScript modules
#

set -e
set -eux

cd "$(dirname "$0")"/..

# --no-pack disables generation of a `package.json` file. Such a file is
# useless to us (our package uses the hand-written one in the root directory),
# and contains incorrect data (our `main` is `index.js`).
exec wasm-pack build --no-pack --target web --scope matrix-org --out-dir pkg --weak-refs "${WASM_PACK_ARGS}"
WASM_PACK_ARGS="${WASM_PACK_ARGS:-}"

rm -rf pkg

# Generate the JavaScript bindings
wasm-pack build --no-pack --target bundler --scope matrix-org --out-dir pkg --weak-refs "${WASM_PACK_ARGS}"

# This will output two important files:
# - pkg/matrix_sdk_crypto_wasm.js
# - pkg/matrix_sdk_crypto_wasm_bg.js
#
# We're only interested in the last one, as the first one is the loader,
# and the output from wasm-bindgen doesn't work well on all platforms, so we ship our own loader.
# We still want to convert the last one to CommonJS, so we ship a proper dual commonjs/es6 module.

babel pkg/matrix_sdk_crypto_wasm_bg.js --out-dir pkg --out-file-extension .cjs --plugins @babel/plugin-transform-modules-commonjs
rm pkg/matrix_sdk_crypto_wasm.js
8 changes: 0 additions & 8 deletions scripts/epilogue.d.ts

This file was deleted.

1 change: 0 additions & 1 deletion scripts/epilogue.js

This file was deleted.

3 changes: 3 additions & 0 deletions tests/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare module "../index.js" {
export * from "../index.d.ts";
}
2 changes: 1 addition & 1 deletion tests/machine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ describe(OlmMachine.name, () => {
try {
const decryptionSettings = new DecryptionSettings(TrustRequirement.Untrusted);
await m.decryptRoomEvent(JSON.stringify(evt), room, decryptionSettings);
fail("it should not reach here");
expect.fail("it should not reach here");
} catch (err) {
expect(err).toBeInstanceOf(MegolmDecryptionError);
expect((err as MegolmDecryptionError).code).toStrictEqual(DecryptionErrorCode.UnableToDecrypt);
Expand Down
8 changes: 6 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{
"extends": "@tsconfig/node-lts/tsconfig.json",
"compilerOptions": {
"strict": true
"lib": ["dom"],
"allowJs": true,
"baseUrl": "."
},
"include": ["index.d.ts", "tests/global.d.ts", "tests/**/*.d.ts"],
"typedocOptions": {
"entryPoints": ["pkg/matrix_sdk_crypto_wasm.d.ts"],
"entryPoints": ["index.d.ts"],
"out": "docs",
"readme": "README.md"
}
Expand Down
Loading

0 comments on commit 51fccce

Please sign in to comment.