AsyncWebAssemblyModulesPlugin.js (5898B)
1 /* 2 MIT License http://www.opensource.org/licenses/mit-license.php 3 Author Tobias Koppers @sokra 4 */ 5 6 "use strict"; 7 8 const { SyncWaterfallHook } = require("tapable"); 9 const Compilation = require("../Compilation"); 10 const Generator = require("../Generator"); 11 const { tryRunOrWebpackError } = require("../HookWebpackError"); 12 const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); 13 const { compareModulesByIdentifier } = require("../util/comparators"); 14 const memoize = require("../util/memoize"); 15 16 /** @typedef {import("webpack-sources").Source} Source */ 17 /** @typedef {import("../Chunk")} Chunk */ 18 /** @typedef {import("../ChunkGraph")} ChunkGraph */ 19 /** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */ 20 /** @typedef {import("../Compiler")} Compiler */ 21 /** @typedef {import("../DependencyTemplates")} DependencyTemplates */ 22 /** @typedef {import("../Module")} Module */ 23 /** @typedef {import("../ModuleGraph")} ModuleGraph */ 24 /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ 25 /** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry */ 26 /** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions */ 27 28 const getAsyncWebAssemblyGenerator = memoize(() => 29 require("./AsyncWebAssemblyGenerator") 30 ); 31 const getAsyncWebAssemblyJavascriptGenerator = memoize(() => 32 require("./AsyncWebAssemblyJavascriptGenerator") 33 ); 34 const getAsyncWebAssemblyParser = memoize(() => 35 require("./AsyncWebAssemblyParser") 36 ); 37 38 /** 39 * @typedef {Object} WebAssemblyRenderContext 40 * @property {Chunk} chunk the chunk 41 * @property {DependencyTemplates} dependencyTemplates the dependency templates 42 * @property {RuntimeTemplate} runtimeTemplate the runtime template 43 * @property {ModuleGraph} moduleGraph the module graph 44 * @property {ChunkGraph} chunkGraph the chunk graph 45 * @property {CodeGenerationResults} codeGenerationResults results of code generation 46 */ 47 48 /** 49 * @typedef {Object} CompilationHooks 50 * @property {SyncWaterfallHook<[Source, Module, WebAssemblyRenderContext]>} renderModuleContent 51 */ 52 53 /** @type {WeakMap<Compilation, CompilationHooks>} */ 54 const compilationHooksMap = new WeakMap(); 55 56 class AsyncWebAssemblyModulesPlugin { 57 /** 58 * @param {Compilation} compilation the compilation 59 * @returns {CompilationHooks} the attached hooks 60 */ 61 static getCompilationHooks(compilation) { 62 if (!(compilation instanceof Compilation)) { 63 throw new TypeError( 64 "The 'compilation' argument must be an instance of Compilation" 65 ); 66 } 67 let hooks = compilationHooksMap.get(compilation); 68 if (hooks === undefined) { 69 hooks = { 70 renderModuleContent: new SyncWaterfallHook([ 71 "source", 72 "module", 73 "renderContext" 74 ]) 75 }; 76 compilationHooksMap.set(compilation, hooks); 77 } 78 return hooks; 79 } 80 81 constructor(options) { 82 this.options = options; 83 } 84 85 /** 86 * Apply the plugin 87 * @param {Compiler} compiler the compiler instance 88 * @returns {void} 89 */ 90 apply(compiler) { 91 compiler.hooks.compilation.tap( 92 "AsyncWebAssemblyModulesPlugin", 93 (compilation, { normalModuleFactory }) => { 94 const hooks = 95 AsyncWebAssemblyModulesPlugin.getCompilationHooks(compilation); 96 compilation.dependencyFactories.set( 97 WebAssemblyImportDependency, 98 normalModuleFactory 99 ); 100 101 normalModuleFactory.hooks.createParser 102 .for("webassembly/async") 103 .tap("AsyncWebAssemblyModulesPlugin", () => { 104 const AsyncWebAssemblyParser = getAsyncWebAssemblyParser(); 105 106 return new AsyncWebAssemblyParser(); 107 }); 108 normalModuleFactory.hooks.createGenerator 109 .for("webassembly/async") 110 .tap("AsyncWebAssemblyModulesPlugin", () => { 111 const AsyncWebAssemblyJavascriptGenerator = 112 getAsyncWebAssemblyJavascriptGenerator(); 113 const AsyncWebAssemblyGenerator = getAsyncWebAssemblyGenerator(); 114 115 return Generator.byType({ 116 javascript: new AsyncWebAssemblyJavascriptGenerator( 117 compilation.outputOptions.webassemblyModuleFilename 118 ), 119 webassembly: new AsyncWebAssemblyGenerator(this.options) 120 }); 121 }); 122 123 compilation.hooks.renderManifest.tap( 124 "WebAssemblyModulesPlugin", 125 (result, options) => { 126 const { moduleGraph, chunkGraph, runtimeTemplate } = compilation; 127 const { 128 chunk, 129 outputOptions, 130 dependencyTemplates, 131 codeGenerationResults 132 } = options; 133 134 for (const module of chunkGraph.getOrderedChunkModulesIterable( 135 chunk, 136 compareModulesByIdentifier 137 )) { 138 if (module.type === "webassembly/async") { 139 const filenameTemplate = 140 outputOptions.webassemblyModuleFilename; 141 142 result.push({ 143 render: () => 144 this.renderModule( 145 module, 146 { 147 chunk, 148 dependencyTemplates, 149 runtimeTemplate, 150 moduleGraph, 151 chunkGraph, 152 codeGenerationResults 153 }, 154 hooks 155 ), 156 filenameTemplate, 157 pathOptions: { 158 module, 159 runtime: chunk.runtime, 160 chunkGraph 161 }, 162 auxiliary: true, 163 identifier: `webassemblyAsyncModule${chunkGraph.getModuleId( 164 module 165 )}`, 166 hash: chunkGraph.getModuleHash(module, chunk.runtime) 167 }); 168 } 169 } 170 171 return result; 172 } 173 ); 174 } 175 ); 176 } 177 178 renderModule(module, renderContext, hooks) { 179 const { codeGenerationResults, chunk } = renderContext; 180 try { 181 const moduleSource = codeGenerationResults.getSource( 182 module, 183 chunk.runtime, 184 "webassembly" 185 ); 186 return tryRunOrWebpackError( 187 () => 188 hooks.renderModuleContent.call(moduleSource, module, renderContext), 189 "AsyncWebAssemblyModulesPlugin.getCompilationHooks().renderModuleContent" 190 ); 191 } catch (e) { 192 e.module = module; 193 throw e; 194 } 195 } 196 } 197 198 module.exports = AsyncWebAssemblyModulesPlugin;