Skip to content

Commit

Permalink
Add wasm backend (#150)
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett committed Jul 30, 2023
1 parent 9b7c657 commit fcd2541
Show file tree
Hide file tree
Showing 27 changed files with 1,137 additions and 208 deletions.
24 changes: 23 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,31 @@ jobs:
name: prebuilds
path: prebuilds

build-wasm:
runs-on: ubuntu-latest
container:
image: emscripten/emsdk
steps:
- uses: actions/checkout@v3
- run: corepack enable
- uses: actions/setup-node@v3
with:
cache: yarn
node-version: 18
- run: yarn --frozen-lockfile
- run: make wasm
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: wasm
path: build/Release/watcher.wasm

release:
runs-on: ubuntu-latest
needs:
- build
- build-freebsd
- build-wasm
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
Expand All @@ -111,7 +131,9 @@ jobs:
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Build npm packages
run: node scripts/build-npm.js
run: |
node scripts/build-npm.js
node scripts/build-wasm.js
- name: Publish to npm
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Expand Down
17 changes: 16 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
test:
Expand Down Expand Up @@ -51,6 +50,7 @@ jobs:
watchman -v
- run: yarn --frozen-lockfile
- run: yarn test

test-freebsd:
runs-on: macos-latest
steps:
Expand All @@ -68,3 +68,18 @@ jobs:
run: |
yarn --frozen-lockfile
yarn test
test-wasm:
runs-on: ubuntu-latest
container:
image: emscripten/emsdk
steps:
- uses: actions/checkout@v3
- run: corepack enable
- uses: actions/setup-node@v3
with:
cache: yarn
node-version: 18
- run: yarn --frozen-lockfile
- run: make wasm-debug
- run: TEST_WASM=1 yarn test
37 changes: 37 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
NODE_PATH := $(dir $(shell which node))
HEADERS_URL := $(shell node -p "process.release.headersUrl")
NODE_VERSION := $(shell node -p "process.version")

INCS_Debug := \
-Ibuild/node-$(NODE_VERSION)/include/node \
-I$(shell node -p "require('node-addon-api').include_dir")

SRC := src/binding.cc src/Watcher.cc src/Backend.cc src/DirTree.cc src/Glob.cc src/Debounce.cc src/shared/BruteForceBackend.cc src/unix/legacy.cc src/wasm/WasmBackend.cc
FLAGS := $(INCS_Debug) \
-Oz \
-flto \
-fwasm-exceptions \
-DNAPI_HAS_THREADS=1 \
-sEXPORTED_FUNCTIONS="['_napi_register_wasm_v1', '_wasm_backend_event_handler', '_malloc', '_free', '_on_timeout']" \
-sERROR_ON_UNDEFINED_SYMBOLS=0 \
-s INITIAL_MEMORY=524288000

build/node-headers.tar.gz:
curl $(HEADERS_URL) -o build/node-headers.tar.gz

build/node-$(NODE_VERSION): build/node-headers.tar.gz
tar -xvf build/node-headers.tar.gz -C build
touch build/node-$(NODE_VERSION)

build/Release/watcher.wasm: build/node-$(NODE_VERSION) $(SRC)
mkdir -p build/Release
em++ $(FLAGS) -sDECLARE_ASM_MODULE_EXPORTS=0 -o build/Release/watcher.js $(SRC)

build/Debug/watcher.wasm: build/node-$(NODE_VERSION) $(SRC)
mkdir -p build/Debug
em++ -g $(FLAGS) -o build/Debug/watcher.js $(SRC)

wasm: build/Release/watcher.wasm
wasm-debug: build/Debug/watcher.wasm

.PHONY: wasm wasm-debug
2 changes: 1 addition & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"target_name": "watcher",
"defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ],
"sources": [ "src/binding.cc", "src/Watcher.cc", "src/Backend.cc", "src/DirTree.cc", "src/Glob.cc" ],
"sources": [ "src/binding.cc", "src/Watcher.cc", "src/Backend.cc", "src/DirTree.cc", "src/Glob.cc", "src/Debounce.cc" ],
"include_dirs" : ["<!(node -p \"require('node-addon-api').include_dir\")"],
'cflags!': [ '-fno-exceptions' ],
'cflags_cc!': [ '-fno-exceptions' ],
Expand Down
44 changes: 6 additions & 38 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
const path = require('path');
const micromatch = require('micromatch');
const isGlob = require('is-glob');
const {createWrapper} = require('./wrapper');

let name = `@parcel/watcher-${process.platform}-${process.arch}`;
if (process.platform === 'linux') {
Expand Down Expand Up @@ -64,38 +62,8 @@ function normalizeOptions(dir, opts = {}) {
return opts;
}

exports.writeSnapshot = (dir, snapshot, opts) => {
return binding.writeSnapshot(
path.resolve(dir),
path.resolve(snapshot),
normalizeOptions(dir, opts),
);
};

exports.getEventsSince = (dir, snapshot, opts) => {
return binding.getEventsSince(
path.resolve(dir),
path.resolve(snapshot),
normalizeOptions(dir, opts),
);
};

exports.subscribe = async (dir, fn, opts) => {
dir = path.resolve(dir);
opts = normalizeOptions(dir, opts);
await binding.subscribe(dir, fn, opts);

return {
unsubscribe() {
return binding.unsubscribe(dir, fn, opts);
},
};
};

exports.unsubscribe = (dir, fn, opts) => {
return binding.unsubscribe(
path.resolve(dir),
fn,
normalizeOptions(dir, opts),
);
};
const wrapper = createWrapper(binding);
exports.writeSnapshot = wrapper.writeSnapshot;
exports.getEventsSince = wrapper.getEventsSince;
exports.subscribe = wrapper.subscribe;
exports.unsubscribe = wrapper.unsubscribe;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"husky": "^7.0.2",
"lint-staged": "^11.1.2",
"mocha": "^9.1.1",
"napi-wasm": "^1.1.0",
"prebuildify": "^5.0.1",
"prettier": "^2.3.2"
},
Expand Down
49 changes: 49 additions & 0 deletions scripts/build-wasm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const exec = require('child_process').execSync;
const fs = require('fs');
const pkg = require('../package.json');

const dir = `${__dirname}/..`;
try {
fs.mkdirSync(dir + '/npm/wasm');
} catch (err) { }

let dts = fs.readFileSync(`${dir}/index.d.ts`, 'utf8');
dts += `
/** Initializes the web assembly module. */
export default function init(input?: string | URL | Request): Promise<void>;
`;
fs.writeFileSync(`${dir}/npm/wasm/index.d.ts`, dts);

let readme = fs.readFileSync(`${dir}/README.md`, 'utf8');
readme = readme.replace('# 鈿★笍 Lightning CSS', '# 鈿★笍 lightningcss-wasm');
fs.writeFileSync(`${dir}/npm/wasm/README.md`, readme);

let js = fs.readFileSync(`${dir}/wasm/index.mjs`, 'utf8');
js = js.replace('../build/Debug/watcher.wasm', 'watcher.wasm');
js = js.replace('../wrapper.js', './wrapper.js');
fs.writeFileSync(`${dir}/npm/wasm/index.mjs`, js);

fs.copyFileSync(`${dir}/wrapper.js`, `${dir}/npm/wasm/wrapper.js`);
fs.copyFileSync(`${dir}/wasm/watcher.wasm`, `${dir}/npm/wasm/watcher.wasm`);

let wasmPkg = { ...pkg };
wasmPkg.name = '@parcel/watcher-wasm';
wasmPkg.main = 'index.mjs';
wasmPkg.module = 'index.mjs';
wasmPkg.types = 'index.d.ts';
wasmPkg.sideEffects = false;
wasmPkg.files = ['*.js', '*.mjs', '*.d.ts', '*.wasm'];
wasmPkg.dependencies = {
'napi-wasm': pkg.devDependencies['napi-wasm'],
'is-glob': pkg.dependencies['is-glob'],
'micromatch': pkg.dependencies['micromatch']
};
delete wasmPkg.exports;
delete wasmPkg.binary;
delete wasmPkg['lint-staged'];
delete wasmPkg.husky;
delete wasmPkg.devDependencies;
delete wasmPkg.optionalDependencies;
delete wasmPkg.targets;
delete wasmPkg.scripts;
fs.writeFileSync(`${dir}/npm/wasm/package.json`, JSON.stringify(wasmPkg, false, 2) + '\n');
51 changes: 37 additions & 14 deletions src/Backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#ifdef KQUEUE
#include "kqueue/KqueueBackend.hh"
#endif
#ifdef __wasm32__
#include "wasm/WasmBackend.hh"
#endif
#include "shared/BruteForceBackend.hh"

#include "Backend.hh"
Expand Down Expand Up @@ -49,6 +52,11 @@ std::shared_ptr<Backend> getBackend(std::string backend) {
return std::make_shared<KqueueBackend>();
}
#endif
#ifdef __wasm32__
if (backend == "wasm" || backend == "default") {
return std::make_shared<WasmBackend>();
}
#endif
if (backend == "brute-force" || backend == "default") {
return std::make_shared<BruteForceBackend>();
}
Expand Down Expand Up @@ -79,20 +87,33 @@ void removeShared(Backend *backend) {
break;
}
}

// Free up memory.
if (sharedBackends.size() == 0) {
sharedBackends.rehash(0);
}
}

void Backend::run() {
mThread = std::thread([this] () {
#ifndef __wasm32__
mThread = std::thread([this] () {
try {
start();
} catch (std::exception &err) {
handleError(err);
}
});

if (mThread.joinable()) {
mStartedSignal.wait();
}
#else
try {
start();
} catch (std::exception &err) {
handleError(err);
}
});

if (mThread.joinable()) {
mStartedSignal.wait();
}
#endif
}

void Backend::notifyStarted() {
Expand All @@ -104,15 +125,17 @@ void Backend::start() {
}

Backend::~Backend() {
// Wait for thread to stop
if (mThread.joinable()) {
// If the backend is being destroyed from the thread itself, detach, otherwise join.
if (mThread.get_id() == std::this_thread::get_id()) {
mThread.detach();
} else {
mThread.join();
#ifndef __wasm32__
// Wait for thread to stop
if (mThread.joinable()) {
// If the backend is being destroyed from the thread itself, detach, otherwise join.
if (mThread.get_id() == std::this_thread::get_id()) {
mThread.detach();
} else {
mThread.join();
}
}
}
#endif
}

void Backend::watch(Watcher &watcher) {
Expand Down

0 comments on commit fcd2541

Please sign in to comment.