Skip to content

Commit 2e3fa51

Browse files
committed
Fix bugs with the modularization
Add a test to ensure that the modularization works correctly. Since we are doing our own modularization rather than relying upon emcc, we have to do a workaround to undo its attempts at exporting the SqlJs Module.
1 parent 1f709a8 commit 2e3fa51

File tree

4 files changed

+80
-10
lines changed

4 files changed

+80
-10
lines changed

src/shell-post.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@
77
return initSqlJsPromise;
88
} // The end of our initSqlJs function
99

10-
// This will allow the module to be used in ES6 or CommonJS
11-
initSqlJs.default = initSqlJs;
10+
// This bit below is copied almost exactly from what you get when you use the MODULARIZE=1 flag with emcc
11+
// However, we don't want to use the emcc modularization. See shell-pre.js
1212
if (typeof exports === 'object' && typeof module === 'object'){
1313
module.exports = initSqlJs;
14+
// This will allow the module to be used in ES6 or CommonJS
15+
module.exports.default = initSqlJs;
1416
}
15-
17+
else if (typeof define === 'function' && define['amd']) {
18+
define([], function() { return initSqlJs; });
19+
}
20+
else if (typeof exports === 'object'){
21+
exports["Module"] = initSqlJs;
22+
}
23+

src/shell-pre.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11

22
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
33
// https://github.com/kripken/emscripten/issues/5820
4-
// This module exports a promise that loads and resolves to the actual sql.js module.
4+
// In addition, When you use emcc's modularization, it still expects to export a global object called `Module`,
5+
// which is able to be used/called before the WASM is loaded.
6+
// The modularization below exports a promise that loads and resolves to the actual sql.js module.
57
// That way, this module can't be used before the WASM is finished loading.
68

7-
8-
// So the first thing that this module does is define a place for the loadedModule to reside
9-
109
// We are going to define a function that a user will call to start loading initializing our Sql.js library
11-
// However, that function might be called multiple times, and on subsequent calls, we want it to return the same module that it's already loaded once before.
10+
// 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
11+
// Instead, we want to return the previously loaded module
1212

13+
// TODO: Make this not declare a global if used in the browser
1314
var initSqlJsPromise = undefined;
1415

1516
var initSqlJs = function (moduleConfig) {
@@ -18,7 +19,7 @@ var initSqlJs = function (moduleConfig) {
1819
return initSqlJsPromise;
1920
}
2021
// If we're here, we've never called this function before
21-
initSqlJsPromise = new Promise((resolveModule) => {
22+
initSqlJsPromise = new Promise((resolveModule, reject) => {
2223

2324
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
2425
// https://github.com/kripken/emscripten/issues/5820
@@ -47,6 +48,24 @@ var initSqlJs = function (moduleConfig) {
4748
// When Emscripted calls postRun, this promise resolves with the built Module
4849
resolveModule(Module);
4950
});
51+
52+
// There is a section of code in the emcc-generated code below that looks like this:
53+
// (Note that this is lowercase `module`)
54+
// if (typeof module !== 'undefined') {
55+
// module['exports'] = Module;
56+
// }
57+
// When that runs, it's going to overwrite our own modularization export efforts in shell-post.js!
58+
// The only way to tell emcc not to emit it is to pass the MODULARIZE=1 or MODULARIZE_INSTANCE=1 flags,
59+
// but that carries with it additional unnecessary baggage/bugs we don't want either.
60+
// So, we have three options:
61+
// 1) We undefine `module`
62+
// 2) We remember what `module['exports']` was at the beginning of this function and we restore it later
63+
// 3) We write a script to remove those lines of code as part of the Make process.
64+
//
65+
// Since those are the only lines of code that care about module, we will undefine it. It's the most straightforward
66+
// of the options, and has the side effect of reducing emcc's efforts to modify the module if its output were to change in the future.
67+
// That's a nice side effect since we're handling the modularization efforts ourselves
68+
module = undefined;
5069

5170
// The emcc-generated code and shell-post.js code goes below,
5271
// meaning that all of it runs inside of this promise. If anything throws an exception, our promise will abort

test/load_sql_lib.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
module.exports = function(sqlLibraryType){
2-
var sqlLibraryType = process.argv[2];
32
// Use sql-wasm.js by default
43
var sqlJsLib = sqlLibraryType ? "../dist/sql-"+sqlLibraryType+".js" : "../dist/sql-wasm.js";
54
begin = new Date();

test/test_modularization.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
exports.test = function (SQL, assert, done, sqlLibFilename) {
3+
if (!sqlLibFilename){
4+
// Whew - this is ugly and fragile and makes way too many assumptions about how these tests are run from all.js
5+
// However, this is the quickest way to make sure that we are testing the lib that is requested
6+
const targetFile = process.argv[2];
7+
sqlLibFilename = targetFile ? "../dist/sql-"+targetFile+".js" : "../dist/sql-wasm.js";
8+
}
9+
10+
var initSqlJsLib1 = require(sqlLibFilename);
11+
initSqlJsLib1().then((sqlModule1) => {
12+
var initSqlJsLib2 = require(sqlLibFilename);
13+
initSqlJsLib2().then((sqlModule2) => {
14+
assert.equal(SQL, sqlModule1, "Initializing the module multiple times only creates it once");
15+
assert.equal(sqlModule1, sqlModule2, "Initializing the module multiple times only creates it once");
16+
var db1 = new sqlModule1.Database();
17+
assert.equal(Object.getPrototypeOf(db1), SQL.Database.prototype, "sqlModule1 has a Database object that has the same prototype as the originally loaded SQL module");
18+
assert.equal(Object.getPrototypeOf(db1), sqlModule2.Database.prototype, "sqlModule1 has a Database object that has the same prototype as the sqlModule2");
19+
20+
21+
var db2 = new sqlModule2.Database();
22+
assert.equal(Object.getPrototypeOf(db2), sqlModule1.Database.prototype, "sqlModule2 has a Database object that has the same prototype as the sqlModule1");
23+
24+
done();
25+
});
26+
});
27+
};
28+
29+
if (module == require.main) {
30+
const targetFile = process.argv[2];
31+
const loadSqlLib = require('./load_sql_lib');
32+
loadSqlLib(targetFile).then((sql) => {
33+
require('test').run({
34+
'test modularization': function (assert, done) {
35+
// TODO: Dry this up so that this code isn't duped between here and load_sql_lib.js
36+
var sqlJsLibFilename = targetFile ? "../dist/sql-"+targetFile+".js" : "../dist/sql-wasm.js";
37+
exports.test(sql, assert, done, sqlJsLibFilename);
38+
}
39+
})
40+
})
41+
.catch((e) => {
42+
console.error(e);
43+
});
44+
}

0 commit comments

Comments
 (0)