From f6822dc9b5a4eb1be2ad41a5ef4c099696cf0bc3 Mon Sep 17 00:00:00 2001 From: Michael McDermott Date: Mon, 25 Mar 2024 17:48:53 -0500 Subject: [PATCH] Browser JavaScript Support (#468) * Sample code to run in the browser. * Added way to extract command output and store it in a string. * Working on getting bundled javascript to work. * Tinkering * Tinkering with bundling. * Got bundled version to run. * Adding index file. --- src/grammar/dice.yacc | 6 ++++++ src/js/gnoll.js | 19 ++++++++++++++++++ src/js/index.html | 22 +++++++++++++++++++++ src/js/package.json | 18 +++++++++++++++++ src/js/preface.js | 5 +++++ src/js/target.mk | 21 ++++++++++++++++++++ src/js/webpack.config.js | 42 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+) create mode 100644 src/js/gnoll.js create mode 100644 src/js/index.html create mode 100644 src/js/package.json create mode 100644 src/js/preface.js create mode 100644 src/js/webpack.config.js diff --git a/src/grammar/dice.yacc b/src/grammar/dice.yacc index 27170c30f..7b74f0d7a 100644 --- a/src/grammar/dice.yacc +++ b/src/grammar/dice.yacc @@ -22,6 +22,9 @@ #include "util/array_functions.h" #include "util/vector_functions.h" #include "util/string_functions.h" +#ifdef __EMSCRIPTEN__ +#include +#endif #define UNUSED(x) (void)(x) // Avoid conflicts with MacOs predefined macros @@ -1619,6 +1622,9 @@ typedef struct yy_buffer_state * YY_BUFFER_STATE; extern YY_BUFFER_STATE yy_scan_string(char * str); extern void yy_delete_buffer(YY_BUFFER_STATE buffer); +#ifdef __EMSCRIPTEN__ +EMSCRIPTEN_KEEPALIVE +#endif int roll_full_options( char* roll_request, char* log_file, diff --git a/src/js/gnoll.js b/src/js/gnoll.js new file mode 100644 index 000000000..ae7ebfcbe --- /dev/null +++ b/src/js/gnoll.js @@ -0,0 +1,19 @@ +import gwFactory from './gnollwasm.js'; + +export async function roll(notation) { + return new Promise((resolve) => { + gwFactory().then((Module) => { + Module.resetOut(); + + Module.ccall('roll_full_options', 'number', ['string', + 'string', 'number', 'number', 'number', 'number', 'number', + 'number'], + [notation, null, 0, 0, 0, 1, 0, 0] + ); + + resolve( Module.stdout ); + }); + + }); +} + diff --git a/src/js/index.html b/src/js/index.html new file mode 100644 index 000000000..b7ab8807f --- /dev/null +++ b/src/js/index.html @@ -0,0 +1,22 @@ + + + Sample App + + + + + +
+

Input:

+

+
+
+ + diff --git a/src/js/package.json b/src/js/package.json new file mode 100644 index 000000000..92297c416 --- /dev/null +++ b/src/js/package.json @@ -0,0 +1,18 @@ +{ + "name": "GNOLL", + "version": "1.0.0", + "main": "index.js", + "devDependencies": { + "webpack": "^5.91.0", + "webpack-cli": "^5.1.4" + }, + "dependencies": { + "browserify-fs": "^1.0.0", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "path-browserify": "^1.0.1", + "stream-browserify": "^3.0.0", + "util": "^0.12.5", + "vm-browserify": "^1.1.2" + } +} diff --git a/src/js/preface.js b/src/js/preface.js new file mode 100644 index 000000000..d2665c8e5 --- /dev/null +++ b/src/js/preface.js @@ -0,0 +1,5 @@ +var Module = { + stdout : "", + resetOut: function() { Module.stdout = ""; }, + print: function(text) { Module.stdout += text; }, +}; diff --git a/src/js/target.mk b/src/js/target.mk index 419eca9dc..895136d78 100644 --- a/src/js/target.mk +++ b/src/js/target.mk @@ -25,3 +25,24 @@ js: javascript clean_js: rm -rf build/js + +jsweb: clean yacc lex + mkdir -p build/jsweb + emcc \ + $(CFILES) \ + -I ./src/grammar \ + -o src/js/gnollwasm.js \ + -D__EMSCRIPTEN__ \ + -s MODULARIZE=1 \ + -sSINGLE_FILE \ + -s EXPORT_NAME=gnollwasm \ + --pre-js ./src/js/preface.js \ + -s WASM=1 -s EXPORTED_RUNTIME_METHODS='["cwrap", "ccall", "print"]' \ + -s EXPORTED_FUNCTIONS="['_roll_full_options']" + +#-s EXPORT_ES6=1 \ + +jsbundle: jsweb + #cp src/js/*.html src/js/*.wasm ./build/jsweb/ + cp src/js/*.html ./build/jsweb/ + yarn --cwd ./src/js run webpack-cli b diff --git a/src/js/webpack.config.js b/src/js/webpack.config.js new file mode 100644 index 000000000..dd41a42aa --- /dev/null +++ b/src/js/webpack.config.js @@ -0,0 +1,42 @@ +const path = require('path'); + +module.exports = { + mode: 'development', + entry: { + wrapper: { + import: './gnoll.js', + }, + }, + node: { + global: true, + __filename: true, + __dirname: true, + }, + resolve: { + fallback: { + fs: require.resolve('browserify-fs'), + path: require.resolve('path-browserify'), + buffer: require.resolve('buffer'), + stream: require.resolve('stream-browserify'), + crypto: require.resolve("crypto-browserify"), + vm: require.resolve("vm-browserify") + } + }, + devtool: 'source-map', + output: { + filename: 'gnoll.bundle.js', + path: path.resolve(__dirname, '../../build/jsweb/'), + library: 'gnoll' + }, + experiments: { + asyncWebAssembly: true, + syncWebAssembly: true + }, + devServer: { + static: { + directory: path.join(__dirname, 'dist'), + }, + compress: true, + port: 9000 + }, +}