Skip to content

Commit

Permalink
Build a dual CommonJS/ES6 module package for Node.js
Browse files Browse the repository at this point in the history
Allowing to be imported as both CommonJS and ES6 module. The unit tests
and benchmark script have been adapted in favor of the ES6 module syntax.
  • Loading branch information
kleisauke committed Jul 10, 2021
1 parent bfdd784 commit 71ee394
Show file tree
Hide file tree
Showing 27 changed files with 542 additions and 468 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,22 @@ syntax:

### Node.js

On Node.js, wasm-vips is exposed as a CommonJS module. It can be required and
initialized like this:
On Node.js, wasm-vips is published as [a dual-package](
https://nodejs.org/api/packages.html#packages_conditional_exports), so it
can be imported as both CommonJS and ES6 module:

```js
// ES6 module
import Vips from 'wasm-vips';

// CommonJS module
const Vips = require('wasm-vips');
```

// Usage with async/await
Then, wasm-vips can be initialized like this:

```js
// Usage with top-level await
const vips = await Vips();

// Usage with .then
Expand Down
39 changes: 38 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,45 @@ echo "============================================="
emcmake cmake $SOURCE_DIR -DCMAKE_BUILD_TYPE=Release -DCMAKE_RUNTIME_OUTPUT_DIRECTORY="$SOURCE_DIR/lib" \
-DENVIRONMENT=${ENVIRONMENT//,/;}
make
)

echo "============================================="
echo "Prepare NPM package"
echo "============================================="
[ "$ENVIRONMENT" = "web,node" ] && (
# Building for both Node.js and web, prepare NPM package
# FIXME(kleisauke): Workaround for https://github.com/emscripten-core/emscripten/issues/11792
sed -i '1iimport { dirname } from "path";' $SOURCE_DIR/lib/node-es6/vips.mjs
sed -i '2iimport { fileURLToPath } from "url";' $SOURCE_DIR/lib/node-es6/vips.mjs
sed -i '3iimport { createRequire } from "module";' $SOURCE_DIR/lib/node-es6/vips.mjs
sed -i '4iconst require = createRequire(import.meta.url);' $SOURCE_DIR/lib/node-es6/vips.mjs
sed -i 's/__dirname/dirname(fileURLToPath(import.meta.url))/g' $SOURCE_DIR/lib/node-es6/vips.mjs
sed -i 's/\(new URL([^)]\+)\).toString()/fileURLToPath(\1)/g' $SOURCE_DIR/lib/node-es6/vips.mjs
sed -i 's/vips.worker.js/vips.worker.mjs/g' $SOURCE_DIR/lib/node-es6/vips.mjs
mv $SOURCE_DIR/lib/node-es6/vips.worker.js $SOURCE_DIR/lib/node-es6/vips.worker.mjs
sed -i 's/var Module/import { fileURLToPath } from "url";&/' $SOURCE_DIR/lib/node-es6/vips.worker.mjs
sed -i 's/var Module/import { createRequire } from "module";&/' $SOURCE_DIR/lib/node-es6/vips.worker.mjs
sed -i 's/var Module/const require = createRequire(import.meta.url);&/' $SOURCE_DIR/lib/node-es6/vips.worker.mjs
sed -i 's/__filename/fileURLToPath(import.meta.url)/g' $SOURCE_DIR/lib/node-es6/vips.worker.mjs

# The produced vips.wasm file should be the same across the different variants (sanity check)
sha256=$(sha256sum "$SOURCE_DIR/lib/web/vips.wasm" | awk '{ print $1 }')
echo "$sha256 $SOURCE_DIR/lib/node-es6/vips.wasm" | sha256sum --check
echo "$sha256 $SOURCE_DIR/lib/node-commonjs/vips.wasm" | sha256sum --check

# Deduplicate produced vips.wasm file for Node.js
mv $SOURCE_DIR/lib/node-es6/vips.wasm $SOURCE_DIR/lib/vips.wasm
rm $SOURCE_DIR/lib/node-commonjs/vips.wasm

# Adjust vips.wasm path for Node.js
# Note: this is intentionally skipped for the web variant
for file in node-commonjs/vips.js node-es6/vips.mjs; do
sed -i 's/vips.wasm/..\/&/g' $SOURCE_DIR/lib/$file
done
# FinalizationGroup -> FinalizationRegistry, see:
# https://github.com/tc39/proposal-weakrefs/issues/180
# https://github.com/emscripten-core/emscripten/issues/11436#issuecomment-645870155
# sed -i 's/FinalizationGroup/FinalizationRegistry/g' $SOURCE_DIR/lib/vips.js
# for file in node-commonjs/vips.js node-es6/vips.mjs web/vips.js; do
# sed -i 's/FinalizationGroup/FinalizationRegistry/g' $SOURCE_DIR/lib/$file
# done
)
18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,22 @@
},
"license": "MIT",
"author": "Kleis Auke Wolthuizen",
"main": "lib/node/vips.js",
"type": "commonjs",
"exports": {
"node": {
"import": "./lib/node-es6/vips.mjs",
"require": "./lib/node-commonjs/vips.js"
},
"default": "./lib/web/vips.js"
},
"main": "lib/node-commonjs/vips.js",
"types": "lib/vips.d.ts",
"files": [
"lib/node/**",
"lib/web/**"
"lib/node-commonjs/*.js",
"lib/node-es6/*.mjs",
"lib/web/*.js",
"lib/vips.d.ts",
"lib/vips.wasm"
],
"scripts": {
"build": "docker build -t wasm-vips . && docker run --rm -v $(pwd):/src wasm-vips ./build.sh",
Expand Down
2 changes: 1 addition & 1 deletion playground/src/playground-runner.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
module.setDelayFunction(fn => globalThis.cleanup = fn);

// Handy for debugging
module.ENV.G_MESSAGES_DEBUG = 'VIPS';
// module.ENV.G_MESSAGES_DEBUG = 'VIPS';

for (const image of ['owl.jpg', 'owl.tif', 'owl.webp', 'banana.webp', 'banana.gif', 'transparency_demo.png'])
module.FS.createPreloadedFile('/', image, 'assets/images/' + image, true, false);
Expand Down
4 changes: 4 additions & 0 deletions playground/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ module.exports = {
{
from: path.join(__dirname, '..', 'lib', 'web'),
to: path.join(__dirname, 'dist', 'lib'),
},
{
from: path.join(__dirname, '..', 'lib', 'vips.d.ts'),
to: path.join(__dirname, 'dist', 'lib'),
}
],
})
Expand Down
32 changes: 23 additions & 9 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,29 @@ target_link_libraries(${PROJECT_NAME}
set(TARGETS "")

if("node" IN_LIST ENVIRONMENT)
add_executable(${PROJECT_NAME}-node $<TARGET_OBJECTS:${PROJECT_NAME}>)
add_executable(${PROJECT_NAME}-node-es6 $<TARGET_OBJECTS:${PROJECT_NAME}>)
add_executable(${PROJECT_NAME}-node-commonjs $<TARGET_OBJECTS:${PROJECT_NAME}>)

set_target_properties(${PROJECT_NAME}-node
set_target_properties(${PROJECT_NAME}-node-es6
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/node"
SUFFIX ".mjs"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/node-es6"
)
set_target_properties(${PROJECT_NAME}-node-commonjs
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/node-commonjs"
)

target_link_libraries(${PROJECT_NAME}-node
target_link_libraries(${PROJECT_NAME}-node-es6
PRIVATE
${VIPS_STATIC_LDFLAGS}
)
target_link_libraries(${PROJECT_NAME}-node-commonjs
PRIVATE
${VIPS_STATIC_LDFLAGS}
)

list(APPEND TARGETS ${PROJECT_NAME}-node)
list(APPEND TARGETS ${PROJECT_NAME}-node-es6 ${PROJECT_NAME}-node-commonjs)
endif()

if("web" IN_LIST ENVIRONMENT)
Expand Down Expand Up @@ -108,13 +118,17 @@ set_target_properties(${TARGETS}
-s EXPORTED_RUNTIME_METHODS='[\"FS\", \"ENV\", \"deletionQueue\", \"addFunction\", \"emscripten_num_logical_cores\"]'"
)

# TODO(kleisauke): Add -s EXPORT_ES6, see:
# https://github.com/emscripten-core/emscripten/issues/11792.
if("node" IN_LIST ENVIRONMENT)
set(NODE_LINK_FLAGS " -s ENVIRONMENT=node,worker -s NODERAWFS -s NODEJS_CATCH_EXIT=0 -s NODEJS_CATCH_REJECTION=0")
set_property(
TARGET ${PROJECT_NAME}-node-es6
APPEND_STRING PROPERTY
LINK_FLAGS "${NODE_LINK_FLAGS} -s EXPORT_ES6"
)
set_property(
TARGET ${PROJECT_NAME}-node
TARGET ${PROJECT_NAME}-node-commonjs
APPEND_STRING PROPERTY
LINK_FLAGS " -s ENVIRONMENT=node,worker -s NODERAWFS -s NODEJS_CATCH_EXIT=0 -s NODEJS_CATCH_REJECTION=0"
LINK_FLAGS "${NODE_LINK_FLAGS}"
)
endif()

Expand Down
18 changes: 18 additions & 0 deletions test/bench/images.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

import { dirname, join } from 'path';
import { fileURLToPath } from 'url';

// Helpers
export function getPath(filename) {
return join(dirname(fileURLToPath(import.meta.url)), 'images', filename);
}

// https://www.flickr.com/photos/grizdave/2569067123/
export const inputJpg = getPath('2569067123_aca715a2ee_o.jpg');

// https://gist.github.com/gasi/769cfb9f2359a1fbedc5
export const inputPng = getPath('alpha-premultiply-2048x1536-paper.png');

// https://www.gstatic.com/webp/gallery/4.webp
export const inputWebP = getPath('4.webp');
17 changes: 0 additions & 17 deletions test/bench/images/index.js

This file was deleted.

1 change: 1 addition & 0 deletions test/bench/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"license": "MIT",
"author": "Kleis Auke Wolthuizen",
"type": "module",
"main": "perf.js",
"scripts": {
"test": "node perf"
Expand Down
Loading

0 comments on commit 71ee394

Please sign in to comment.