Skip to content

Commit

Permalink
update production build wasm support
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Mar 30, 2018
1 parent 5157088 commit f7f9fc6
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 19 deletions.
2 changes: 1 addition & 1 deletion docs/production-build.md
Expand Up @@ -2,7 +2,7 @@

The SystemJS production build supports loading System, AMD and global modules.

The configuration options of `baseURL`, `paths`, `map` and `depCache` are supported identically to the
The configuration options of `baseURL`, `paths`, `map`, `depCache` and `wasm` are supported identically to the
full development build, and as documented at the [configuration API page](config-api.md).

For contextual map configuration, the production build permits objects in the map configuration which act just
Expand Down
2 changes: 1 addition & 1 deletion node-production.js
Expand Up @@ -78,7 +78,7 @@ SystemJSProductionNodeLoader.prototype[SystemJSProductionLoader.instantiate] = f
}));
}

throw new TypeError('SystemJS production does not support loading ES modules. For ES module support see the node-es-module-loader project.');
throw new TypeError('SystemJS production does not support loading ES or WASM modules in Node.');
};

function tryNodeLoad (path) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -20,7 +20,7 @@
"es-module-loader": "^2.2.8",
"mocha": "^3.1.2",
"rimraf": "^2.6.1",
"rollup": "^0.41.1",
"rollup": "~0.57.1",
"rollup-plugin-node-resolve": "^2.0.0",
"rollup-plugin-replace": "^1.1.1",
"systemjs-plugin-babel": "0.0.17",
Expand Down
21 changes: 11 additions & 10 deletions rollup.config.js
Expand Up @@ -12,16 +12,17 @@ else
var name = `system${process.env.production ? '-production' : ''}`;

export default {
entry: `src/${name}.js`,
format: 'iife',
dest: `dist/${name}.src.js`,

sourceMap: true,
sourceMapFile: `dist/${name}.js.map`,

banner: `/*
* SystemJS v${version}
*/`,
input: `src/${name}.js`,

output: {
format: 'iife',
file: `dist/${name}.src.js`,
sourceMap: true,
sourceMapFile: `dist/${name}.js.map`,
banner: `/*
* SystemJS v${version}
*/`
},

plugins: [
nodeResolve({
Expand Down
87 changes: 82 additions & 5 deletions src/systemjs-production-loader.js
Expand Up @@ -115,6 +115,8 @@ systemJSPrototype.config = function (cfg) {
}
}

config.wasm = cfg.wasm === true;

for (var p in cfg) {
if (!Object.hasOwnProperty.call(cfg, p))
continue;
Expand All @@ -125,6 +127,7 @@ systemJSPrototype.config = function (cfg) {
case 'baseURL':
case 'paths':
case 'map':
case 'wasm':
break;

case 'depCache':
Expand Down Expand Up @@ -165,7 +168,8 @@ systemJSPrototype.getConfig = function (name) {
baseURL: config.baseURL,
paths: extend({}, config.paths),
depCache: depCache,
map: map
map: map,
wasm: config.wasm === true
};
};

Expand Down Expand Up @@ -207,8 +211,36 @@ function plainResolve (key, parentKey) {
}
}

function doScriptLoad (loader, url, processAnonRegister) {
function instantiateWasm (loader, response, processAnonRegister) {
return WebAssembly.compileStreaming(response).then(function (module) {
var deps = [];
var setters = [];
var importObj = {};

// we can only set imports if supported (eg early Safari doesnt support)
if (WebAssembly.Module.imports)
WebAssembly.Module.imports(module).forEach(function (i) {
var key = i.module;
setters.push(function (m) {
importObj[key] = m;
});
if (deps.indexOf(key) === -1)
deps.push(key);
});

loader.register(deps, function (_export) {
return {
setters: setters,
execute: function () {
_export(new WebAssembly.Instance(module, importObj).exports);
}
};
});
processAnonRegister();
});
}

function doScriptLoad (loader, url, processAnonRegister) {
// store a global snapshot in case it turns out to be global
globalSnapshot = {};
Object.keys(global).forEach(globalIterator, function (name, value) {
Expand All @@ -227,18 +259,47 @@ function doScriptLoad (loader, url, processAnonRegister) {

// still no registration -> attempt a global detection
if (!registered) {
loader.registerDynamic([], false, function () {
return retrieveGlobal();
loader.register([], function () {
return {
execute: retrieveGlobal
};
});
processAnonRegister();
}
}

resolve();
}, reject);
});
}

function doEvalLoad (loader, url, source, processAnonRegister) {
// store a global snapshot in case it turns out to be global
globalSnapshot = {};
Object.keys(global).forEach(globalIterator, function (name, value) {
globalSnapshot[name] = value;
});

(0, eval)(source + '\n//# sourceURL=' + url);

// check for System.register call
var registered = processAnonRegister();
if (!registered) {
// no System.register -> support named AMD as anonymous
registerLastDefine(loader);
registered = processAnonRegister();

// still no registration -> attempt a global detection
if (!registered) {
loader.register([], function () {
return {
execute: retrieveGlobal
};
});
processAnonRegister();
}
}
}

var globalSnapshot;
function retrieveGlobal () {
var globalValue = { __esModule: true };
Expand Down Expand Up @@ -277,5 +338,21 @@ function coreInstantiate (key, processAnonRegister) {
this.resolve(depCache[i], key).then(preloadScript);
}

if (config.wasm) {
var loader = this;
return fetch(key)
.then(function (res) {
if (!res.ok)
throw new Error('Fetch error: ' + res.status + ' ' + res.statusText);
if (res.headers.get('content-type').indexOf('application/wasm') === -1) {
return res.text()
.then(function (source) {
doEvalLoad(loader, key, source, processAnonRegister);
});
}
return instantiateWasm(loader, res, processAnonRegister);
});
}

return doScriptLoad(this, key, processAnonRegister);
}
16 changes: 15 additions & 1 deletion test/test-production.js
Expand Up @@ -10,7 +10,7 @@ if (typeof document !== 'undefined') {
base = document.baseURI.substr(0, document.baseURI.lastIndexOf('/') + 1);
}
else {
var cwd = process.cwd();
var cwd = process.cwd().replace(/\\/g, '/');
base = 'file://' + (cwd[0] !== '/' ? '/' : '') + cwd + '/test/';
}

Expand Down Expand Up @@ -249,6 +249,20 @@ suite('SystemJS Standard Tests', function() {
});
});
}

if (typeof WebAssembly !== 'undefined' && typeof process === 'undefined')
test('Loading WASM', function () {
System.config({
wasm: true,
map: {
'example': 'tests/wasm/example.js'
}
});
return System.import('tests/wasm/example.wasm')
.then(function (m) {
ok(m.exampleExport(1) === 2);
});
});
});

System.register([], function () { return function () {} });

0 comments on commit f7f9fc6

Please sign in to comment.