Skip to content
Draft
22 changes: 13 additions & 9 deletions esbuild.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { build } from "esbuild";

function config({ format, minify, ext = "js" }) {
function config({ format, minify, input, ext = "js" }) {
const dir = `dist/${format}/`;
const minifierSuffix = minify ? ".min" : "";
const globalName = format === "iife" ? "Synclink" : undefined;
return build({
entryPoints: [`./src/synclink.ts`],
outfile: `${dir}/synclink${minifierSuffix}.${ext}`,
entryPoints: [`./src/${input}.ts`],
outfile: `${dir}/${input}${minifierSuffix}.${ext}`,
bundle: true,
minify,
keepNames: true,
Expand All @@ -17,10 +17,14 @@ function config({ format, minify, ext = "js" }) {
}

[
{ format: "esm", minify: false, ext: "mjs" },
{ format: "esm", minify: true, ext: "mjs" },
{ format: "iife", minify: false },
{ format: "iife", minify: true },
{ format: "cjs", minify: false },
{ format: "cjs", minify: true },
{ input: "synclink", format: "esm", minify: false, ext: "mjs" },
{ input: "synclink", format: "esm", minify: true, ext: "mjs" },
{ input: "synclink", format: "iife", minify: false },
{ input: "synclink", format: "iife", minify: true },
{ input: "synclink", format: "cjs", minify: false },
{ input: "synclink", format: "cjs", minify: true },
{ input: "node-adapter", format: "esm", minify: false, ext: "mjs" },
{ input: "node-adapter", format: "esm", minify: true, ext: "mjs" },
{ input: "node-adapter", format: "cjs", minify: false },
{ input: "node-adapter", format: "cjs", minify: true },
].map(config);
13 changes: 10 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@
"types": "dist/types/synclink.d.ts",
"exports": {
".": {
"types": "./dist/types/synclink.d.ts",
"require": "./dist/cjs/synclink.js",
"import": "./dist/esm/synclink.mjs"
},
"./*": {
"types": "./dist/types/*.d.ts",
"require": "./dist/cjs/*.js",
"import": "./dist/esm/*.mjs"
}
},
"sideEffects": false,
Expand All @@ -17,6 +23,7 @@
"rimraf": "rimraf ./dist",
"tsc": "tsc --outDir ./dist/types",
"test:unit": "karma start",
"test:node": "mocha ./tests/node/main.mjs",
"test:types": "tsc -p ./tests/tsconfig.json",
"test:types:watch": "npm run test:types -- --watch",
"test": "npm run build && npm run test:types && npm run test:unit",
Expand All @@ -37,7 +44,7 @@
},
"license": "Apache-2.0",
"devDependencies": {
"chai": "4.2.0",
"chai": "^4.3.7",
"conditional-type-checks": "1.0.5",
"esbuild": "^0.17.15",
"husky": "4.2.5",
Expand All @@ -50,9 +57,9 @@
"karma-mocha": "^2.0.1",
"karma-safari-launcher": "1.0.0",
"karma-safaritechpreview-launcher": "2.0.2",
"mocha": "^7.2.0",
"mocha": "^10.2.0",
"prettier": "2.0.5",
"rimraf": "3.0.2",
"typescript": "4.8"
"typescript": "4.9.4"
}
}
7 changes: 6 additions & 1 deletion src/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,9 @@ class _Syncifier {

pollTasks(task?: SynclinkTask<any>): boolean {
let result = false;
if (!task && this.tasks.size < 1) {
return true;
}
for (let wokenTaskId of this.tasksIdsToWakeup()) {
// console.log("poll task", wokenTaskId, "looking for",task);
let wokenTask = this.tasks.get(wokenTaskId);
Expand Down Expand Up @@ -398,7 +401,9 @@ export let Syncifier = new _Syncifier();

(async function syncifyPollLoop() {
while (true) {
Syncifier.pollTasks();
if (Syncifier.pollTasks()) {
return;
}
await sleep(20);
}
})();
55 changes: 55 additions & 0 deletions tests/node/main.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Worker, MessageChannel } from "node:worker_threads";
import * as Synclink from "../../dist/esm/synclink.mjs";
import nodeEndpoint from "../../dist/esm/node-adapter.mjs";
import { expect } from "chai";

describe("node", () => {
describe("Synclink across workers", function () {
beforeEach(function () {
const worker = new Worker("./tests/node/worker.mjs");
this.worker = worker;
});

afterEach(async function () {
await this.worker.terminate();
});

it("can communicate", async function () {
const proxy = Synclink.wrap(nodeEndpoint(this.worker));
expect(await proxy(1, 3)).to.equal(4);
});

it("can work with objects + syncify in same thread", function () {
let fakePort1, fakePort2;
const { port1, port2 } = new MessageChannel();
({ port1: fakePort1, port2: fakePort2 } =
new Synclink.FakeMessageChannel());
port1.start();
port2.start();
const thing = Synclink.wrap(fakePort1);
Synclink.expose(
{
value: 4,
func(n) {
return n + 10;
},
},
fakePort2,
);
expect(thing.value.syncify()).to.equal(4);
expect(thing.func(5).syncify()).to.equal(15);
});

it("can communicate synchronously", async function () {
const proxy = Synclink.wrap(nodeEndpoint(this.worker));
expect(proxy(2, 4).syncify()).to.equal(6);
});

it("can tunnels a new endpoint with createEndpoint", async function () {
const proxy = Synclink.wrap(nodeEndpoint(this.worker));
const otherEp = await proxy[Synclink.createEndpoint]();
const otherProxy = Synclink.wrap(otherEp);
expect(await otherProxy(20, 1)).to.equal(21);
});
});
});
5 changes: 5 additions & 0 deletions tests/node/worker.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { parentPort } from "node:worker_threads";
import * as Synclink from "../../dist/esm/synclink.mjs";
import nodeEndpoint from "../../dist/esm/node-adapter.mjs";

Synclink.expose((a, b) => Promise.resolve(a + b), nodeEndpoint(parentPort));
7 changes: 7 additions & 0 deletions tests/worker.comlink.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ describe("Synclink across workers", function () {
expect(await proxy(1, 3)).to.equal(4);
});

it("returns type error with syncify in main thread", async function () {
const proxy = Synclink.wrap(this.worker);
expect(() => {
proxy(2, 4).syncify();
}).to.throw("Atomics.wait cannot be called in this context");
});

it("can tunnels a new endpoint with createEndpoint", async function () {
const proxy = Synclink.wrap(this.worker);
const otherEp = await proxy[Synclink.createEndpoint]();
Expand Down