Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/browser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Browser CI

on:
push:
branches: [main]
workflow_dispatch:
Comment on lines +3 to +6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Run browser CI on pull requests

This workflow only runs after a commit reaches main (or when manually dispatched), so browser-only regressions introduced by a pull request cannot be detected before merge; the existing Node workflow does not execute make -C browser test. Add a pull_request trigger so this new suite can serve as a pre-merge CI check.

Useful? React with 👍 / 👎.


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
Comment thread
kawanet marked this conversation as resolved.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
._*
.idea/
.vscode/
node_modules/
browser/tests/
node_modules
npm-debug.log*
package-lock.json
~$*
*.browserify.js
*.js.gz
gh-pages/
*.log
!browser/tests.cli.mjs
1 change: 0 additions & 1 deletion .npmrc

This file was deleted.

61 changes: 61 additions & 0 deletions browser/Makefile
Original file line number Diff line number Diff line change
@@ -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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Provide the Node global expected by bundled tests

Bundling the 1* and 2* suites into a plain browser IIFE includes test/21.ext.js and test/22.typedarray.js, which evaluate expressions such as global[name]. Chromium does not define the Node global identifier, and none of the loaded shims creates it, so bundled.js raises a ReferenceError while registering tests and the new browser job fails on every run. Replace those lookups with globalThis/window or provide an explicit browser global shim.

Useful? React with 👍 / 👎.

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
40 changes: 40 additions & 0 deletions browser/tests.cli.mjs
Original file line number Diff line number Diff line change
@@ -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
})
22 changes: 22 additions & 0 deletions browser/tests.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>msgpack-lite browser test</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="../node_modules/mocha/mocha.css"/>
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script>
<script class="mocha-init">
mocha.setup("bdd");
mocha.checkLeaks();
</script>
<script src="../dist/msgpack.min.js"></script>
<script src="./tests/assert.shim.js"></script>
<script src="./tests/buffer.shim.js"></script>
<script src="./tests/bundled.js"></script>
<script>const runner = mocha.run(() => (window.mochaStats = runner.stats));</script>
</body>
</html>
18 changes: 17 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"description": "Fast Pure JavaScript MessagePack Encoder and Decoder",
"version": "0.2.1",
"author": "@kawanet",
"allowScripts": {
"msgpackr-extract": false
},
Comment on lines +6 to +8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Actually block the optional dependency's install script

On regular installs such as the Node CI workflow's npm install, npm does not enforce this allowScripts metadata, so removing .npmrc causes the optional msgpackr-extract lifecycle script to run again. I confirmed this behavior with npm 11.4.2—the version bundled with the workflow's Node 24 toolchain—where a dependency's install script still executed despite an allowScripts: {dep: false} entry; npm's documented mechanism for suppressing lifecycle scripts is ignore-scripts. Use an enforcement mechanism that npm actually recognizes so the native installer remains blocked as intended.

Useful? React with 👍 / 👎.

Comment on lines +6 to +8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the optional-dependency script protection

When developers or the existing Node.js CI run plain npm install, this allowScripts object is ignored by npm, so deleting .npmrc's omit=optional causes msgpackr-extract to be installed and its lifecycle script to run again. This was reproducible with npm 11.4.2, and older npm versions in the Node 18/20/22 matrix also do not enforce this field; retain an npm-supported restriction such as omitting optional dependencies or using --ignore-scripts at every install site.

Useful? React with 👍 / 👎.

"bin": {
"msgpack": "./bin/msgpack"
},
Expand All @@ -29,15 +32,27 @@
},
"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",
"mocha": "^11.8.0",
"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",
Expand Down Expand Up @@ -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"
}
6 changes: 2 additions & 4 deletions test/10.encode.js
Original file line number Diff line number Diff line change
@@ -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);

Expand Down
6 changes: 2 additions & 4 deletions test/11.decode.js
Original file line number Diff line number Diff line change
@@ -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);

Expand Down
6 changes: 2 additions & 4 deletions test/12.encoder.js
Original file line number Diff line number Diff line change
@@ -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));
Expand Down
6 changes: 2 additions & 4 deletions test/13.decoder.js
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
6 changes: 2 additions & 4 deletions test/14.codec.js
Original file line number Diff line number Diff line change
@@ -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);

Expand Down
6 changes: 2 additions & 4 deletions test/15.useraw.js
Original file line number Diff line number Diff line change
@@ -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];

Expand Down
6 changes: 2 additions & 4 deletions test/16.binarraybuffer.js
Original file line number Diff line number Diff line change
@@ -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];
Expand Down
6 changes: 2 additions & 4 deletions test/17.uint8array.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 2 additions & 4 deletions test/18.utf8.js
Original file line number Diff line number Diff line change
@@ -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}];

Expand Down
6 changes: 2 additions & 4 deletions test/20.roundtrip.js
Original file line number Diff line number Diff line change
@@ -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 = "α";
Expand Down
6 changes: 2 additions & 4 deletions test/21.ext.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
6 changes: 2 additions & 4 deletions test/22.typedarray.js
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
6 changes: 2 additions & 4 deletions test/23.extbuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 2 additions & 4 deletions test/24.int64.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
Expand Down
Loading