From e9bcc460d1a6e0140147be69241fff325b1cbf07 Mon Sep 17 00:00:00 2001 From: Stephen Wan Date: Mon, 2 Jan 2023 18:59:58 +1100 Subject: [PATCH 1/4] makefile: add esmodule target --- Makefile | 10 +++++++++- module.js | 5 +++++ package.json | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 module.js diff --git a/Makefile b/Makefile index 8e409262..d92cda11 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,11 @@ EMFLAGS_OPTIMIZED= \ -flto \ --closure 1 +EMFLAGS_ESMODULE= \ + -s EXPORT_ES6=1 \ + -s MODULARIZE=1 \ + -s EXPORT_NAME=loadWASM \ + EMFLAGS_DEBUG = \ -s ASSERTIONS=1 \ -O1 @@ -88,7 +93,7 @@ dist/sql-wasm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FI rm out/tmp-raw.js .PHONY: optimized -optimized: dist/sql-asm.js dist/sql-wasm.js dist/sql-asm-memory-growth.js +optimized: dist/sql-asm.js dist/sql-wasm.js dist/sql-asm-memory-growth.js dist/sql-wasm-module.js dist/sql-asm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ @@ -102,6 +107,9 @@ dist/sql-wasm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $ cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ rm out/tmp-raw.js +dist/sql-wasm-module.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) + $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ESMODULE) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ + dist/sql-asm-memory-growth.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM_MEMORY_GROWTH) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ mv $@ out/tmp-raw.js diff --git a/module.js b/module.js new file mode 100644 index 00000000..63c19fe7 --- /dev/null +++ b/module.js @@ -0,0 +1,5 @@ +import * as wasm from "./dist/sql-wasm-module" + +const def = await wasm.default(); + +export const Database = def.Database; diff --git a/package.json b/package.json index 52b499ec..8fac6116 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ ], "license": "MIT", "main": "./dist/sql-wasm.js", + "module": "./module.js", "scripts": { "build": "make", "rebuild": "npm run clean && npm run build", From 57725483ac570bce27b62d45c36597ad22bf35cc Mon Sep 17 00:00:00 2001 From: Stephen Wan Date: Tue, 3 Jan 2023 00:15:38 +1100 Subject: [PATCH 2/4] *: add browser only build This change prevents webpack and other junk from doing errors like: https://stackoverflow.com/questions/59487224/webpack-throws-error-with-emscripten-cant-resolve-fs Other notes: https://esbuild.github.io/api/#main-fields-for-package-authors --- Makefile | 8 +++++++- module-web.js | 5 +++++ package.json | 3 +++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 module-web.js diff --git a/Makefile b/Makefile index d92cda11..c8bbef3c 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,9 @@ EMFLAGS_ESMODULE= \ -s MODULARIZE=1 \ -s EXPORT_NAME=loadWASM \ +EMFLAGS_WEB= \ + -s ENVIRONMENT=web + EMFLAGS_DEBUG = \ -s ASSERTIONS=1 \ -O1 @@ -93,7 +96,7 @@ dist/sql-wasm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FI rm out/tmp-raw.js .PHONY: optimized -optimized: dist/sql-asm.js dist/sql-wasm.js dist/sql-asm-memory-growth.js dist/sql-wasm-module.js +optimized: dist/sql-asm.js dist/sql-wasm.js dist/sql-asm-memory-growth.js dist/sql-wasm-module.js dist/sql-wasm-module-web.js dist/sql-asm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ @@ -110,6 +113,9 @@ dist/sql-wasm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $ dist/sql-wasm-module.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ESMODULE) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ +dist/sql-wasm-module-web.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) + $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ESMODULE) $(EMFLAGS_WEB) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ + dist/sql-asm-memory-growth.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM_MEMORY_GROWTH) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ mv $@ out/tmp-raw.js diff --git a/module-web.js b/module-web.js new file mode 100644 index 00000000..3b2ae969 --- /dev/null +++ b/module-web.js @@ -0,0 +1,5 @@ +import * as wasm from "./dist/sql-wasm-module-web" + +const def = await wasm.default(); + +export const Database = def.Database; diff --git a/package.json b/package.json index 8fac6116..7d89299b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,9 @@ "license": "MIT", "main": "./dist/sql-wasm.js", "module": "./module.js", + "browser": { + "./module.js": "./module-web.js" + }, "scripts": { "build": "make", "rebuild": "npm run clean && npm run build", From 5aad0daf2bb9c381ae33a475c1c8af7d7ab6916c Mon Sep 17 00:00:00 2001 From: Stephen Wan Date: Tue, 3 Jan 2023 00:59:19 +1100 Subject: [PATCH 3/4] readme: document es module usage --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 4e98ee5e..e4a889bb 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,18 @@ There are a few examples [available here](https://sql-js.github.io/sql.js/index. ## Examples The test files provide up to date example of the use of the api. ### Inside the browser + +#### Using ES Modules +This package supports exports an es module that works with bundlers like webpack: +```js +const SQL = await import("sql.js"); + +const db = new SQL.Database(); +console.log(db.exec("select 1")); +``` + +You may need to enable features in your bundler, e.g. `asyncWebassembly` and `topLevelAwait` in [Webpack 5](https://webpack.js.org/configuration/experiments/). + #### Example **HTML** file: ```html From 7aad773508495a3583af1bd8c4cd3ab4befc518f Mon Sep 17 00:00:00 2001 From: Stephen Wan Date: Thu, 5 Jan 2023 22:22:18 +1000 Subject: [PATCH 4/4] browser/module: fix statement binding This was tricky to figure out. Using the ENVIRONMENT=web flag for the browser build started causing prepared statements to fail - it would behave as if no params were passed to db.exec("...", []) as the second arg. It turns out that the closure compiler was removing the bind() call.. It's not clear to me why, but adding externs that map out the exported structure fixes the issue. Some other notes: - emscripten runs with ADVANCED mode for closure compiler - closure compiler reuses variables... - use --closure-args=--debug and --closure-args=--pretty-print for clues --- Makefile | 3 ++- src/externs.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/externs.js diff --git a/Makefile b/Makefile index c8bbef3c..a720fd7a 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,8 @@ EMFLAGS_WASM = \ EMFLAGS_OPTIMIZED= \ -Oz \ -flto \ - --closure 1 + --closure 1 \ + --closure-args=--externs=./src/externs.js EMFLAGS_ESMODULE= \ -s EXPORT_ES6=1 \ diff --git a/src/externs.js b/src/externs.js new file mode 100644 index 00000000..1bd7e6fe --- /dev/null +++ b/src/externs.js @@ -0,0 +1,49 @@ + +Module.Database = class Database { + constructor(data) {} + run(sql, params) {} + exec(sql, params, config) {} + each(sql, params, callback, done, config) {} + prepare(sql, params) {} + iterateStatements(sql) {} + export() {} + close() {} + handleError(returnCode) {} + getRowsModified() {} + create_function() {} + create_aggregate() {} +} + +Module.Statement = class Statement { + constructor(stmt, db) {} + bind(values) {} + step() {} + getNumber(pos) {} + getBigInt(pos) {} + getString(pos) {} + getBlob(pos) {} + get(params, config) {} + getColumnNames() {} + getAsObject() {} + getSQL() {} + getNormalizedSQL() {} + run(values) {} + bindString(string, pos) {} + bindBlob(array, pos) {} + bindNumber(num, pos) {} + bindNull(pos) {} + bindVlaue(val, pos) {} + bindFromObject(valuesObj) {} + bindFromArray(values) {} + reset() {} + freemem() {} + free() {} +} + +Module.StatementItearator = class StatementIterator { + constructor(sql, obj) {} + next() {} + finalize() {} + getRemainingSQL() {} + // [Symbol.iterator]() {} // XXX: Causes closure compiler error? com.google.javascript.rhino.Node cannot be cast to com.google.javascript.rhino.Node$StringNode +}