From eedab933e3131ec164a697bf85bf33a99299e62b Mon Sep 17 00:00:00 2001 From: Daniel Meyer <8926560+pubkey@users.noreply.github.com> Date: Mon, 30 Oct 2023 03:22:02 +0100 Subject: [PATCH] Feature/deno (#1288) * ADD deno support * ADD deno support * ADD docs * FIX lint * FIX test * UPDATE node * FIX check * FIX tests * CLEAR cache * PIN node version --- .github/README.md | 8 ++-- .github/workflows/main.yml | 75 +++++++++++++++++++++++++++++++++++--- CHANGELOG.md | 2 + README.md | 2 +- package.json | 12 +++++- src/methods/native.js | 9 +++++ test/test-deno.js | 34 +++++++++++++++++ 7 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 test/test-deno.js diff --git a/.github/README.md b/.github/README.md index f48a3b00..06f8a1b5 100644 --- a/.github/README.md +++ b/.github/README.md @@ -7,7 +7,7 @@

BroadcastChannel

- A BroadcastChannel to send data across multiple browser-tabs or nodejs-processes + A BroadcastChannel to send data across multiple browser-tabs or nodejs-processes or Deno-Deploy-Instances
+ LeaderElection over the channels

@@ -22,7 +22,7 @@ * * * -A BroadcastChannel that allows you to send data between different browser-tabs or nodejs-processes. +A BroadcastChannel that allows you to send data between different browser-tabs or nodejs-processes or Deno-Deploy-Instances. - It works completely **client-side** and **offline**, - Tested on **old browsers**, **new browsers**, **WebWorkers**, **Iframes** and **NodeJs**. @@ -188,7 +188,7 @@ Depending in which environment this is used, a proper method is automatically se | Method | Used in | Description | | ---------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Native** | [Modern Browsers](https://caniuse.com/broadcastchannel) | If the browser supports the BroadcastChannel-API, this method will be used because it is the fastest | +| **Native** | [Modern Browsers](https://caniuse.com/broadcastchannel) | If the browser supports the BroadcastChannel-API, this method will be used because it is the fastest. This is also used in Deno runtimes. | | **IndexedDB** | [Browsers with WebWorkers](https://caniuse.com/#feat=indexeddb) | If there is no native BroadcastChannel support, the IndexedDB method is used because it supports messaging between browser-tabs, iframes and WebWorkers | | **LocalStorage** | [Older Browsers](https://caniuse.com/#feat=namevalue-storage) | In older browsers that do not support IndexedDb, a localstorage-method is used | | **Sockets** | NodeJs | In NodeJs the communication is handled by sockets that send each other messages | @@ -282,7 +282,7 @@ This module is optimised for: - This is not a polyfill. Do not set this module to `window.BroadcastChannel`. This implementation behaves similiar to the [BroadcastChannel-Standard](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) with these limitations: - You can only send data that can be `JSON.stringify`-ed, - While the offical API emits [onmessage-events](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel/onmessage), this module directly emitts the data which was posted. -- This is not a replacement for a message queue. If you use this in NodeJs and want send more than 50 messages per second, you should use proper [IPC-Tooling](https://en.wikipedia.org/wiki/Message_queue). +- This is not a replacement for a message queue. If you use this in NodeJs or Deno and want send more than 50 messages per second, you should use proper [IPC-Tooling](https://en.wikipedia.org/wiki/Message_queue). ## Browser Support diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 20949a2f..105b77a1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,6 +13,11 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: +# https://stackoverflow.com/a/72408109/3443137 +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" @@ -24,6 +29,10 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v4 + - name: Setup Node.js environment + uses: actions/setup-node@v4.0.0 + with: + node-version: '20.9.0' # https://docs.github.com/en/free-pro-team@latest/actions/guides/caching-dependencies-to-speed-up-workflows - name: Reuse npm cache folder @@ -37,10 +46,10 @@ jobs: ./node_modules ./test-electron/node_modules # invalidate cache when any package.json changes - key: ${{ runner.os }}-npm-x1-${{ env.cache-name }}-${{ hashFiles('**/package.json') }} + key: ${{ runner.os }}-npm-x2-${{ env.cache-name }}-${{ hashFiles('**/package.json') }} restore-keys: | - ${{ runner.os }}-npm-x1-${{ env.cache-name }}- - ${{ runner.os }}-npm-x1- + ${{ runner.os }}-npm-x2-${{ env.cache-name }}- + ${{ runner.os }}-npm-x2- ${{ runner.os }}- # install @@ -89,7 +98,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - node: ['17.3.0', '18.12.1'] + node: ['18.18.2', '20.9.0'] steps: - uses: actions/checkout@v4 - name: Setup Node.js environment @@ -108,9 +117,9 @@ jobs: ./node_modules ./test-electron/node_modules # invalidate cache when any package.json changes - key: ${{ runner.os }}-npm-test-node-x1-${{ matrix.node }}-${{ env.cache-name }}-${{ hashFiles('**/package.json') }} + key: ${{ runner.os }}-npm-test-node-x2-${{ matrix.node }}-${{ env.cache-name }}-${{ hashFiles('**/package.json') }} restore-keys: | - ${{ runner.os }}-npm-test-node-x1-${{ matrix.node }}-${{ env.cache-name }}- + ${{ runner.os }}-npm-test-node-x2-${{ matrix.node }}-${{ env.cache-name }}- ${{ runner.os }}-npm-test-node ${{ runner.os }}-test-node @@ -124,6 +133,60 @@ jobs: run: npm run test:node + test-deno: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js environment + uses: actions/setup-node@v4.0.0 + with: + node-version: '20.9.0' + + # https://docs.github.com/en/free-pro-team@latest/actions/guides/caching-dependencies-to-speed-up-workflows + - name: Reuse npm cache folder + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + path: | + ~/.npm + ./node_modules + ./test-electron/node_modules + # invalidate cache when any package.json changes + key: ${{ runner.os }}-npm-test-deno-x2-${{ env.cache-name }}-${{ hashFiles('**/package.json') }} + restore-keys: | + ${{ runner.os }}-npm-test-deno-x2-${{ env.cache-name }}- + ${{ runner.os }}-npm-test-deno + ${{ runner.os }}-test-deno + + - name: install node modules + run: npm install --legacy-peer-deps + + - name: build + run: npm run build + + - name: Reuse deno cache folder + uses: actions/cache@v3 + env: + cache-name: cache-deno-modules + with: + path: | + /home/runner/.cache/deno + # do not cache based on package.json because deno install randomly fails + # and it would then never succeed on the first run on dependency updateds + key: ${{ runner.os }}-deno-x2- + + - uses: denoland/setup-deno@v1 + with: + # https://github.com/denoland/deno/releases + deno-version: "1.37.2" + - name: run deno tests + run: | + sudo npm i -g cross-env + deno info + npm run test:deno + + # TODO this does not work atm. fix this. # - name: test electron # uses: GabrielBB/xvfb-action@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index e38c004d..438b758c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## X.X.X (comming soon) +- ADD support for the Deno runtime + ## 5.5.1 (23 October 2023) - REPLACE `new Date().getTime()` with `Date.now()` which is faster diff --git a/README.md b/README.md index 6727879d..2dd9184d 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@

BroadcastChannel

- A BroadcastChannel that works in old browsers, new browsers, WebWorkers and NodeJs + A BroadcastChannel that works in old browsers, new browsers, WebWorkers and NodeJs and Deno
+ LeaderElection over the channels

diff --git a/package.json b/package.json index c7631288..17491ae6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "broadcast-channel", "version": "5.5.1", - "description": "A BroadcastChannel that works in New Browsers, Old Browsers, WebWorkers and NodeJs and iframes", + "description": "A BroadcastChannel that works in New Browsers, Old Browsers, WebWorkers, NodeJs, Deno and iframes", "exports": { ".": { "node": { @@ -9,6 +9,11 @@ "import": "./dist/esnode/index.js", "default": "./dist/es5node/index.js" }, + "deno": { + "types": "./types/index.d.ts", + "import": "./dist/esbrowser/index.js", + "default": "./dist/lib/index.js" + }, "browser": { "types": "./types/index.d.ts", "import": "./dist/esbrowser/index.js", @@ -34,7 +39,9 @@ "postMessage", "crosstab", "ipc", - "leader-election" + "leader-election", + "queue", + "inter-process" ], "repository": { "type": "git", @@ -58,6 +65,7 @@ "test:module:cjs": "npm run build:es5node && mocha ./test/module.cjs.test.js -b --timeout 6000 --exit", "test:node": "npm run build:es5node && mocha ./test/index.test.js -b --timeout 6000 --exit", "test:node:loop": "npm run test:node && npm run test:node:loop", + "test:deno": "deno run --allow-env --unstable ./test/test-deno.js", "test:browser": "npm run build && karma start ./config/karma.conf.js --single-run", "test:e2e": "concurrently \"npm run docs:serve\" \"sleep 20 && testcafe -b && testcafe chrome -e test/e2e.test.js --hostname localhost\" --kill-others --success first", "test:typings": "npm run build && mocha ./test/typings.test.js -b --timeout 12000 --exit", diff --git a/src/methods/native.js b/src/methods/native.js index d06862b7..fa14d229 100644 --- a/src/methods/native.js +++ b/src/methods/native.js @@ -1,3 +1,4 @@ + import { microSeconds as micro, PROMISE_RESOLVED_VOID @@ -42,6 +43,14 @@ export function onMessage(channelState, fn) { } export function canBeUsed() { + + // Deno runtime + // eslint-disable-next-line + if (typeof globalThis !== 'undefined' && globalThis.Deno && globalThis.Deno.args) { + return true; + } + + // Browser runtime if ( (typeof window !== 'undefined' || typeof self !== 'undefined') && typeof BroadcastChannel === 'function' diff --git a/test/test-deno.js b/test/test-deno.js new file mode 100644 index 00000000..9aa974fb --- /dev/null +++ b/test/test-deno.js @@ -0,0 +1,34 @@ +import { BroadcastChannel } from '../dist/esbrowser/index.js'; +import { randomString } from 'async-test-util'; +import assert from 'assert'; +export async function run() { + + console.log('--- 1'); + + console.dir({ + // eslint-disable-next-line + 'globalThis.Deno': !!globalThis.Deno, + // eslint-disable-next-line + 'globalThis.Deno.args': !!globalThis.Deno.args + }); + console.log('--- 2'); + // eslint-disable-next-line + console.log(Object.keys(Deno).sort().join(', ')); + + console.log('--- 3'); + + + const bc = new BroadcastChannel(randomString()); + console.log('bc.type: ' + bc.type); + + + /** + * Deno should use its global native BroadcastChannel + * @link https://docs.deno.com/deploy/api/runtime-broadcast-channel + */ + assert.strictEqual(bc.type, 'native'); + + await bc.postMessage({ foo: 'bar' }); + await bc.close(); +} +run();