diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index c7b53a016..dcebaa9e6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -4,6 +4,8 @@ on: [push, pull_request] jobs: unit-tests: + env: + WIREIT_LOGGER: simple runs-on: ubuntu-latest timeout-minutes: 10 steps: diff --git a/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer-worker.ts b/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer-worker.ts index 94fdf759e..0dca89e37 100644 --- a/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer-worker.ts +++ b/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer-worker.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -import * as workerthreads from 'worker_threads'; +import {isMainThread, parentPort} from 'worker_threads'; import {Renderer} from './renderer.js'; import { WorkerMessage, @@ -13,12 +13,12 @@ import { Shutdown, } from './blocking-renderer.js'; -if (workerthreads.isMainThread || !workerthreads.parentPort) { +if (isMainThread || !parentPort) { throw new Error('BlockingRenderer worker must be spawned in a worker thread'); } const rendererPromise = Renderer.start(); -const encoder = new TextEncoder(); +// const encoder = new TextEncoder(); let shuttingDown = false; let sharedDataResolve: (value: HandshakeMessage) => void; @@ -28,7 +28,7 @@ let sharedDataPromise = new Promise((resolve) => { const unreachable = (_x: never, msg: string) => new Error(msg); -workerthreads.parentPort.on('message', (msg: WorkerMessage) => { +parentPort.on('message', (msg: WorkerMessage) => { switch (msg.type) { case 'handshake': return onHandshake(msg); @@ -46,22 +46,30 @@ workerthreads.parentPort.on('message', (msg: WorkerMessage) => { const onHandshake = (msg: HandshakeMessage) => { sharedDataResolve(msg); + msg.port.start(); + msg.port.on('message', (msg: Render) => { + return onRender(msg); + }); }; const onRender = async (msg: Render) => { + console.log(`rendering ${msg.code.slice(0, 20)}`); + console.time(`rendered ${msg.code.slice(0, 20)}`); const renderer = await rendererPromise; const {html} = await renderer.render(msg.lang, msg.code); const shared = await sharedDataPromise; - const length = html.length; - if (length > shared.htmlBuffer.length) { - throw new Error( - `Shared HTML buffer was too short ` + - `(${shared.htmlBuffer.length} < ${html.length} bytes)` - ); - } - shared.htmlBufferLength[0] = length; - encoder.encodeInto(html, shared.htmlBuffer); + // const length = html.length; + // if (length > shared.htmlBuffer.length) { + // throw new Error( + // `Shared HTML buffer was too short ` + + // `(${shared.htmlBuffer.length} < ${html.length} bytes)` + // ); + // } + // shared.htmlBufferLength[0] = length; + // encoder.encodeInto(html, shared.htmlBuffer); + shared.port.postMessage(html); Atomics.notify(shared.notify, 0); + console.timeEnd(`rendered ${msg.code.slice(0, 20)}`); }; const onShutdown = async (_msg: Shutdown) => { diff --git a/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer.ts b/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer.ts index 334a9e698..8bbd03e72 100644 --- a/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer.ts +++ b/packages/lit-dev-tools-cjs/src/playground-plugin/blocking-renderer.ts @@ -4,7 +4,12 @@ * SPDX-License-Identifier: BSD-3-Clause */ -import * as workerthreads from 'worker_threads'; +import { + Worker, + MessageChannel, + MessagePort, + receiveMessageOnPort, +} from 'worker_threads'; import * as pathlib from 'path'; export type WorkerMessage = HandshakeMessage | Render | Shutdown; @@ -20,6 +25,7 @@ export interface HandshakeMessage { * each render is done, and the value will always be 0. */ notify: Int32Array; + port: MessagePort; } export interface Render { @@ -34,21 +40,22 @@ export interface Shutdown { export class BlockingRenderer { /** Worker that performs rendering. */ - private worker: workerthreads.Worker; + private worker: Worker; /** Shared memory that the worker will write render results into. */ private sharedHtml: Uint8Array; /** Shared memory that the worker will set to the result length. */ private sharedLength = new Int32Array(new SharedArrayBuffer(4)); /* Shared memory for done notifications. */ private sharedNotify = new Int32Array(new SharedArrayBuffer(4)); - private decoder = new TextDecoder(); + // private decoder = new TextDecoder(); private exited = false; private renderTimeout: number; + private port: MessagePort; constructor({renderTimeout = 60_000, maxHtmlBytes = 1024 * 1024} = {}) { this.renderTimeout = renderTimeout; this.sharedHtml = new Uint8Array(new SharedArrayBuffer(maxHtmlBytes)); - this.worker = new workerthreads.Worker( + this.worker = new Worker( pathlib.join(__dirname, 'blocking-renderer-worker.js') ); this.worker.on('error', (error) => { @@ -64,12 +71,26 @@ export class BlockingRenderer { ); } }); - this.workerPost({ - type: 'handshake', - htmlBufferLength: this.sharedLength, - htmlBuffer: this.sharedHtml, - notify: this.sharedNotify, - }); + const {port1, port2} = new MessageChannel(); + this.port = port1; + this.port.start(); + // this.workerPost({ + // type: 'handshake', + // htmlBufferLength: this.sharedLength, + // htmlBuffer: this.sharedHtml, + // notify: this.sharedNotify, + // port: port2 + // }); + this.worker.postMessage( + { + type: 'handshake', + htmlBufferLength: this.sharedLength, + htmlBuffer: this.sharedHtml, + notify: this.sharedNotify, + port: port2, + }, + [port2] + ); } async stop(): Promise { @@ -86,7 +107,9 @@ export class BlockingRenderer { if (this.exited) { throw new Error('BlockingRenderer worker has already exited'); } - this.workerPost({type: 'render', lang, code}); + this.port.postMessage({type: 'render', lang, code}); + // this.workerPost({type: 'render', lang, code}); + console.log(`posted ${code.slice(0, 20)}`); if ( Atomics.wait(this.sharedNotify, 0, 0, this.renderTimeout) === 'timed-out' ) { @@ -94,10 +117,11 @@ export class BlockingRenderer { `BlockingRenderer timed out waiting for worker to render ${lang}` ); } - const raw = this.decoder.decode(this.sharedHtml); - const length = this.sharedLength[0]; - const html = raw.substring(0, length); - return {html}; + const {message} = receiveMessageOnPort(this.port)!; + // const raw = this.decoder.decode(this.sharedHtml); + // const length = this.sharedLength[0]; + // const html = raw.substring(0, length); + return {html: message}; } private workerPost(message: WorkerMessage) {