diff --git a/.github/workflows/browser.yml b/.github/workflows/browser.yml
new file mode 100644
index 0000000..3e17efe
--- /dev/null
+++ b/.github/workflows/browser.yml
@@ -0,0 +1,28 @@
+name: Browser CI
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+concurrency:
+ group: browser-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ browser:
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+
+ steps:
+ - uses: actions/checkout@v7
+
+ - uses: actions/setup-node@v7
+ with:
+ node-version: "24"
+
+ - run: make -C browser install
+ - run: make -C browser test
diff --git a/.gitignore b/.gitignore
index fb3a416..ace8864 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,8 @@
._*
.idea/
.vscode/
-node_modules/
+browser/tests/
+node_modules
npm-debug.log*
package-lock.json
~$*
@@ -13,3 +14,4 @@ package-lock.json
*.js.gz
gh-pages/
*.log
+!browser/tests.cli.mjs
diff --git a/.npmrc b/.npmrc
deleted file mode 100644
index d373ccb..0000000
--- a/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-omit=optional
diff --git a/browser/Makefile b/browser/Makefile
new file mode 100755
index 0000000..506959e
--- /dev/null
+++ b/browser/Makefile
@@ -0,0 +1,61 @@
+# Force bash so `set -o pipefail` works in the recipes below.
+SHELL := bash
+.SHELLFLAGS := -eo pipefail -c
+
+PLAYWRIGHT_VERSION := 1.62.1
+
+TEST_SRC := ../test/[12]*.js ../test/6[12]*.js
+TEST_DST := tests/bundled.js
+BUFFER_SRC := ../node_modules/buffer/index.js
+BUFFER_DST := tests/buffer.shim.js
+ASSERT_SRC := ../node_modules/assert/assert.js
+ASSERT_DST := tests/assert.shim.js
+
+ALL := $(TEST_DST) $(BUFFER_DST) $(ASSERT_DST)
+
+all: dist $(ALL)
+
+bundled: all
+
+# Keep Playwright out of package.json. CI installs it transiently alongside
+# the project's build dependencies, then downloads only the headless shell.
+install:
+ cd .. && PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install playwright@$(PLAYWRIGHT_VERSION) --no-save --ignore-scripts --no-audit --no-fund
+ cd .. && npx --no-install playwright install --with-deps --only-shell chromium
+
+# tests.html loads the shipped bundle, so ask the root Makefile for it
+# first; whether it rebuilds stays the root Makefile's decision.
+dist:
+ $(MAKE) -C .. dist/msgpack.min.js
+
+test: all
+ cd .. && node browser/tests.cli.mjs
+
+$(TEST_DST): $(TEST_SRC) Makefile
+ mkdir -p $(dir $@)
+ ../node_modules/.bin/rollup $(TEST_SRC) --format iife \
+ --plugin @rollup/plugin-commonjs \
+ --plugin @rollup/plugin-multi-entry \
+ --plugin @rollup/plugin-node-resolve \
+ --external 'assert,../index' |\
+ perl -pe 's#^}\)\(require.*\);#})(assert, msgpack)#' > $@
+
+$(BUFFER_DST): $(BUFFER_SRC) Makefile
+ mkdir -p $(dir $@)
+ ../node_modules/.bin/rollup $< --format iife \
+ --plugin @rollup/plugin-commonjs \
+ --plugin @rollup/plugin-node-resolve \
+ --name "__BUFFER__" | \
+ perl -pe 's#^var __BUFFER__#const {Buffer}#' > $@
+
+$(ASSERT_DST): $(ASSERT_SRC) Makefile
+ mkdir -p $(dir $@)
+ ../node_modules/.bin/rollup $< --format iife \
+ --plugin @rollup/plugin-commonjs \
+ --plugin @rollup/plugin-node-resolve \
+ --name "assert" > $@
+
+clean:
+ /bin/rm -fr $(ALL)
+
+.PHONY: all bundled dist install test clean
diff --git a/browser/tests.cli.mjs b/browser/tests.cli.mjs
new file mode 100644
index 0000000..b5a3def
--- /dev/null
+++ b/browser/tests.cli.mjs
@@ -0,0 +1,40 @@
+import {chromium} from "playwright"
+import {fileURLToPath, pathToFileURL} from "node:url"
+
+const html = fileURLToPath(new URL("./tests.html", import.meta.url))
+
+const run = async () => {
+ const browser = await chromium.launch()
+
+ try {
+ const page = await browser.newPage()
+ const pageErrors = []
+ page.on("pageerror", error => pageErrors.push(error))
+
+ await page.goto(pathToFileURL(html).href)
+
+ // Completion is a state, not a promise: mocha.run() publishes its
+ // stats on window when done, and an unfinished or broken page just
+ // never does -- so this times out instead of passing.
+ await page.waitForFunction(() => window.mochaStats !== undefined, null, {timeout: 60_000})
+ const {tests, passes, pending, failures, duration} = await page.evaluate(() => window.mochaStats)
+ console.log(`${passes} passing, ${failures} failing, ${pending} pending (${tests} tests, ${duration}ms)`)
+
+ if (pageErrors.length) {
+ throw new AggregateError(pageErrors, "Browser page errors occurred")
+ }
+ if (failures) {
+ throw new Error(`Mocha reported ${failures} failed test(s)`)
+ }
+ if (!tests) {
+ throw new Error("Mocha ran no tests")
+ }
+ } finally {
+ await browser.close()
+ }
+}
+
+run().catch(error => {
+ console.error(error)
+ process.exitCode = 1
+})
diff --git a/browser/tests.html b/browser/tests.html
new file mode 100644
index 0000000..bc79416
--- /dev/null
+++ b/browser/tests.html
@@ -0,0 +1,22 @@
+
+
+
+
+ msgpack-lite browser test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index 2cb7b3c..9af9244 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,9 @@
"description": "Fast Pure JavaScript MessagePack Encoder and Decoder",
"version": "0.2.1",
"author": "@kawanet",
+ "allowScripts": {
+ "msgpackr-extract": false
+ },
"bin": {
"msgpack": "./bin/msgpack"
},
@@ -29,6 +32,10 @@
},
"devDependencies": {
"@msgpack/msgpack": "^3.1.3",
+ "@rollup/plugin-commonjs": "^29.0.3",
+ "@rollup/plugin-multi-entry": "^7.1.0",
+ "@rollup/plugin-node-resolve": "^16.0.3",
+ "assert": "^1.5.1",
"browserify": "^17.0.1",
"concat-stream": "^2.0.0",
"jshint": "^2.13.6",
@@ -36,8 +43,16 @@
"msgpack5": "^6.0.2",
"msgpackr": "^2.0.6",
"notepack.io": "^3.0.1",
+ "rollup": "^4.63.1",
"uglify-js": "^3.19.3"
},
+ "devEngines": {
+ "runtime": {
+ "name": "node",
+ "version": ">=22.18.0",
+ "onFail": "warn"
+ }
+ },
"files": [
"LICENSE",
"README.md",
@@ -85,5 +100,6 @@
"make": "make",
"size": "make clean dist/msgpack.min.js && gzip -9fkv dist/msgpack.min.js && ls -l dist",
"test": "make test"
- }
+ },
+ "type": "commonjs"
}
diff --git a/test/10.encode.js b/test/10.encode.js
index 1881a8f..148615e 100755
--- a/test/10.encode.js
+++ b/test/10.encode.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "10.encode.js";
var HAS_UINT8ARRAY = ("undefined" !== typeof Uint8Array);
diff --git a/test/11.decode.js b/test/11.decode.js
index 8052c0d..248ece5 100755
--- a/test/11.decode.js
+++ b/test/11.decode.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "11.decode.js";
var HAS_UINT8ARRAY = ("undefined" !== typeof Uint8Array);
diff --git a/test/12.encoder.js b/test/12.encoder.js
index 3a1e48c..2bcb758 100755
--- a/test/12.encoder.js
+++ b/test/12.encoder.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "12.encoder.js";
var source = {"foo": "bar"};
var packed = toArray(msgpack.encode(source));
diff --git a/test/13.decoder.js b/test/13.decoder.js
index 6683ac8..f1d1505 100755
--- a/test/13.decoder.js
+++ b/test/13.decoder.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "13.decoder.js";
var source = {"foo": "bar"};
var packed = msgpack.encode(source);
diff --git a/test/14.codec.js b/test/14.codec.js
index af7fe83..47024a4 100755
--- a/test/14.codec.js
+++ b/test/14.codec.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "14.codec.js";
var HAS_UINT8ARRAY = ("undefined" !== typeof Uint8Array);
diff --git a/test/15.useraw.js b/test/15.useraw.js
index c9e445e..0cade20 100755
--- a/test/15.useraw.js
+++ b/test/15.useraw.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "15.useraw.js";
var TESTS = [0, 1, 31, 32, 255, 256, 65535, 65536];
diff --git a/test/16.binarraybuffer.js b/test/16.binarraybuffer.js
index cdc78e5..25fef5e 100755
--- a/test/16.binarraybuffer.js
+++ b/test/16.binarraybuffer.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "16.binarraybuffer.js";
var HAS_UINT8ARRAY = ("undefined" !== typeof Uint8Array);
var TESTS = [0, 1, 31, 32, 255, 256, 65535, 65536];
diff --git a/test/17.uint8array.js b/test/17.uint8array.js
index 423643d..797e5e8 100755
--- a/test/17.uint8array.js
+++ b/test/17.uint8array.js
@@ -2,10 +2,8 @@
var assert = require("assert");
var Bufferish = require("../lib/bufferish");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "17.uint8array.js";
var HAS_UINT8ARRAY = ("undefined" !== typeof Uint8Array);
diff --git a/test/18.utf8.js b/test/18.utf8.js
index 5398735..94de5fe 100755
--- a/test/18.utf8.js
+++ b/test/18.utf8.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "18.utf8.js";
var OPTIONS = [{}, {safe: true}];
diff --git a/test/20.roundtrip.js b/test/20.roundtrip.js
index 909329d..bc1fd93 100755
--- a/test/20.roundtrip.js
+++ b/test/20.roundtrip.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "20.roundtrip.js";
var STRING_ASCII = "a";
var STRING_GREEK = "α";
diff --git a/test/21.ext.js b/test/21.ext.js
index 401693b..c913ab7 100755
--- a/test/21.ext.js
+++ b/test/21.ext.js
@@ -3,10 +3,8 @@
/*jshint -W053 */
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "21.ext.js";
describe(TITLE, function() {
it("Boolean", function() {
diff --git a/test/22.typedarray.js b/test/22.typedarray.js
index b536a88..96afdbc 100755
--- a/test/22.typedarray.js
+++ b/test/22.typedarray.js
@@ -3,10 +3,8 @@
/*jshint -W053 */
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "22.typedarray.js";
var TYPED_ARRAY = {
"Int8Array": [0, 1, 2, 126, 127, -128, -127, -2, -1],
diff --git a/test/23.extbuffer.js b/test/23.extbuffer.js
index 983b762..35d9e63 100755
--- a/test/23.extbuffer.js
+++ b/test/23.extbuffer.js
@@ -3,10 +3,8 @@
/*jshint -W053 */
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "23.extbuffer.js";
var HAS_UINT8ARRAY = ("undefined" !== typeof Uint8Array);
diff --git a/test/24.int64.js b/test/24.int64.js
index bb8810b..cc02e59 100755
--- a/test/24.int64.js
+++ b/test/24.int64.js
@@ -7,10 +7,8 @@ var Uint64BE = Int64Buffer.Uint64BE;
var Int64BE = Int64Buffer.Int64BE;
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "24.int64.js";
describe(TITLE, function() {
var options = {};
diff --git a/test/26.es6.js b/test/26.es6.js
index 432a8a9..3667198 100755
--- a/test/26.es6.js
+++ b/test/26.es6.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "26.es6.js";
describe(TITLE, function() {
diff --git a/test/27.usemap.js b/test/27.usemap.js
index 7533fa9..bcc77c6 100755
--- a/test/27.usemap.js
+++ b/test/27.usemap.js
@@ -1,11 +1,9 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
var HAS_MAP = ("undefined" !== typeof Map);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "27.usemap.js";
function pattern(min, max, offset) {
var array = [];
diff --git a/test/30.stream.js b/test/30.stream.js
index b7a7986..d37f86c 100755
--- a/test/30.stream.js
+++ b/test/30.stream.js
@@ -5,7 +5,7 @@ var Stream = require("stream");
var concat = require("concat-stream");
var msgpack = require("../index");
-var TITLE = __filename.replace(/^.*\//, "");
+var TITLE = "30.stream.js";
var example = require("./example.json");
var src = [
diff --git a/test/50.compat.js b/test/50.compat.js
index e07eb2c..ba23f94 100755
--- a/test/50.compat.js
+++ b/test/50.compat.js
@@ -3,7 +3,7 @@
var assert = require("assert");
var msgpack = require("../index");
-var TITLE = __filename.replace(/^.*\//, "");
+var TITLE = "50.compat.js";
var data = require("./example.json");
diff --git a/test/61.encode-only.js b/test/61.encode-only.js
index 1078352..c779259 100755
--- a/test/61.encode-only.js
+++ b/test/61.encode-only.js
@@ -4,7 +4,7 @@ var assert = require("assert");
var encode = require("../lib/encode").encode;
var ExtBuffer = require("../lib/ext-buffer").ExtBuffer;
-var TITLE = __filename.replace(/^.*\//, "");
+var TITLE = "61.encode-only.js";
describe(TITLE, function() {
it("encode", function() {
diff --git a/test/62.decode-only.js b/test/62.decode-only.js
index 057e1a5..5b68a14 100755
--- a/test/62.decode-only.js
+++ b/test/62.decode-only.js
@@ -4,7 +4,7 @@ var assert = require("assert");
var decode = require("../lib/decode").decode;
var ExtBuffer = require("../lib/ext-buffer").ExtBuffer;
-var TITLE = __filename.replace(/^.*\//, "");
+var TITLE = "62.decode-only.js";
describe(TITLE, function() {
it("decode", function() {
diff --git a/test/64.decode-limit.js b/test/64.decode-limit.js
index 32cd9d1..7dacce2 100644
--- a/test/64.decode-limit.js
+++ b/test/64.decode-limit.js
@@ -1,10 +1,8 @@
#!/usr/bin/env mocha -R spec
var assert = require("assert");
-var msgpackJS = "../index";
-var isBrowser = ("undefined" !== typeof window);
-var msgpack = isBrowser && window.msgpack || require(msgpackJS);
-var TITLE = __filename.replace(/^.*\//, "");
+var msgpack = require("../index");
+var TITLE = "64.decode-limit.js";
describe(TITLE, function() {
// An array32/map32 header may declare up to 2^32-1 elements. Decoding a