mirror of https://github.com/webpack/webpack.git
				
				
				
			Merge pull request #6160 from webpack/wasm/imports
add support for imports in wasm modules
This commit is contained in:
		
						commit
						c6c447b42c
					
				|  | @ -0,0 +1,5 @@ | |||
| var supportsWebAssembly = require("../../test/helpers/supportsWebAssembly"); | ||||
| 
 | ||||
| module.exports = function(config) { | ||||
| 	return supportsWebAssembly(); | ||||
| }; | ||||
|  | @ -5,12 +5,15 @@ | |||
| "use strict"; | ||||
| 
 | ||||
| const WebAssemblyParser = require("./WebAssemblyParser"); | ||||
| const WebAssemblyImportDependency = require("./dependencies/WebAssemblyImportDependency"); | ||||
| 
 | ||||
| class WebAssemblyModulesPlugin { | ||||
| 	apply(compiler) { | ||||
| 		compiler.hooks.compilation.tap("WebAssemblyModulesPlugin", (compilation, { | ||||
| 			normalModuleFactory | ||||
| 		}) => { | ||||
| 			compilation.dependencyFactories.set(WebAssemblyImportDependency, normalModuleFactory); | ||||
| 
 | ||||
| 			normalModuleFactory.hooks.createParser.for("webassembly/experimental").tap("WebAssemblyModulesPlugin", () => { | ||||
| 				return new WebAssemblyParser(); | ||||
| 			}); | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
 | ||||
| 
 | ||||
| const Tapable = require("tapable").Tapable; | ||||
| const WebAssemblyImportDependency = require("./dependencies/WebAssemblyImportDependency"); | ||||
| 
 | ||||
| class WebAssemblyParser extends Tapable { | ||||
| 	constructor(options) { | ||||
|  | @ -29,10 +30,13 @@ class WebAssemblyParser extends Tapable { | |||
| 		if(typeof WebAssembly !== "undefined") { | ||||
| 			WebAssembly.compile(source).then(module => { | ||||
| 				state.module.buildMeta.providedExports = WebAssembly.Module.exports(module).map(exp => exp.name); | ||||
| 				for(const imp of WebAssembly.Module.imports(module)) { | ||||
| 					const dep = new WebAssemblyImportDependency(imp.module, imp.name, imp.kind); | ||||
| 					state.module.addDependency(dep); | ||||
| 				} | ||||
| 			}).then(() => callback(null, state), err => callback(err)); | ||||
| 		} else { | ||||
| 			state.module.buildMeta.providedExports = false; | ||||
| 			callback(null, state); | ||||
| 			throw new Error("Can't compile WebAssembly modules without WebAssembly support in current node.js version (Update to latest node.js version)"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,27 @@ | |||
| /* | ||||
| 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||||
| 	Author Tobias Koppers @sokra | ||||
| */ | ||||
| "use strict"; | ||||
| const ModuleDependency = require("./ModuleDependency"); | ||||
| 
 | ||||
| class WebAssemblyImportDependency extends ModuleDependency { | ||||
| 	constructor(request, name) { | ||||
| 		super(request); | ||||
| 		this.name = name; | ||||
| 	} | ||||
| 
 | ||||
| 	getReference() { | ||||
| 		if(!this.module) return null; | ||||
| 		return { | ||||
| 			module: this.module, | ||||
| 			importedNames: [this.name] | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
| 	get type() { | ||||
| 		return "wasm import"; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| module.exports = WebAssemblyImportDependency; | ||||
|  | @ -5,6 +5,7 @@ | |||
| "use strict"; | ||||
| 
 | ||||
| const RawSource = require("webpack-sources").RawSource; | ||||
| const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); | ||||
| 
 | ||||
| class WasmModuleTemplatePlugin { | ||||
| 	apply(moduleTemplate) { | ||||
|  | @ -30,11 +31,40 @@ class WasmModuleTemplatePlugin { | |||
| 						return `${module.moduleArgument}.exports = instance.exports;`; | ||||
| 					} | ||||
| 				}; | ||||
| 				const generateImports = () => { | ||||
| 					const depsByRequest = new Map(); | ||||
| 					for(const dep of module.dependencies) { | ||||
| 						if(dep instanceof WebAssemblyImportDependency) { | ||||
| 							const request = dep.request; | ||||
| 							let array = depsByRequest.get(request); | ||||
| 							if(!array) { | ||||
| 								depsByRequest.set(request, array = []); | ||||
| 							} | ||||
| 							const exportName = dep.name; | ||||
| 							const usedName = dep.module && dep.module.isUsed(exportName); | ||||
| 							array.push({ | ||||
| 								exportName, | ||||
| 								usedName, | ||||
| 								module: dep.module | ||||
| 							}); | ||||
| 						} | ||||
| 					} | ||||
| 					const importsCode = []; | ||||
| 					for(const pair of depsByRequest) { | ||||
| 						const properties = []; | ||||
| 						for(const data of pair[1]) { | ||||
| 							properties.push(`\n\t\t${JSON.stringify(data.exportName)}: __webpack_require__(${JSON.stringify(data.module.id)})[${JSON.stringify(data.usedName)}]`); | ||||
| 						} | ||||
| 						importsCode.push(`\n\t${JSON.stringify(pair[0])}: {${properties.join(",")}\n\t}`); | ||||
| 					} | ||||
| 					return importsCode.join(","); | ||||
| 				}; | ||||
| 				const source = new RawSource([ | ||||
| 					"\"use strict\";", | ||||
| 					"", | ||||
| 					"// Instanciate WebAssembly module", | ||||
| 					"var instance = new WebAssembly.Instance(__webpack_require__.w[module.i], {});", | ||||
| 					"var instance = new WebAssembly.Instance(__webpack_require__.w[module.i], {" + generateImports(), | ||||
| 					"});", | ||||
| 					"", | ||||
| 					"// export exports from WebAssmbly module", | ||||
| 					// TODO rewrite this to getters depending on exports to support circular dependencies
 | ||||
|  |  | |||
|  | @ -11,6 +11,11 @@ describe("Examples", () => { | |||
| 	const examples = require("../examples/examples.js"); | ||||
| 
 | ||||
| 	examples.forEach((examplePath) => { | ||||
| 		const filterPath = path.join(examplePath, "test.filter.js"); | ||||
| 		if(fs.existsSync(filterPath) && !require(filterPath)()) { | ||||
| 			describe.skip(path.relative(basePath, examplePath), () => it("filtered")); | ||||
| 			return; | ||||
| 		} | ||||
| 		it("should compile " + path.relative(basePath, examplePath), function(done) { | ||||
| 			this.timeout(20000); | ||||
| 			let options = {}; | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| it("should allow to run a WebAssembly module with imports", function() { | ||||
| 	return import("./wasm.wasm").then(function(wasm) { | ||||
| 		const result = wasm.addNumber(20); | ||||
| 		result.should.be.eql(42); | ||||
| 	}); | ||||
| }); | ||||
|  | @ -0,0 +1,5 @@ | |||
| var supportsWebAssembly = require("../../../helpers/supportsWebAssembly"); | ||||
| 
 | ||||
| module.exports = function(config) { | ||||
| 	return supportsWebAssembly(); | ||||
| }; | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,5 @@ | |||
| it("should allow to run a WebAssembly module importing JS circular", function() { | ||||
| 	return import("./module").then(function(mod) { | ||||
| 		mod.result.should.be.eql(42); | ||||
| 	}); | ||||
| }); | ||||
|  | @ -0,0 +1,7 @@ | |||
| import { addNumber } from "./wasm.wasm"; | ||||
| 
 | ||||
| export var result = addNumber(22); | ||||
| 
 | ||||
| export function getNumber() { | ||||
| 	return 20; | ||||
| } | ||||
|  | @ -0,0 +1,5 @@ | |||
| var supportsWebAssembly = require("../../../helpers/supportsWebAssembly"); | ||||
| 
 | ||||
| module.exports = function(config) { | ||||
| 	return supportsWebAssembly(); | ||||
| }; | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,6 @@ | |||
| it("should allow to run a WebAssembly module with imports", function() { | ||||
| 	return import("./wasm.wasm?1").then(function(wasm) { | ||||
| 		const result = wasm.addNumber(3); | ||||
| 		result.should.be.eql(11); | ||||
| 	}); | ||||
| }); | ||||
|  | @ -0,0 +1,3 @@ | |||
| export function getNumber() { | ||||
| 	return 8; | ||||
| } | ||||
|  | @ -0,0 +1,5 @@ | |||
| var supportsWebAssembly = require("../../../helpers/supportsWebAssembly"); | ||||
| 
 | ||||
| module.exports = function(config) { | ||||
| 	return supportsWebAssembly(); | ||||
| }; | ||||
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue