diff --git a/.eslintrc.js b/.eslintrc.js index 02e6047c..5187188f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,6 +21,8 @@ module.exports = { "/out/", "/src/shell-post.js", "/src/shell-pre.js", + "/src/shell-post-esm.js", + "/src/shell-pre-esm.js", "/test/", "!/.eslintrc.js" ], diff --git a/Makefile b/Makefile index 45306539..a4c5e56b 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ EXPORTED_METHODS_JSON_FILES = src/exported_functions.json src/exported_runtime_m all: optimized debug worker .PHONY: debug -debug: dist/sql-asm-debug.js dist/sql-wasm-debug.js +debug: dist/sql-asm-debug.js dist/sql-wasm-debug.js dist/sql-wasm-esm-debug.js dist/sql-asm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) $(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ @@ -87,8 +87,14 @@ dist/sql-wasm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FI cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@ rm out/tmp-raw.js +dist/sql-wasm-esm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) + $(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ + mv $@ out/tmp-raw.js + cat src/shell-pre-esm.js out/tmp-raw.js src/shell-post-esm.js > $@ + 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-wasm-esm.js dist/sql-asm-memory-growth.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 +108,12 @@ 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-esm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES) + $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@ + mv $@ out/tmp-raw.js + cat src/shell-pre-esm.js out/tmp-raw.js src/shell-post-esm.js > $@ + rm out/tmp-raw.js + 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/src/shell-post-esm.js b/src/shell-post-esm.js new file mode 100644 index 00000000..882f9094 --- /dev/null +++ b/src/shell-post-esm.js @@ -0,0 +1,10 @@ + + + // The shell-pre.js and emcc-generated code goes above + return Module; + }); // The end of the promise being returned + + return initSqlJsPromise; +} // The end of our initSqlJs function + +export = initSqlJs; diff --git a/src/shell-pre-esm.js b/src/shell-pre-esm.js new file mode 100644 index 00000000..3803df09 --- /dev/null +++ b/src/shell-pre-esm.js @@ -0,0 +1,50 @@ + +// We are modularizing this manually because the current modularize setting in Emscripten has some issues: +// https://github.com/kripken/emscripten/issues/5820 +// In addition, When you use emcc's modularization, it still expects to export a global object called `Module`, +// which is able to be used/called before the WASM is loaded. +// The modularization below exports a promise that loads and resolves to the actual sql.js module. +// That way, this module can't be used before the WASM is finished loading. + +// We are going to define a function that a user will call to start loading initializing our Sql.js library +// However, that function might be called multiple times, and on subsequent calls, we don't actually want it to instantiate a new instance of the Module +// Instead, we want to return the previously loaded module + +// TODO: Make this not declare a global if used in the browser +var initSqlJsPromise = undefined; + +var initSqlJs = function (moduleConfig) { + + if (initSqlJsPromise){ + return initSqlJsPromise; + } + // If we're here, we've never called this function before + initSqlJsPromise = new Promise(function (resolveModule, reject) { + + // We are modularizing this manually because the current modularize setting in Emscripten has some issues: + // https://github.com/kripken/emscripten/issues/5820 + + // The way to affect the loading of emcc compiled modules is to create a variable called `Module` and add + // properties to it, like `preRun`, `postRun`, etc + // We are using that to get notified when the WASM has finished loading. + // Only then will we return our promise + + // If they passed in a moduleConfig object, use that + // Otherwise, initialize Module to the empty object + var Module = typeof moduleConfig !== 'undefined' ? moduleConfig : {}; + + // EMCC only allows for a single onAbort function (not an array of functions) + // So if the user defined their own onAbort function, we remember it and call it + var originalOnAbortFunction = Module['onAbort']; + Module['onAbort'] = function (errorThatCausedAbort) { + reject(new Error(errorThatCausedAbort)); + if (originalOnAbortFunction){ + originalOnAbortFunction(errorThatCausedAbort); + } + }; + + Module['postRun'] = Module['postRun'] || []; + Module['postRun'].push(function () { + // When Emscripted calls postRun, this promise resolves with the built Module + resolveModule(Module); + });