Merge pull request #7144 from webpack/next

Upgrade to the WASM toolchain
This commit is contained in:
Tobias Koppers 2018-05-07 12:15:48 +02:00 committed by GitHub
commit 00b0364c8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1349 additions and 541 deletions

63
declarations.d.ts vendored
View File

@ -29,6 +29,69 @@ declare module "chrome-trace-event" {
}
}
// There are no typings for @webassemblyjs/ast
declare module "@webassemblyjs/ast" {
export function traverse(
ast: any,
visitor: { [name: string]: (context: { node: Node }) => void }
);
export class Node {
index: number;
}
export class Identifier extends Node {
value: string;
}
export class ModuleImport extends Node {
module: string;
descr: {
type: string;
valtype: string;
};
name: string;
}
export class ModuleExport extends Node {
name: string;
}
export class IndexLiteral extends Node {}
export class NumberLiteral extends Node {}
export class Global extends Node {}
export class FuncParam extends Node {}
export class Instruction extends Node {}
export class CallInstruction extends Instruction {}
export class ObjectInstruction extends Instruction {}
export class Func extends Node {
signature: Signature;
}
export class Signature {
params: any;
result: any;
}
export class TypeInstructionFunc extends Node {}
export class IndexInFuncSection extends Node {}
export function indexLiteral(index: number): IndexLiteral;
export function numberLiteral(num: number): NumberLiteral;
export function global(globalType: string, nodes: Node[]): Global;
export function identifier(indentifier: string): Identifier;
export function funcParam(valType: string, id: Identifier): FuncParam;
export function instruction(inst: string, args: Node[]): Instruction;
export function callInstruction(funcIndex: IndexLiteral): CallInstruction;
export function objectInstruction(
kind: string,
type: string,
init: Node[]
): ObjectInstruction;
export function func(initFuncId, funcParams, funcResults, funcBody): Func;
export function typeInstructionFunc(params, result): TypeInstructionFunc;
export function indexInFuncSection(index: IndexLiteral): IndexInFuncSection;
export function moduleExport(
identifier: string,
type: string,
index: IndexLiteral
): ModuleExport;
export function getSectionMetadata(ast: any, section: string);
}
/**
* Global variable declarations
* @todo Once this issue is resolved, remove these globals and add JSDoc onsite instead

View File

@ -230,8 +230,8 @@ class Compilation extends Tapable {
this.requestShortener
);
this.moduleTemplates = {
javascript: new ModuleTemplate(this.runtimeTemplate),
webassembly: new ModuleTemplate(this.runtimeTemplate)
javascript: new ModuleTemplate(this.runtimeTemplate, "javascript"),
webassembly: new ModuleTemplate(this.runtimeTemplate, "webassembly")
};
this.semaphore = new Semaphore(options.parallelism || 100);

52
lib/Generator.js Normal file
View File

@ -0,0 +1,52 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
/** @typedef {import("./Module")} Module */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("webpack-sources").Source} Source */
/**
*
*/
class Generator {
static byType(map) {
return new ByTypeGenerator(map);
}
/**
* @abstract
* @param {Module} module module for which the code should be generated
* @param {Map<Function, any>} dependencyTemplates mapping from dependencies to templates
* @param {RuntimeTemplate} runtimeTemplate the runtime template
* @param {string} type which kind of code should be generated
* @returns {Source} generated code
*/
generate(module, dependencyTemplates, runtimeTemplate, type) {
throw new Error("Generator.generate: must be overriden");
}
}
class ByTypeGenerator extends Generator {
constructor(map) {
super();
this.map = map;
}
generate(module, dependencyTemplates, runtimeTemplate, type) {
const generator = this.map[type];
if (!generator) {
throw new Error(`Generator.byType: no generator specified for ${type}`);
}
return generator.generate(
module,
dependencyTemplates,
runtimeTemplate,
type
);
}
}
module.exports = Generator;

View File

@ -7,9 +7,10 @@
const { Tapable, SyncWaterfallHook, SyncHook } = require("tapable");
module.exports = class ModuleTemplate extends Tapable {
constructor(runtimeTemplate) {
constructor(runtimeTemplate, type) {
super();
this.runtimeTemplate = runtimeTemplate;
this.type = type;
this.hooks = {
content: new SyncWaterfallHook([
"source",
@ -40,34 +41,40 @@ module.exports = class ModuleTemplate extends Tapable {
}
render(module, dependencyTemplates, options) {
const moduleSource = module.source(
dependencyTemplates,
this.runtimeTemplate
);
const moduleSourcePostContent = this.hooks.content.call(
moduleSource,
module,
options,
dependencyTemplates
);
const moduleSourcePostModule = this.hooks.module.call(
moduleSourcePostContent,
module,
options,
dependencyTemplates
);
const moduleSourcePostRender = this.hooks.render.call(
moduleSourcePostModule,
module,
options,
dependencyTemplates
);
return this.hooks.package.call(
moduleSourcePostRender,
module,
options,
dependencyTemplates
);
try {
const moduleSource = module.source(
dependencyTemplates,
this.runtimeTemplate,
this.type
);
const moduleSourcePostContent = this.hooks.content.call(
moduleSource,
module,
options,
dependencyTemplates
);
const moduleSourcePostModule = this.hooks.module.call(
moduleSourcePostContent,
module,
options,
dependencyTemplates
);
const moduleSourcePostRender = this.hooks.render.call(
moduleSourcePostModule,
module,
options,
dependencyTemplates
);
return this.hooks.package.call(
moduleSourcePostRender,
module,
options,
dependencyTemplates
);
} catch (e) {
e.message = `${module.identifier()}\n${e.message}`;
throw e;
}
}
updateHash(hash) {

View File

@ -62,6 +62,12 @@ class NonErrorEmittedError extends WebpackError {
}
}
/**
* @typedef {Object} CachedSourceEntry
* @property {any} source the generated source
* @property {string} hash the hash value
*/
class NormalModule extends Module {
constructor({
type,
@ -92,8 +98,8 @@ class NormalModule extends Module {
this._source = null;
this._buildHash = "";
this.buildTimestamp = undefined;
this._cachedSource = undefined;
this._cachedSourceHash = undefined;
/** @private @type {Map<string, CachedSourceEntry>} */
this._cachedSources = new Map();
// Options for the NormalModule set by plugins
// TODO refactor this -> options object filled from Factory
@ -357,8 +363,7 @@ class NormalModule extends Module {
};
return this.doBuild(options, compilation, resolver, fs, err => {
this._cachedSource = undefined;
this._cachedSourceHash = undefined;
this._cachedSources.clear();
// if we have an error mark module as failed and exit
if (err) {
@ -421,22 +426,26 @@ class NormalModule extends Module {
return `${this.hash}-${dtHash}`;
}
source(dependencyTemplates, runtimeTemplate) {
source(dependencyTemplates, runtimeTemplate, type = "javascript") {
const hashDigest = this.getHashDigest(dependencyTemplates);
if (this._cachedSourceHash === hashDigest) {
const cacheEntry = this._cachedSources.get(type);
if (cacheEntry !== undefined && cacheEntry.hash === hashDigest) {
// We can reuse the cached source
return this._cachedSource;
return cacheEntry.source;
}
const source = this.generator.generate(
this,
dependencyTemplates,
runtimeTemplate
runtimeTemplate,
type
);
const cachedSource = new CachedSource(source);
this._cachedSource = cachedSource;
this._cachedSourceHash = hashDigest;
this._cachedSources.set(type, {
source: cachedSource,
hash: hashDigest
});
return cachedSource;
}

View File

@ -1,13 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
class WebAssemblyGenerator {
generate(module) {
return module.originalSource();
}
}
module.exports = WebAssemblyGenerator;

View File

@ -1,50 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
/* globals WebAssembly */
"use strict";
// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
const { Tapable } = require("tapable");
const WebAssemblyImportDependency = require("./dependencies/WebAssemblyImportDependency");
class WebAssemblyParser extends Tapable {
constructor(options) {
super();
this.hooks = {};
this.options = options;
}
parse(source, state, callback) {
// TODO parse WASM AST and walk it
// TODO extract imports
// flag it as ESM
state.module.buildMeta.exportsType = "namespace";
// extract exports
// TODO find more efficient way doing it
// TODO use Promises
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);
state.module.addDependency(dep);
}
})
.then(() => callback(null, state), err => callback(err));
} else {
throw new Error(
"Can't compile WebAssembly modules without WebAssembly support in current node.js version (Update to latest node.js version)"
);
}
}
}
module.exports = WebAssemblyParser;

View File

@ -8,7 +8,7 @@ const OptionsApply = require("./OptionsApply");
const JavascriptModulesPlugin = require("./JavascriptModulesPlugin");
const JsonModulesPlugin = require("./JsonModulesPlugin");
const WebAssemblyModulesPlugin = require("./WebAssemblyModulesPlugin");
const WebAssemblyModulesPlugin = require("./wasm/WebAssemblyModulesPlugin");
const LoaderTargetPlugin = require("./LoaderTargetPlugin");
const FunctionModulePlugin = require("./FunctionModulePlugin");

View File

@ -6,11 +6,14 @@
const DependencyReference = require("./DependencyReference");
const ModuleDependency = require("./ModuleDependency");
const UnsupportedWebAssemblyFeatureError = require("../wasm/UnsupportedWebAssemblyFeatureError");
class WebAssemblyImportDependency extends ModuleDependency {
constructor(request, name) {
constructor(request, name, description, onlyDirectImport) {
super(request);
this.name = name;
this.description = description;
this.onlyDirectImport = onlyDirectImport;
}
getReference() {
@ -18,6 +21,21 @@ class WebAssemblyImportDependency extends ModuleDependency {
return new DependencyReference(this.module, [this.name], false);
}
getErrors() {
if (
this.onlyDirectImport &&
this.module &&
!this.module.type.startsWith("webassembly")
) {
const type = this.description.type;
return [
new UnsupportedWebAssemblyFeatureError(
`${type} imports are only available for direct wasm to wasm dependencies`
)
];
}
}
get type() {
return "wasm import";
}

View File

@ -1,113 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Template = require("../Template");
class ReadFileCompileWasmMainTemplatePlugin {
apply(mainTemplate) {
mainTemplate.hooks.localVars.tap(
"ReadFileCompileWasmMainTemplatePlugin",
(source, chunk) => {
return Template.asString([
source,
"",
"// object to store loaded and loading wasm modules",
"var installedWasmModules = {};"
]);
}
);
mainTemplate.hooks.requireEnsure.tap(
"ReadFileCompileWasmMainTemplatePlugin",
(source, chunk, hash) => {
const webassemblyModuleFilename =
mainTemplate.outputOptions.webassemblyModuleFilename;
const chunkModuleMaps = chunk.getChunkModuleMaps(m =>
m.type.startsWith("webassembly")
);
if (Object.keys(chunkModuleMaps.id).length === 0) return source;
const wasmModuleSrcPath = mainTemplate.getAssetPath(
JSON.stringify(webassemblyModuleFilename),
{
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
hashWithLength: length =>
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
module: {
id: '" + wasmModuleId + "',
hash: `" + ${JSON.stringify(
chunkModuleMaps.hash
)}[wasmModuleId] + "`,
hashWithLength(length) {
const shortChunkHashMap = Object.create(null);
for (const wasmModuleId of Object.keys(chunkModuleMaps.hash)) {
if (typeof chunkModuleMaps.hash[wasmModuleId] === "string")
shortChunkHashMap[wasmModuleId] = chunkModuleMaps.hash[
wasmModuleId
].substr(0, length);
}
return `" + ${JSON.stringify(
shortChunkHashMap
)}[wasmModuleId] + "`;
}
}
}
);
return Template.asString([
source,
"",
"// ReadFile + compile chunk loading for webassembly",
"",
`var wasmModules = ${JSON.stringify(
chunkModuleMaps.id
)}[chunkId] || [];`,
"",
"wasmModules.forEach(function(wasmModuleId) {",
Template.indent([
"var installedWasmModuleData = installedWasmModules[wasmModuleId];",
"",
'// a Promise means "currently loading" or "already loaded".',
"promises.push(installedWasmModuleData ||",
Template.indent([
"(installedWasmModules[wasmModuleId] = new Promise(function(resolve, reject) {",
Template.indent([
`require('fs').readFile(require('path').resolve(__dirname, ${wasmModuleSrcPath}), function(err, buffer) {`,
Template.indent([
"if(err) return reject(err);",
"resolve(WebAssembly.compile(buffer));"
]),
"});"
]),
`}).then(function(module) { ${
mainTemplate.requireFn
}.w[wasmModuleId] = module; }))`
]),
");"
]),
"});"
]);
}
);
mainTemplate.hooks.requireExtensions.tap(
"ReadFileCompileWasmMainTemplatePlugin",
(source, chunk) => {
return Template.asString([
source,
"",
"// object with all compiled WebAssembly.Modules",
`${mainTemplate.requireFn}.w = {};`
]);
}
);
mainTemplate.hooks.hash.tap(
"ReadFileCompileWasmMainTemplatePlugin",
hash => {
hash.update("ReadFileCompileWasmMainTemplatePlugin");
hash.update("1");
hash.update(`${mainTemplate.outputOptions.webassemblyModuleFilename}`);
}
);
}
}
module.exports = ReadFileCompileWasmMainTemplatePlugin;

View File

@ -4,20 +4,46 @@
*/
"use strict";
const ReadFileCompileWasmMainTemplatePlugin = require("./ReadFileCompileWasmMainTemplatePlugin");
const WasmModuleTemplatePlugin = require("../wasm/WasmModuleTemplatePlugin");
const Template = require("../Template");
const WasmMainTemplatePlugin = require("../wasm/WasmMainTemplatePlugin");
class ReadFileCompileWasmTemplatePlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap(
"ReadFileCompileWasmTemplatePlugin",
compilation => {
new ReadFileCompileWasmMainTemplatePlugin().apply(
compilation.mainTemplate
);
new WasmModuleTemplatePlugin().apply(
compilation.moduleTemplates.javascript
const generateLoadBinaryCode = path =>
Template.asString([
"new Promise(function (resolve, reject) {",
Template.indent([
"var { readFile } = require('fs');",
"var { join } = require('path');",
"",
"try {",
Template.indent([
`readFile(join(__dirname, ${path}), function(err, buffer){`,
Template.indent([
"if (err) return reject(err);",
"",
"// Fake fetch response",
"resolve({",
Template.indent([
"arrayBuffer() { return Promise.resolve(buffer); }"
]),
"});"
]),
"});"
]),
"} catch (err) { reject(err); }"
]),
"})"
]);
const plugin = new WasmMainTemplatePlugin(
generateLoadBinaryCode,
false
);
plugin.apply(compilation.mainTemplate);
}
);
}

View File

@ -0,0 +1,18 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const WebpackError = require("../WebpackError");
module.exports = class UnsupportedWebAssemblyFeatureError extends WebpackError {
/** @param {string} message Error message */
constructor(message) {
super();
this.name = "UnsupportedWebAssemblyFeatureError";
this.message = message;
this.hideStack = true;
Error.captureStackTrace(this, this.constructor);
}
};

View File

@ -0,0 +1,304 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Template = require("../Template");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
// Get all wasm modules
function getAllWasmModules(chunk) {
const wasmModules = chunk.getAllAsyncChunks();
const array = [];
for (const chunk of wasmModules) {
for (const m of chunk.modulesIterable) {
if (m.type.startsWith("webassembly")) {
array.push(m);
}
}
}
return array;
}
function generateImportObject(module) {
const depsByRequest = new Map();
for (const dep of module.dependencies) {
if (dep instanceof WebAssemblyImportDependency) {
// Ignore global they will be handled later
if (dep.description.type === "GlobalType") {
continue;
}
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);
if (dep.module === null) {
// Dependency was not found, an error will be thrown later
continue;
}
if (usedName !== false) {
array.push({
exportName,
usedName,
module: dep.module,
description: dep.description,
direct: dep.onlyDirectImport
});
}
}
}
const importsCode = [];
const waitForPromises = new Map();
for (const pair of depsByRequest) {
const properties = [];
for (const data of pair[1]) {
if (data.direct) {
const instanceVar = `m${waitForPromises.size}`;
waitForPromises.set(
instanceVar,
`installedWasmModules[${JSON.stringify(data.module.id)}]`
);
properties.push(
`${JSON.stringify(data.exportName)}: ${instanceVar}.exports` +
`[${JSON.stringify(data.exportName)}]`
);
} else {
const params = data.description.signature.params.map(
(param, k) => "p" + k + param.valtype
);
const result = `__webpack_require__(${JSON.stringify(
data.module.id
)})[${JSON.stringify(data.usedName)}](${params})`;
properties.push(
Template.asString([
`${JSON.stringify(data.exportName)}: function(${params}) {`,
Template.indent([`return ${result};`]),
"}"
])
);
}
}
importsCode.push(
Template.asString([
`${JSON.stringify(pair[0])}: {`,
Template.indent([properties.join(",")]),
"}"
])
);
}
if (waitForPromises.size > 0) {
const promises = Array.from(waitForPromises.values()).join(", ");
const variables = Array.from(
waitForPromises.keys(),
(name, i) => `var ${name} = array[${i}];`
).join("\n");
return Template.asString([
`${JSON.stringify(module.id)}: function() {`,
Template.indent([
`return Promise.resolve().then(function() { return Promise.all([${promises}]); }).then(function(array) {`,
Template.indent([
variables,
"return {",
Template.indent([importsCode.join(",")]),
"};"
]),
"});"
]),
"},"
]);
} else {
return Template.asString([
`${JSON.stringify(module.id)}: function() {`,
Template.indent([
"return {",
Template.indent([importsCode.join(",")]),
"};"
]),
"},"
]);
}
}
class WasmMainTemplatePlugin {
constructor(generateLoadBinaryCode, supportsStreaming) {
this.generateLoadBinaryCode = generateLoadBinaryCode;
this.supportsStreaming = supportsStreaming;
}
apply(mainTemplate) {
mainTemplate.hooks.localVars.tap(
"WasmMainTemplatePlugin",
(source, chunk) => {
const wasmModules = getAllWasmModules(chunk);
if (wasmModules.length === 0) return source;
const importObjects = wasmModules.map(generateImportObject);
return Template.asString([
source,
"",
"// object to store loaded and loading wasm modules",
"var installedWasmModules = {};",
"",
"var wasmImportObjects = {",
Template.indent(importObjects),
"};"
]);
}
);
mainTemplate.hooks.requireEnsure.tap(
"WasmMainTemplatePlugin",
(source, chunk, hash) => {
const webassemblyModuleFilename =
mainTemplate.outputOptions.webassemblyModuleFilename;
const chunkModuleMaps = chunk.getChunkModuleMaps(m =>
m.type.startsWith("webassembly")
);
if (Object.keys(chunkModuleMaps.id).length === 0) return source;
const wasmModuleSrcPath = mainTemplate.getAssetPath(
JSON.stringify(webassemblyModuleFilename),
{
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
hashWithLength: length =>
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
module: {
id: '" + wasmModuleId + "',
hash: `" + ${JSON.stringify(
chunkModuleMaps.hash
)}[wasmModuleId] + "`,
hashWithLength(length) {
const shortChunkHashMap = Object.create(null);
for (const wasmModuleId of Object.keys(chunkModuleMaps.hash)) {
if (typeof chunkModuleMaps.hash[wasmModuleId] === "string")
shortChunkHashMap[wasmModuleId] = chunkModuleMaps.hash[
wasmModuleId
].substr(0, length);
}
return `" + ${JSON.stringify(
shortChunkHashMap
)}[wasmModuleId] + "`;
}
}
}
);
return Template.asString([
source,
"",
"// Fetch + compile chunk loading for webassembly",
"",
`var wasmModules = ${JSON.stringify(
chunkModuleMaps.id
)}[chunkId] || [];`,
"",
"wasmModules.forEach(function(wasmModuleId) {",
Template.indent([
"var installedWasmModuleData = installedWasmModules[wasmModuleId];",
"",
'// a Promise means "currently loading" or "already loaded".',
"if(installedWasmModuleData)",
Template.indent(["promises.push(installedWasmModuleData);"]),
"else {",
Template.indent([
`var importObject = wasmImportObjects[wasmModuleId]();`,
`var req = ${this.generateLoadBinaryCode(wasmModuleSrcPath)};`,
"var promise;",
this.supportsStreaming
? Template.asString([
"if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {",
Template.indent([
"promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {",
Template.indent([
"return WebAssembly.instantiate(items[0], items[1]);"
]),
"});"
]),
"} else if(typeof WebAssembly.instantiateStreaming === 'function') {",
Template.indent([
"promise = WebAssembly.instantiateStreaming(req, importObject);"
])
])
: Template.asString([
"if(importObject instanceof Promise) {",
Template.indent([
"var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });",
"promise = Promise.all([",
Template.indent([
"bytesPromise.then(function(bytes) { return WebAssembly.compile(bytes); }),",
"importObject"
]),
"]).then(function(items) {",
Template.indent([
"return WebAssembly.instantiate(items[0], items[1]);"
]),
"});"
])
]),
"} else {",
Template.indent([
"var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });",
"promise = bytesPromise.then(function(bytes) {",
Template.indent([
"return WebAssembly.instantiate(bytes, importObject);"
]),
"});"
]),
"}",
"promises.push(installedWasmModules[wasmModuleId] = promise.then(function(res) {",
Template.indent([
`return ${
mainTemplate.requireFn
}.w[wasmModuleId] = res.instance || res;`
]),
"}));"
]),
"}"
]),
"});"
]);
}
);
mainTemplate.hooks.requireExtensions.tap(
"WasmMainTemplatePlugin",
(source, chunk) => {
if (!chunk.hasModuleInGraph(m => m.type.startsWith("webassembly")))
return source;
return Template.asString([
source,
"",
"// object with all WebAssembly.instance",
`${mainTemplate.requireFn}.w = {};`
]);
}
);
mainTemplate.hooks.hash.tap("WasmMainTemplatePlugin", hash => {
hash.update("WasmMainTemplatePlugin");
hash.update("1");
hash.update(`${mainTemplate.outputOptions.webassemblyModuleFilename}`);
});
mainTemplate.hooks.hashForChunk.tap(
"WasmMainTemplatePlugin",
(hash, chunk) => {
const chunkModuleMaps = chunk.getChunkModuleMaps(m =>
m.type.startsWith("webassembly")
);
hash.update(JSON.stringify(chunkModuleMaps.id));
const wasmModules = getAllWasmModules(chunk);
for (const module of wasmModules) {
hash.update(module.hash);
}
}
);
}
}
module.exports = WasmMainTemplatePlugin;

View File

@ -1,106 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { RawSource } = require("webpack-sources");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
class WasmModuleTemplatePlugin {
apply(moduleTemplate) {
moduleTemplate.hooks.content.tap(
"WasmModuleTemplatePlugin",
(moduleSource, module, { chunk }) => {
if (module.type && module.type.startsWith("webassembly")) {
if (chunk.canBeInitial())
throw new Error(
"Sync WebAssembly compilation is not yet implemented"
);
const generateExports = () => {
if (
Array.isArray(module.buildMeta.providedExports) &&
Array.isArray(module.usedExports)
) {
// generate mangled exports
return module.buildMeta.providedExports
.map(exp => {
const usedName = module.isUsed(exp);
if (usedName) {
return `${module.exportsArgument}[${JSON.stringify(
usedName
)}] = instance.exports[${JSON.stringify(exp)}];`;
} else {
return `// unused ${JSON.stringify(exp)} export`;
}
})
.join("\n");
} else {
// generate simple export
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";',
"",
"// Instantiate WebAssembly module",
"var instance = new WebAssembly.Instance(__webpack_require__.w[module.i], {" +
generateImports(),
"});",
"",
"// export exports from WebAssembly module",
// TODO rewrite this to getters depending on exports to support circular dependencies
generateExports()
].join("\n")
);
return source;
} else {
return moduleSource;
}
}
);
moduleTemplate.hooks.hash.tap("WasmModuleTemplatePlugin", hash => {
hash.update("WasmModuleTemplatePlugin");
hash.update("1");
});
}
}
module.exports = WasmModuleTemplatePlugin;

View File

@ -0,0 +1,273 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Generator = require("../Generator");
const { RawSource } = require("webpack-sources");
const { edit, add } = require("@webassemblyjs/wasm-edit");
const { decode } = require("@webassemblyjs/wasm-parser");
const t = require("@webassemblyjs/ast");
function compose(...fns) {
return fns.reverse().reduce((prevFn, nextFn) => {
return value => nextFn(prevFn(value));
}, value => value);
}
// Utility functions
const isGlobalImport = moduleImport => moduleImport.descr.type === "GlobalType";
const isFuncImport = moduleImport =>
moduleImport.descr.type === "FuncImportDescr";
const initFuncId = t.identifier("__webpack_init__");
// TODO replace with @callback
/**
* @typedef {(ArrayBuffer) => ArrayBuffer} ArrayBufferTransform
*/
/**
* Removes the start instruction
*
* @param {Object} state - unused state
* @returns {ArrayBufferTransform} transform
*/
const removeStartFunc = state => bin => {
return edit(bin, {
Start(path) {
path.remove();
}
});
};
/**
* Retrieve the start function
*
* @param {Object} ast - Module's AST
* @returns {t.Identifier | undefined} - node if any
*/
function getStartFuncIndex(ast) {
let startAtFuncIndex;
t.traverse(ast, {
Start({ node }) {
startAtFuncIndex = node.index;
}
});
return startAtFuncIndex;
}
/**
* Get imported globals
*
* @param {Object} ast - Module's AST
* @returns {Array<t.ModuleImport>} - nodes
*/
function getImportedGlobals(ast) {
const importedGlobals = [];
t.traverse(ast, {
ModuleImport({ node }) {
if (isGlobalImport(node) === true) {
importedGlobals.push(node);
}
}
});
return importedGlobals;
}
function getCountImportedFunc(ast) {
let count = 0;
t.traverse(ast, {
ModuleImport({ node }) {
if (isFuncImport(node) === true) {
count++;
}
}
});
return count;
}
/**
* Get next type index
*
* @param {Object} ast - Module's AST
* @returns {t.IndexLiteral} - index
*/
function getNextTypeIndex(ast) {
const typeSectionMetadata = t.getSectionMetadata(ast, "type");
if (typeof typeSectionMetadata === "undefined") {
return t.indexLiteral(0);
}
return t.indexLiteral(typeSectionMetadata.vectorOfSize.value);
}
/**
* Get next func index
*
* The Func section metadata provide informations for implemented funcs
* in order to have the correct index we shift the index by number of external
* functions.
*
* @param {Object} ast - Module's AST
* @param {Number} countImportedFunc - number of imported funcs
* @returns {t.IndexLiteral} - index
*/
function getNextFuncIndex(ast, countImportedFunc) {
const funcSectionMetadata = t.getSectionMetadata(ast, "func");
if (typeof funcSectionMetadata === "undefined") {
return t.indexLiteral(0 + countImportedFunc);
}
const vectorOfSize = funcSectionMetadata.vectorOfSize.value;
return t.indexLiteral(vectorOfSize + countImportedFunc);
}
/**
* Rewrite the import globals:
* - removes the ModuleImport instruction
* - injects at the same offset a mutable global of the same time
*
* Since the imported globals are before the other global declarations, our
* indices will be preserved.
*
* Note that globals will become mutable.
*
* @param {Object} state - unused state
* @returns {ArrayBufferTransform} transform
*/
const rewriteImportedGlobals = state => bin => {
const newGlobals = [];
bin = edit(bin, {
ModuleImport(path) {
if (isGlobalImport(path.node) === true) {
const globalType = path.node.descr;
globalType.mutability = "var";
newGlobals.push(
t.global(globalType, [
t.objectInstruction("const", "i32", [t.numberLiteral(0)])
])
);
path.remove();
}
}
});
// Add global declaration instructions
return add(bin, newGlobals);
};
/**
* Add an init function.
*
* The init function fills the globals given input arguments.
*
* @param {Object} state transformation state
* @param {t.IndexLiteral} state.startAtFuncIndex index of the start function
* @param {t.ModuleImport[]} state.importedGlobals list of imported globals
* @param {*} state.funcSectionMetadata ??
* @param {t.IndexLiteral} state.nextFuncIndex index of the next function
* @param {t.IndexLiteral} state.nextTypeIndex index of the next type
* @returns {ArrayBufferTransform} transform
*/
const addInitFunction = ({
startAtFuncIndex,
importedGlobals,
funcSectionMetadata,
nextFuncIndex,
nextTypeIndex
}) => bin => {
const funcParams = importedGlobals.map(importedGlobal => {
// used for debugging
const id = t.identifier(`${importedGlobal.module}.${importedGlobal.name}`);
return t.funcParam(importedGlobal.descr.valtype, id);
});
const funcBody = importedGlobals.reduce((acc, importedGlobal, index) => {
const args = [t.indexLiteral(index)];
const body = [
t.instruction("get_local", args),
t.instruction("set_global", args)
];
return [...acc, ...body];
}, []);
if (typeof startAtFuncIndex !== "undefined") {
funcBody.push(t.callInstruction(startAtFuncIndex));
}
const funcResults = [];
// Code section
const func = t.func(initFuncId, funcParams, funcResults, funcBody);
// Type section
const functype = t.typeInstructionFunc(
func.signature.params,
func.signature.result
);
// Func section
const funcindex = t.indexInFuncSection(nextTypeIndex);
// Export section
const moduleExport = t.moduleExport(initFuncId.value, "Func", nextFuncIndex);
return add(bin, [func, moduleExport, funcindex, functype]);
};
class WebAssemblyGenerator extends Generator {
generate(module) {
const bin = module.originalSource().source();
// FIXME(sven): this module is parsed twice, we could preserve the AST
// from wasm/WebAssemblyParser.js
const ast = decode(bin, {
ignoreDataSection: true,
ignoreCodeSection: true
});
const importedGlobals = getImportedGlobals(ast);
const funcSectionMetadata = t.getSectionMetadata(ast, "func");
const countImportedFunc = getCountImportedFunc(ast);
const startAtFuncIndex = getStartFuncIndex(ast);
const nextFuncIndex = getNextFuncIndex(ast, countImportedFunc);
const nextTypeIndex = getNextTypeIndex(ast);
const transform = compose(
removeStartFunc({}),
rewriteImportedGlobals({}),
addInitFunction({
importedGlobals,
funcSectionMetadata,
startAtFuncIndex,
nextFuncIndex,
nextTypeIndex
})
);
const newBin = transform(bin);
return new RawSource(newBin);
}
}
module.exports = WebAssemblyGenerator;

View File

@ -0,0 +1,107 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Generator = require("../Generator");
const Template = require("../Template");
const { RawSource } = require("webpack-sources");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
function generateInitParams(module) {
const list = [];
for (const dep of module.dependencies) {
if (dep instanceof WebAssemblyImportDependency) {
if (dep.description.type === "GlobalType") {
const exportName = dep.name;
const usedName = dep.module && dep.module.isUsed(exportName);
if (dep.module === null) {
// Dependency was not found, an error will be thrown later
continue;
}
if (usedName !== false) {
list.push(
`__webpack_require__(${JSON.stringify(
dep.module.id
)})[${JSON.stringify(usedName)}]`
);
}
}
}
}
return list;
}
class WebAssemblyJavascriptGenerator extends Generator {
generate(module, dependencyTemplates, runtimeTemplate) {
const generateExports = () => {
if (
Array.isArray(module.buildMeta.providedExports) &&
Array.isArray(module.usedExports)
) {
// generate mangled exports
return Template.asString(
module.buildMeta.providedExports.map(exp => {
const usedName = module.isUsed(exp);
if (usedName) {
return `${module.exportsArgument}[${JSON.stringify(
usedName
)}] = instance.exports[${JSON.stringify(exp)}];`;
} else {
return `// unused ${JSON.stringify(exp)} export`;
}
})
);
} else {
// generate simple export
return `${module.moduleArgument}.exports = instance.exports;`;
}
};
const generateImports = () => {
const modules = new Map();
for (const dep of module.dependencies) {
if (dep.module) modules.set(dep.module, dep.userRequest);
}
return Template.asString(
Array.from(modules, ([m, r]) => {
return `${runtimeTemplate.moduleRaw({
module: m,
request: r
})};`;
})
);
};
// FIXME(sven): assert that the exports exists in the modules
// otherwise it will default to i32 0
const initParams = generateInitParams(module).join(",");
// create source
const source = new RawSource(
[
'"use strict";',
"// Instantiate WebAssembly module",
"var instance = __webpack_require__.w[module.i];",
// this must be before import for circular dependencies
"// export exports from WebAssembly module",
generateExports(),
"// exec imports from WebAssembly module (for esm order)",
generateImports(),
"// exec wasm module",
`instance.exports.__webpack_init__(${initParams})`
].join("\n")
);
return source;
}
}
module.exports = WebAssemblyJavascriptGenerator;

View File

@ -4,9 +4,11 @@
*/
"use strict";
const Generator = require("../Generator");
const WebAssemblyParser = require("./WebAssemblyParser");
const WebAssemblyGenerator = require("./WebAssemblyGenerator");
const WebAssemblyImportDependency = require("./dependencies/WebAssemblyImportDependency");
const WebAssemblyJavascriptGenerator = require("./WebAssemblyJavascriptGenerator");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
class WebAssemblyModulesPlugin {
apply(compiler) {
@ -27,7 +29,10 @@ class WebAssemblyModulesPlugin {
normalModuleFactory.hooks.createGenerator
.for("webassembly/experimental")
.tap("WebAssemblyModulesPlugin", () => {
return new WebAssemblyGenerator();
return Generator.byType({
javascript: new WebAssemblyJavascriptGenerator(),
webassembly: new WebAssemblyGenerator()
});
});
compilation.chunkTemplate.hooks.renderManifest.tap(

View File

@ -0,0 +1,80 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const t = require("@webassemblyjs/ast");
const { decode } = require("@webassemblyjs/wasm-parser");
const { Tapable } = require("tapable");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
/**
* @param {t.ModuleImport} moduleImport the import
* @returns {boolean} true, if a memory was imported
*/
const isMemoryImport = moduleImport => moduleImport.descr.type === "Memory";
/**
* @param {t.ModuleImport} moduleImport the import
* @returns {boolean} true, if a table was imported
*/
const isTableImport = moduleImport => moduleImport.descr.type === "Table";
const decoderOpts = {
ignoreCodeSection: true,
ignoreDataSection: true
};
class WebAssemblyParser extends Tapable {
constructor(options) {
super();
this.hooks = {};
this.options = options;
}
parse(binary, state) {
// flag it as ESM
state.module.buildMeta.exportsType = "namespace";
// parse it
const ast = decode(binary, decoderOpts);
// extract imports and exports
const exports = (state.module.buildMeta.providedExports = []);
t.traverse(ast, {
ModuleExport({ node }) {
const moduleExport = /** @type {t.ModuleExport} */ (node);
exports.push(moduleExport.name);
},
ModuleImport({ node }) {
const moduleImport = /** @type {t.ModuleImport} */ (node);
let onlyDirectImport = false;
if (isMemoryImport(moduleImport) === true) {
onlyDirectImport = true;
}
if (isTableImport(moduleImport) === true) {
onlyDirectImport = true;
}
const dep = new WebAssemblyImportDependency(
moduleImport.module,
moduleImport.name,
moduleImport.descr,
onlyDirectImport
);
state.module.addDependency(dep);
}
});
return state;
}
}
module.exports = WebAssemblyParser;

View File

@ -1,119 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Template = require("../Template");
class FetchCompileWasmMainTemplatePlugin {
apply(mainTemplate) {
mainTemplate.hooks.localVars.tap(
"FetchCompileWasmMainTemplatePlugin",
(source, chunk) => {
if (!chunk.hasModuleInGraph(m => m.type.startsWith("webassembly")))
return source;
return Template.asString([
source,
"",
"// object to store loaded and loading wasm modules",
"var installedWasmModules = {};"
]);
}
);
mainTemplate.hooks.requireEnsure.tap(
"FetchCompileWasmMainTemplatePlugin",
(source, chunk, hash) => {
const webassemblyModuleFilename =
mainTemplate.outputOptions.webassemblyModuleFilename;
const chunkModuleMaps = chunk.getChunkModuleMaps(m =>
m.type.startsWith("webassembly")
);
if (Object.keys(chunkModuleMaps.id).length === 0) return source;
const wasmModuleSrcPath = mainTemplate.getAssetPath(
JSON.stringify(webassemblyModuleFilename),
{
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
hashWithLength: length =>
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
module: {
id: '" + wasmModuleId + "',
hash: `" + ${JSON.stringify(
chunkModuleMaps.hash
)}[wasmModuleId] + "`,
hashWithLength(length) {
const shortChunkHashMap = Object.create(null);
for (const wasmModuleId of Object.keys(chunkModuleMaps.hash)) {
if (typeof chunkModuleMaps.hash[wasmModuleId] === "string")
shortChunkHashMap[wasmModuleId] = chunkModuleMaps.hash[
wasmModuleId
].substr(0, length);
}
return `" + ${JSON.stringify(
shortChunkHashMap
)}[wasmModuleId] + "`;
}
}
}
);
return Template.asString([
source,
"",
"// Fetch + compile chunk loading for webassembly",
"",
`var wasmModules = ${JSON.stringify(
chunkModuleMaps.id
)}[chunkId] || [];`,
"",
"wasmModules.forEach(function(wasmModuleId) {",
Template.indent([
"var installedWasmModuleData = installedWasmModules[wasmModuleId];",
"",
'// a Promise means "currently loading" or "already loaded".',
"promises.push(installedWasmModuleData ||",
Template.indent([
`(installedWasmModules[wasmModuleId] = fetch(${
mainTemplate.requireFn
}.p + ${wasmModuleSrcPath}).then(function(response) {`,
Template.indent([
"if(WebAssembly.compileStreaming) {",
Template.indent([
"return WebAssembly.compileStreaming(response);"
]),
"} else {",
Template.indent([
"return response.arrayBuffer().then(function(bytes) { return WebAssembly.compile(bytes); });"
]),
"}"
]),
`}).then(function(module) { ${
mainTemplate.requireFn
}.w[wasmModuleId] = module; }))`
]),
");"
]),
"});"
]);
}
);
mainTemplate.hooks.requireExtensions.tap(
"FetchCompileWasmMainTemplatePlugin",
(source, chunk) => {
if (!chunk.hasModuleInGraph(m => m.type.startsWith("webassembly")))
return source;
return Template.asString([
source,
"",
"// object with all compiled WebAssembly.Modules",
`${mainTemplate.requireFn}.w = {};`
]);
}
);
mainTemplate.hooks.hash.tap("FetchCompileWasmMainTemplatePlugin", hash => {
hash.update("FetchCompileWasmMainTemplatePlugin");
hash.update("1");
hash.update(`${mainTemplate.outputOptions.webassemblyModuleFilename}`);
});
}
}
module.exports = FetchCompileWasmMainTemplatePlugin;

View File

@ -4,20 +4,19 @@
*/
"use strict";
const FetchCompileWasmMainTemplatePlugin = require("./FetchCompileWasmMainTemplatePlugin");
const WasmModuleTemplatePlugin = require("../wasm/WasmModuleTemplatePlugin");
const WasmMainTemplatePlugin = require("../wasm/WasmMainTemplatePlugin");
class FetchCompileWasmTemplatePlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap(
"FetchCompileWasmTemplatePlugin",
compilation => {
new FetchCompileWasmMainTemplatePlugin().apply(
compilation.mainTemplate
);
new WasmModuleTemplatePlugin().apply(
compilation.moduleTemplates.javascript
);
const mainTemplate = compilation.mainTemplate;
const generateLoadBinaryCode = path =>
`fetch(${mainTemplate.requireFn}.p + ${path})`;
const plugin = new WasmMainTemplatePlugin(generateLoadBinaryCode, true);
plugin.apply(mainTemplate);
}
);
}

View File

@ -5,6 +5,9 @@
"description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.3.0",
"@webassemblyjs/wasm-edit": "1.3.0",
"@webassemblyjs/wasm-parser": "1.3.0",
"acorn": "^5.0.0",
"acorn-dynamic-import": "^3.0.0",
"ajv": "^6.1.0",

View File

@ -55,6 +55,15 @@ describe("WatchTestCases", () => {
tests: fs
.readdirSync(path.join(casesPath, cat))
.filter(folder => folder.indexOf("_") < 0)
.filter(testName => {
const testDirectory = path.join(casesPath, cat, testName);
const filterPath = path.join(testDirectory, "test.filter.js");
if (fs.existsSync(filterPath) && !require(filterPath)()) {
describe.skip(testName, () => it("filtered"));
return false;
}
return true;
})
.sort()
};
});

View File

@ -1,21 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StatsTestCases should print correct stats for aggressive-splitting-entry 1`] = `
"Hash: b907386938ff12cf9dbbb907386938ff12cf9dbb
"Hash: 4fe9463156cb2a99f4a94fe9463156cb2a99f4a9
Child fitting:
Hash: b907386938ff12cf9dbb
Hash: 4fe9463156cb2a99f4a9
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
9ac13fb7087e9ff1b93e.js 1.05 KiB 0 [emitted]
077726e3805b482fd93e.js 10.2 KiB 1 [emitted]
f2e891598128a57b072c.js 10.2 KiB 1 [emitted]
d1ba53816ff760e185b0.js 1.94 KiB 2 [emitted]
7b5b0a943e9362bc88c6.js 1.94 KiB 3 [emitted]
Entrypoint main = d1ba53816ff760e185b0.js 7b5b0a943e9362bc88c6.js 077726e3805b482fd93e.js
Entrypoint main = d1ba53816ff760e185b0.js 7b5b0a943e9362bc88c6.js f2e891598128a57b072c.js
chunk {0} 9ac13fb7087e9ff1b93e.js 916 bytes <{1}> <{2}> <{3}>
> ./g [4] ./index.js 7:0-13
[7] ./g.js 916 bytes {0} [built]
chunk {1} 077726e3805b482fd93e.js 1.87 KiB ={2}= ={3}= >{0}< [entry] [rendered]
chunk {1} f2e891598128a57b072c.js 1.87 KiB ={2}= ={3}= >{0}< [entry] [rendered]
> ./index main
[3] ./e.js 899 bytes {1} [built]
[4] ./index.js 111 bytes {1} [built]
@ -29,19 +29,19 @@ Child fitting:
[1] ./c.js 899 bytes {3} [built]
[2] ./d.js 899 bytes {3} [built]
Child content-change:
Hash: b907386938ff12cf9dbb
Hash: 4fe9463156cb2a99f4a9
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
9ac13fb7087e9ff1b93e.js 1.05 KiB 0 [emitted]
077726e3805b482fd93e.js 10.2 KiB 1 [emitted]
f2e891598128a57b072c.js 10.2 KiB 1 [emitted]
d1ba53816ff760e185b0.js 1.94 KiB 2 [emitted]
7b5b0a943e9362bc88c6.js 1.94 KiB 3 [emitted]
Entrypoint main = d1ba53816ff760e185b0.js 7b5b0a943e9362bc88c6.js 077726e3805b482fd93e.js
Entrypoint main = d1ba53816ff760e185b0.js 7b5b0a943e9362bc88c6.js f2e891598128a57b072c.js
chunk {0} 9ac13fb7087e9ff1b93e.js 916 bytes <{1}> <{2}> <{3}>
> ./g [4] ./index.js 7:0-13
[7] ./g.js 916 bytes {0} [built]
chunk {1} 077726e3805b482fd93e.js 1.87 KiB ={2}= ={3}= >{0}< [entry] [rendered]
chunk {1} f2e891598128a57b072c.js 1.87 KiB ={2}= ={3}= >{0}< [entry] [rendered]
> ./index main
[3] ./e.js 899 bytes {1} [built]
[4] ./index.js 111 bytes {1} [built]
@ -57,7 +57,7 @@ Child content-change:
`;
exports[`StatsTestCases should print correct stats for aggressive-splitting-on-demand 1`] = `
"Hash: d1ec33892177d3771968
"Hash: 84ad1d7e4c9cdd4b13e4
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -71,9 +71,9 @@ d6418937dfae4b3ee922.js 1 KiB 1 [emitted]
685acdc95ff4af957f47.js 1 KiB 7 [emitted]
606f48c13070850338b1.js 1.94 KiB 8 [emitted]
c5a8eae840969538f450.js 1.94 KiB 9 [emitted]
3bf16d513625c7c39e6f.js 8.68 KiB 10 [emitted] main
c69b2f79fdf6e98907c4.js 8.68 KiB 10 [emitted] main
fcdf398c8972e4dcf788.js 1.94 KiB 11 [emitted]
Entrypoint main = 3bf16d513625c7c39e6f.js
Entrypoint main = c69b2f79fdf6e98907c4.js
chunk {0} fd868baa40dab4fc30fd.js 1.76 KiB <{10}> ={1}= ={2}= ={3}= ={7}= ={9}= [recorded] aggressive splitted
> ./b ./d ./e ./f ./g [11] ./index.js 5:0-44
> ./b ./d ./e ./f ./g ./h ./i ./j ./k [11] ./index.js 6:0-72
@ -115,7 +115,7 @@ chunk {9} c5a8eae840969538f450.js 1.76 KiB <{10}> ={0}= ={2}= ={3}= ={7}= [re
> ./b ./d ./e ./f ./g ./h ./i ./j ./k [11] ./index.js 6:0-72
[7] ./i.js 899 bytes {9} {11} [built]
[8] ./j.js 901 bytes {6} {9} [built]
chunk {10} 3bf16d513625c7c39e6f.js (main) 248 bytes >{0}< >{1}< >{11}< >{2}< >{3}< >{4}< >{5}< >{6}< >{7}< >{8}< >{9}< [entry] [rendered]
chunk {10} c69b2f79fdf6e98907c4.js (main) 248 bytes >{0}< >{1}< >{11}< >{2}< >{3}< >{4}< >{5}< >{6}< >{7}< >{8}< >{9}< [entry] [rendered]
> ./index main
[11] ./index.js 248 bytes {10} [built]
chunk {11} fcdf398c8972e4dcf788.js 1.76 KiB <{10}> ={2}= ={6}= [rendered] [recorded] aggressive splitted
@ -467,7 +467,7 @@ Child all:
`;
exports[`StatsTestCases should print correct stats for chunk-module-id-range 1`] = `
"Hash: 0bb3f504cf6cc3cbace1
"Hash: bc5067cf597a5fece180
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -492,7 +492,7 @@ chunk {1} main1.js (main1) 136 bytes [entry] [rendered]
`;
exports[`StatsTestCases should print correct stats for chunks 1`] = `
"Hash: 41fab27e5669c037a625
"Hash: 329edf3a78275c679fe4
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -530,7 +530,7 @@ chunk {3} 3.bundle.js 44 bytes <{1}> [rendered]
`;
exports[`StatsTestCases should print correct stats for chunks-development 1`] = `
"Hash: 7724565418b8b6c8467a
"Hash: d9a9db28b39a3075bdb3
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -581,7 +581,7 @@ chunk {3} 3.bundle.js (c) 98 bytes <{0}> <{1}> >{0}< >{1}< [rendered]
`;
exports[`StatsTestCases should print correct stats for color-disabled 1`] = `
"Hash: a6779032127bc5f302b0
"Hash: 259c9ad9aa282b7b9017
Time: Xms
Built at: Thu Jan 01 1970 <CLR=BOLD>00:00:00</CLR> GMT
Asset Size Chunks Chunk Names
@ -591,7 +591,7 @@ Entrypoint main = main.js
`;
exports[`StatsTestCases should print correct stats for color-enabled 1`] = `
"Hash: <CLR=BOLD>a6779032127bc5f302b0</CLR>
"Hash: <CLR=BOLD>259c9ad9aa282b7b9017</CLR>
Time: <CLR=BOLD>X</CLR>ms
Built at: Thu Jan 01 1970 <CLR=BOLD>00:00:00</CLR> GMT
<CLR=BOLD>Asset</CLR> <CLR=BOLD>Size</CLR> <CLR=BOLD>Chunks</CLR> <CLR=39,BOLD><CLR=22> <CLR=39,BOLD><CLR=22><CLR=BOLD>Chunk Names</CLR>
@ -601,7 +601,7 @@ Entrypoint <CLR=BOLD>main</CLR> = <CLR=32,BOLD>main.js</CLR>
`;
exports[`StatsTestCases should print correct stats for color-enabled-custom 1`] = `
"Hash: <CLR=BOLD>a6779032127bc5f302b0</CLR>
"Hash: <CLR=BOLD>259c9ad9aa282b7b9017</CLR>
Time: <CLR=BOLD>X</CLR>ms
Built at: Thu Jan 01 1970 <CLR=BOLD>00:00:00</CLR> GMT
<CLR=BOLD>Asset</CLR> <CLR=BOLD>Size</CLR> <CLR=BOLD>Chunks</CLR> <CLR=39,BOLD><CLR=22> <CLR=39,BOLD><CLR=22><CLR=BOLD>Chunk Names</CLR>
@ -611,7 +611,7 @@ Entrypoint <CLR=BOLD>main</CLR> = <CLR=32>main.js</CLR>
`;
exports[`StatsTestCases should print correct stats for commons-chunk-min-size-0 1`] = `
"Hash: fe1218333b65ce9f8634
"Hash: ba7c69f3acc19ed72f3f
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -628,7 +628,7 @@ Entrypoint entry-1 = vendor-1~entry-1.js entry-1.js
`;
exports[`StatsTestCases should print correct stats for commons-chunk-min-size-Infinity 1`] = `
"Hash: 795be68665d680b959bb
"Hash: f8b8bebc8cf37cf02f7f
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -645,9 +645,9 @@ Entrypoint entry-1 = vendor-1.js entry-1.js
`;
exports[`StatsTestCases should print correct stats for commons-plugin-issue-4980 1`] = `
"Hash: 3da37f8a7e9d647c86531c172aabb881b93ba6be
"Hash: b7026c887b1a4d42c4c08b5ecbff0d004a138881
Child
Hash: 3da37f8a7e9d647c8653
Hash: b7026c887b1a4d42c4c0
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -660,7 +660,7 @@ Child
| ./submodule-a.js 59 bytes [built]
| ./submodule-b.js 59 bytes [built]
Child
Hash: 1c172aabb881b93ba6be
Hash: 8b5ecbff0d004a138881
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -693,9 +693,9 @@ exports[`StatsTestCases should print correct stats for concat-and-sideeffects 1`
`;
exports[`StatsTestCases should print correct stats for define-plugin 1`] = `
"Hash: e7d8a913568c3242d80b39c3fe9ff20894943d05
"Hash: efa53b4a8c763381d4296ac4ef4ab386e0e18a8c
Child
Hash: e7d8a913568c3242d80b
Hash: efa53b4a8c763381d429
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -703,7 +703,7 @@ Child
Entrypoint main = main.js
[0] ./index.js 24 bytes {0} [built]
Child
Hash: 39c3fe9ff20894943d05
Hash: 6ac4ef4ab386e0e18a8c
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -713,7 +713,7 @@ Child
`;
exports[`StatsTestCases should print correct stats for exclude-with-loader 1`] = `
"Hash: 0bfe3f933dc07ac74c68
"Hash: 82110ff5e7d166cc4117
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -726,7 +726,7 @@ Entrypoint main = bundle.js
`;
exports[`StatsTestCases should print correct stats for external 1`] = `
"Hash: c978d13c314f28182daa
"Hash: 447b77fa7bc9bbdfcf31
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -737,9 +737,9 @@ Entrypoint main = main.js
`;
exports[`StatsTestCases should print correct stats for filter-warnings 1`] = `
"Hash: 894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d894b7278b69dd6b1969d
"Hash: a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25a128fafbc2b7d659de25
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -759,49 +759,49 @@ Child
Dropping unused function someRemoteUnUsedFunction4 [./a.js:6,0]
Dropping unused function someRemoteUnUsedFunction5 [./a.js:7,0]
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
bundle.js 2.19 KiB 0 [emitted] main
Entrypoint main = bundle.js
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
bundle.js 2.19 KiB 0 [emitted] main
Entrypoint main = bundle.js
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
bundle.js 2.19 KiB 0 [emitted] main
Entrypoint main = bundle.js
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
bundle.js 2.19 KiB 0 [emitted] main
Entrypoint main = bundle.js
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
bundle.js 2.19 KiB 0 [emitted] main
Entrypoint main = bundle.js
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
bundle.js 2.19 KiB 0 [emitted] main
Entrypoint main = bundle.js
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -821,7 +821,7 @@ Child
Dropping unused function someRemoteUnUsedFunction4 [./a.js:6,0]
Dropping unused function someRemoteUnUsedFunction5 [./a.js:7,0]
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -841,7 +841,7 @@ Child
Dropping unused function someRemoteUnUsedFunction4 [./a.js:6,0]
Dropping unused function someRemoteUnUsedFunction5 [./a.js:7,0]
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -861,7 +861,7 @@ Child
Dropping unused function someRemoteUnUsedFunction4 [./a.js:6,0]
Dropping unused function someRemoteUnUsedFunction5 [./a.js:7,0]
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -881,7 +881,7 @@ Child
Dropping unused function someRemoteUnUsedFunction4 [./a.js:6,0]
Dropping unused function someRemoteUnUsedFunction5 [./a.js:7,0]
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -901,7 +901,7 @@ Child
Dropping unused function someRemoteUnUsedFunction4 [./a.js:6,0]
Dropping unused function someRemoteUnUsedFunction5 [./a.js:7,0]
Child
Hash: 894b7278b69dd6b1969d
Hash: a128fafbc2b7d659de25
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -978,7 +978,7 @@ chunk {5} b.js (b) 179 bytes <{2}> >{1}< [rendered]
`;
exports[`StatsTestCases should print correct stats for import-context-filter 1`] = `
"Hash: e08ae3f7bf8b895ac342
"Hash: f249efcc0232c180bf68
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -995,7 +995,7 @@ Entrypoint entry = entry.js
`;
exports[`StatsTestCases should print correct stats for import-weak 1`] = `
"Hash: 59a0e9590a7c1754c76d
"Hash: 9cccc27b7625bd171c12
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1008,9 +1008,9 @@ Entrypoint entry = entry.js
`;
exports[`StatsTestCases should print correct stats for limit-chunk-count-plugin 1`] = `
"Hash: fbf4374d5e6774f1f5763193fa6cb748ec53112f17662c5c606c0e127c765794818a8074e5c164c7
"Hash: 3c127dca42ce1c13b8eae6c0ceac1aa3be512946a5969fc94d792cce5364503bf42779f704747e2d
Child 1 chunks:
Hash: fbf4374d5e6774f1f576
Hash: 3c127dca42ce1c13b8ea
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1024,7 +1024,7 @@ Child 1 chunks:
[4] ./d.js 22 bytes {0} [built]
[5] ./e.js 22 bytes {0} [built]
Child 2 chunks:
Hash: 3193fa6cb748ec53112f
Hash: e6c0ceac1aa3be512946
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1040,7 +1040,7 @@ Child 2 chunks:
chunk {1} bundle.js (main) 73 bytes >{0}< [entry] [rendered]
[5] ./index.js 73 bytes {1} [built]
Child 3 chunks:
Hash: 17662c5c606c0e127c76
Hash: a5969fc94d792cce5364
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1058,7 +1058,7 @@ Child 3 chunks:
chunk {2} bundle.js (main) 73 bytes >{0}< >{1}< [entry] [rendered]
[5] ./index.js 73 bytes {2} [built]
Child 4 chunks:
Hash: 5794818a8074e5c164c7
Hash: 503bf42779f704747e2d
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1080,7 +1080,7 @@ Child 4 chunks:
`;
exports[`StatsTestCases should print correct stats for max-modules 1`] = `
"Hash: 75aa9fbfda2cb79419d8
"Hash: 528955f6d280625ce14d
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1110,7 +1110,7 @@ Entrypoint main = main.js
`;
exports[`StatsTestCases should print correct stats for max-modules-default 1`] = `
"Hash: 75aa9fbfda2cb79419d8
"Hash: 528955f6d280625ce14d
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1135,7 +1135,7 @@ Entrypoint main = main.js
`;
exports[`StatsTestCases should print correct stats for module-assets 1`] = `
"Hash: 50b073bf8c481825a488
"Hash: f544bcf110bd1cf43d65
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Entrypoint main = main.js
@ -1317,7 +1317,7 @@ Child
`;
exports[`StatsTestCases should print correct stats for named-chunks-plugin 1`] = `
"Hash: bda0a8a2c2ad3a4d41bd
"Hash: 4d266c3680a506e31e7e
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1331,7 +1331,7 @@ Entrypoint entry = vendor.js entry.js
`;
exports[`StatsTestCases should print correct stats for named-chunks-plugin-async 1`] = `
"Hash: b07ae41580240259728a
"Hash: b54cb3a3bc63561b46b3
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1345,7 +1345,7 @@ Entrypoint entry = entry.js
`;
exports[`StatsTestCases should print correct stats for no-emit-on-errors-plugin-with-child-error 1`] = `
"Hash: 30e651c30e081df7d6fb
"Hash: 6c219bd2ffa7d0ba8efb
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1367,7 +1367,7 @@ Child child:
`;
exports[`StatsTestCases should print correct stats for optimize-chunks 1`] = `
"Hash: 72023c7499b4b25526da
"Hash: 5d3814f1fdaba61ed71c
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1438,9 +1438,9 @@ You may need an appropriate loader to handle this file type.
`;
exports[`StatsTestCases should print correct stats for performance-different-mode-and-target 1`] = `
"Hash: 1600ea0c15704981d2afb76a49f4a3d86abe6cece7a6e8bbef9e93fb375f94f7ccc27c401fad35731592704355cc413e2afcf8bdd2c0c7cffce662a97f3b443bb4363f92335d
"Hash: 36ef9589e3f3c206907d131fd32b3ce1bbf1fb07e0ec393717b117b253ba7bd80de90c69fbe1699ff5afc47fa7eaf1e7303afe2ff2a34c467b43c85c513ab90423c98ca17f51
Child
Hash: 1600ea0c15704981d2af
Hash: 36ef9589e3f3c206907d
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1463,7 +1463,7 @@ Child
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Child
Hash: b76a49f4a3d86abe6cec
Hash: 131fd32b3ce1bbf1fb07
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1486,7 +1486,7 @@ Child
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Child
Hash: e7a6e8bbef9e93fb375f
Hash: e0ec393717b117b253ba
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1494,7 +1494,7 @@ Child
Entrypoint main = no-warning.pro-node.js
[0] ./index.js 293 KiB {0} [built]
Child
Hash: 94f7ccc27c401fad3573
Hash: 7bd80de90c69fbe1699f
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1502,7 +1502,7 @@ Child
Entrypoint main = no-warning.dev-web.js
[./index.js] 293 KiB {main} [built]
Child
Hash: 1592704355cc413e2afc
Hash: f5afc47fa7eaf1e7303a
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1510,7 +1510,7 @@ Child
Entrypoint main = no-warning.dev-node.js
[./index.js] 293 KiB {main} [built]
Child
Hash: f8bdd2c0c7cffce662a9
Hash: fe2ff2a34c467b43c85c
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1518,7 +1518,7 @@ Child
Entrypoint main [big] = no-warning.dev-web-with-limit-set.js
[./index.js] 293 KiB {main} [built]
Child
Hash: 7f3b443bb4363f92335d
Hash: 513ab90423c98ca17f51
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1719,7 +1719,7 @@ chunk {6} inner2.js (inner2) 0 bytes <{0}> [rendered]"
`;
exports[`StatsTestCases should print correct stats for preset-detailed 1`] = `
"Hash: 633de649e1fd60300acb
"Hash: 8abc26856f4ca9b61679
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1778,7 +1778,7 @@ exports[`StatsTestCases should print correct stats for preset-none-array 1`] = `
exports[`StatsTestCases should print correct stats for preset-none-error 1`] = `""`;
exports[`StatsTestCases should print correct stats for preset-normal 1`] = `
"Hash: 633de649e1fd60300acb
"Hash: 8abc26856f4ca9b61679
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1856,7 +1856,7 @@ Entrypoints:
`;
exports[`StatsTestCases should print correct stats for preset-verbose 1`] = `
"Hash: 633de649e1fd60300acb
"Hash: 8abc26856f4ca9b61679
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1900,7 +1900,7 @@ chunk {3} 3.js 44 bytes <{1}> [rendered]
`;
exports[`StatsTestCases should print correct stats for resolve-plugin-context 1`] = `
"Hash: b03156e9d530e0fdde16
"Hash: 11a1659e0148f10e3a15
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1914,7 +1914,7 @@ Entrypoint main = bundle.js
`;
exports[`StatsTestCases should print correct stats for reverse-sort-modules 1`] = `
"Hash: 75aa9fbfda2cb79419d8
"Hash: 528955f6d280625ce14d
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -1979,7 +1979,7 @@ Entrypoint e2 = runtime.js e2.js"
`;
exports[`StatsTestCases should print correct stats for scope-hoisting-bailouts 1`] = `
"Hash: eca97dadc365a5ea9495
"Hash: 6c000e1efebf892a7639
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Entrypoint index = index.js
@ -2011,9 +2011,9 @@ Entrypoint entry = entry.js
`;
exports[`StatsTestCases should print correct stats for scope-hoisting-multi 1`] = `
"Hash: 649bc82f0ddfa78bf8265487d50fbccae514909d
"Hash: 3354b6776c2bb6b558f4c9101316bd6316bf5251
Child
Hash: 649bc82f0ddfa78bf826
Hash: 3354b6776c2bb6b558f4
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Entrypoint first = vendor.js first.js
@ -2030,7 +2030,7 @@ Child
[9] ./module_first.js 31 bytes {4} [built]
[10] ./second.js 177 bytes {5} [built]
Child
Hash: 5487d50fbccae514909d
Hash: c9101316bd6316bf5251
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Entrypoint first = vendor.js first.js
@ -2058,7 +2058,7 @@ Child
`;
exports[`StatsTestCases should print correct stats for simple 1`] = `
"Hash: 85e288d6fa103903dde9
"Hash: 1843cc9aed8366594774
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -2068,7 +2068,7 @@ Entrypoint main = bundle.js
`;
exports[`StatsTestCases should print correct stats for simple-more-info 1`] = `
"Hash: f252a9e1a2892c292e8e
"Hash: c4097b5edb272ec4b73c
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -2574,7 +2574,7 @@ chunk {4} default/main.js (main) 147 bytes >{0}< >{1}< >{2}< >{3}< [entry] [r
`;
exports[`StatsTestCases should print correct stats for tree-shaking 1`] = `
"Hash: 268985187bb6f35a0709
"Hash: 9470b99b4586c4006572
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names
@ -2611,7 +2611,7 @@ Entrypoint main = bundle.js
`;
exports[`StatsTestCases should print correct stats for warnings-uglifyjs 1`] = `
"Hash: c9585261f508c0a85e1b
"Hash: c0402129c5c14a0d4a19
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names

View File

@ -0,0 +1,15 @@
it("should support wasm compiled from c++", function() {
return import("./memory3.wasm").then(function(wasm) {
expect(wasm._Z3getv()).toBe(0);
wasm._Z3seti(42);
expect(wasm._Z3getv()).toBe(42);
});
});
it("should raw memory export without data", function() {
return import("./memory2.wasm").then(function(wasm) {
expect(wasm.memory).toBeInstanceOf(WebAssembly.Memory);
expect(wasm.memory.buffer).toBeInstanceOf(ArrayBuffer);
expect(wasm.memory.buffer.byteLength).toBe(1 << 16);
});
});

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
var supportsWebAssembly = require("../../../helpers/supportsWebAssembly");
module.exports = function(config) {
return supportsWebAssembly();
};

View File

@ -0,0 +1,8 @@
it("should allow direct memory connection between wasm modules", function() {
return import("./run").then(function(module) {
expect(module.x1).toBe(42);
expect(module.x2).toBe(42);
expect(module.y1).toBe(11);
expect(module.y2).toBe(11);
});
});

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,9 @@
import * as a1 from "./mem-access.wasm?1";
import * as a2 from "./mem-access.wasm?2";
a1.set(42);
export const x1 = a1.get();
export const x2 = a2.get();
a2.set(11);
export const y1 = a1.get();
export const y2 = a2.get();

View File

@ -0,0 +1,5 @@
var supportsWebAssembly = require("../../../helpers/supportsWebAssembly");
module.exports = function(config) {
return supportsWebAssembly();
};

View File

@ -0,0 +1,31 @@
// the message is inconsistency between some nodejs versions
const UNKNOWN_FUNCTION_TABLE = /invalid index into function table|invalid function/;
it("should support tables", function() {
return import("./wasm-table.wasm").then(function(wasm) {
expect(wasm.callByIndex(0)).toEqual(42);
expect(wasm.callByIndex(1)).toEqual(13);
expect(() => wasm.callByIndex(2)).toThrow(UNKNOWN_FUNCTION_TABLE);
});
});
it("should support exported tables", function() {
return import("./wasm-table-export.wasm").then(function(wasm) {
expect(wasm.table).toBeInstanceOf(WebAssembly.Table);
expect(wasm.table.length).toBe(2);
const e0 = wasm.table.get(0);
const e1 = wasm.table.get(1);
expect(e0).toBeInstanceOf(Function);
expect(e1).toBeInstanceOf(Function);
expect(e0()).toEqual(42);
expect(e1()).toEqual(13);
});
});
it("should support imported tables", function() {
return import("./wasm-table-imported.wasm").then(function(wasm) {
expect(wasm.callByIndex(0)).toEqual(42);
expect(wasm.callByIndex(1)).toEqual(13);
expect(() => wasm.callByIndex(2)).toThrow(UNKNOWN_FUNCTION_TABLE);
});
});

View File

@ -0,0 +1,5 @@
var supportsWebAssembly = require("../../../helpers/supportsWebAssembly");
module.exports = function(config) {
return supportsWebAssembly();
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,18 @@
it("should allow to run a WebAssembly module with imports", function() {
return import("./wasm.wasm").then(function(wasm) {
const result = wasm.get();
switch(WATCH_STEP) {
case "0":
expect(result).toEqual(9);
break;
case "1":
expect(result).toEqual(10);
break;
case "2":
expect(result).toEqual(42);
break;
default:
throw new Error("should not happen");
}
});
});

View File

@ -0,0 +1,3 @@
export function getNumber() {
return 8;
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
export function getNumber() {
return 40;
}

View File

@ -0,0 +1,5 @@
var supportsWebAssembly = require("../../../helpers/supportsWebAssembly");
module.exports = function(config) {
return supportsWebAssembly();
};

133
yarn.lock
View File

@ -18,6 +18,117 @@
version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.2.tgz#e13182e1b69871a422d7863e11a4a6f5b814a4bd"
"@webassemblyjs/ast@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.3.0.tgz#524246cd578c30ff792d0c7b49bb0a0f89191dd2"
dependencies:
"@webassemblyjs/helper-wasm-bytecode" "1.3.0"
"@webassemblyjs/wast-parser" "1.3.0"
webassemblyjs "1.3.0"
"@webassemblyjs/floating-point-hex-parser@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.3.0.tgz#a32574e1327a946c78711179fda8bcc808285913"
"@webassemblyjs/helper-buffer@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.3.0.tgz#790599218673099863b6f5f84d36cc8caab861b2"
"@webassemblyjs/helper-code-frame@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.3.0.tgz#8f7d4cd9a2aed3c633cdd79aa660e96279a349bf"
dependencies:
"@webassemblyjs/wast-printer" "1.3.0"
"@webassemblyjs/helper-fsm@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.3.0.tgz#515141ec51c47b892def606dfc706e7708d4398a"
"@webassemblyjs/helper-wasm-bytecode@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.3.0.tgz#d23d55fcef04e4f24d6728e31bda8f1257293f91"
"@webassemblyjs/helper-wasm-section@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.3.0.tgz#a8c9435faca44734fc67dfaee4911ac8e6627bd7"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/helper-buffer" "1.3.0"
"@webassemblyjs/helper-wasm-bytecode" "1.3.0"
"@webassemblyjs/wasm-gen" "1.3.0"
"@webassemblyjs/leb128@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.3.0.tgz#b9995160f0f94d785579a149716bb2cb0d102f08"
dependencies:
leb "^0.3.0"
"@webassemblyjs/validation@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/validation/-/validation-1.3.0.tgz#0a1261f414607a04e2ffebb1b3ea9777b35c97af"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/wasm-edit@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.3.0.tgz#48551c391aebb07e82634cd4ecf257456208a0d3"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/helper-buffer" "1.3.0"
"@webassemblyjs/helper-wasm-bytecode" "1.3.0"
"@webassemblyjs/helper-wasm-section" "1.3.0"
"@webassemblyjs/wasm-gen" "1.3.0"
"@webassemblyjs/wasm-opt" "1.3.0"
"@webassemblyjs/wasm-parser" "1.3.0"
"@webassemblyjs/wast-printer" "1.3.0"
debug "^3.1.0"
"@webassemblyjs/wasm-gen@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.3.0.tgz#acf45b38159f351178aa14135e5efa4172931e9a"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/helper-wasm-bytecode" "1.3.0"
"@webassemblyjs/leb128" "1.3.0"
"@webassemblyjs/wasm-opt@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.3.0.tgz#958150b0d631eb407fc9b85b9a852526c849c015"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/helper-buffer" "1.3.0"
"@webassemblyjs/wasm-gen" "1.3.0"
"@webassemblyjs/wasm-parser" "1.3.0"
"@webassemblyjs/wasm-parser@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.3.0.tgz#66dd5ac632e0f938b1656bd46f01fe5f5f9488d0"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/helper-wasm-bytecode" "1.3.0"
"@webassemblyjs/leb128" "1.3.0"
"@webassemblyjs/wasm-parser" "1.3.0"
webassemblyjs "1.3.0"
"@webassemblyjs/wast-parser@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.3.0.tgz#bfc692d8a159d5fde7c1fee0f4e6d848d5bbcb71"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/floating-point-hex-parser" "1.3.0"
"@webassemblyjs/helper-code-frame" "1.3.0"
"@webassemblyjs/helper-fsm" "1.3.0"
long "^3.2.0"
webassemblyjs "1.3.0"
"@webassemblyjs/wast-printer@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.3.0.tgz#b4ed84f0fea9f222d540e25b262cd5eabfee84d4"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/wast-parser" "1.3.0"
long "^3.2.0"
abab@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"
@ -795,7 +906,7 @@ chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.2:
chalk@^2.0.0, chalk@^2.3.2:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies:
@ -803,7 +914,7 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^2.0.1:
chalk@^2.0.1, chalk@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
dependencies:
@ -3468,6 +3579,10 @@ lcov-parse@^1.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0"
leb@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/leb/-/leb-0.3.0.tgz#32bee9fad168328d6aea8522d833f4180eed1da3"
left-pad@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee"
@ -3578,6 +3693,10 @@ lolex@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6"
long@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b"
longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
@ -6035,6 +6154,16 @@ watchpack@^1.5.0:
graceful-fs "^4.1.2"
neo-async "^2.5.0"
webassemblyjs@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/webassemblyjs/-/webassemblyjs-1.3.0.tgz#970ca465d5ee45ebe611c5c6f7d461900c3e10b2"
dependencies:
"@webassemblyjs/ast" "1.3.0"
"@webassemblyjs/validation" "1.3.0"
"@webassemblyjs/wasm-parser" "1.3.0"
"@webassemblyjs/wast-parser" "1.3.0"
long "^3.2.0"
webidl-conversions@^4.0.1, webidl-conversions@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"