Deprecate MainTemplate, ChunkTemplate, ModuleTemplate

move logic and hooks to JavascriptModulesPlugin
This commit is contained in:
Tobias Koppers 2019-10-02 08:54:21 +02:00
parent f45ba2408e
commit 69a545c444
24 changed files with 1393 additions and 1088 deletions

2
.gitignore vendored
View File

@ -1,7 +1,7 @@
/node_modules /node_modules
/test/js /test/js
/test/browsertest/js /test/browsertest/js
/test/fixtures/temp-cache-fixture* /test/fixtures/temp-*
/benchmark/js /benchmark/js
/benchmark/fixtures /benchmark/fixtures
/examples/**/dist /examples/**/dist

View File

@ -1302,7 +1302,12 @@ export interface OutputOptions {
/** /**
* The `publicPath` specifies the public URL address of the output files when referenced in a browser. * The `publicPath` specifies the public URL address of the output files when referenced in a browser.
*/ */
publicPath?: string | Function; publicPath?:
| string
| ((
pathData: import("../lib/Compilation").PathData,
assetInfo?: import("../lib/Compilation").AssetInfo
) => string);
/** /**
* The filename of the SourceMaps for the JavaScript files. They are inside the `output.path` directory. * The filename of the SourceMaps for the JavaScript files. They are inside the `output.path` directory.
*/ */

View File

@ -5,78 +5,119 @@
"use strict"; "use strict";
const { SyncWaterfallHook, SyncHook } = require("tapable"); const util = require("util");
const memorize = require("./util/memorize");
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */ /** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./Module")} Module} */
/** @typedef {import("./util/Hash")} Hash} */
/** @typedef {import("webpack-sources").Source} Source} */
/** @typedef {import("./ModuleTemplate").RenderContext} RenderContext} */
/** @typedef {import("./MainTemplate").UpdateHashForChunkContext} UpdateHashForChunkContext} */
/** @typedef {import("./Template").RenderManifestOptions} RenderManifestOptions} */
/** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry} */
module.exports = class ChunkTemplate { const getJavascriptModulesPlugin = memorize(() =>
constructor(outputOptions) { require("./JavascriptModulesPlugin")
this.outputOptions = outputOptions || {}; );
// TODO webpack 6 remove this class
class ChunkTemplate {
/**
* @param {TODO} outputOptions TODO
* @param {Compilation} compilation the compilation
*/
constructor(outputOptions, compilation) {
this._outputOptions = outputOptions || {};
const moduleTemplate = null; // TODO add deprecated ModuleTemplate
this.hooks = Object.freeze({ this.hooks = Object.freeze({
/** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */ renderManifest: {
renderManifest: new SyncWaterfallHook(["result", "options"]), tap: util.deprecate(
/** @type {SyncWaterfallHook<[Source, ModuleTemplate, RenderContext]>} */ (options, fn) => {
modules: new SyncWaterfallHook([ compilation.hooks.renderManifest.tap(
"source", options,
"moduleTemplate", (entries, options) => {
"renderContext" if (options.chunk.hasRuntime()) return entries;
]), return fn(entries, options);
/** @type {SyncWaterfallHook<[Source, ModuleTemplate, RenderContext]>} */ }
render: new SyncWaterfallHook([ );
"source", },
"moduleTemplate", "ChunkTemplate.hooks.renderManifest is deprecated (use Compilation.hooks.renderManifest instead)",
"renderContext" "DEP_WEBPACK_CHUNK_TEMPLATE_RENDER_MANIFEST"
]), )
/** @type {SyncWaterfallHook<[Source, Chunk]>} */ },
renderWithEntry: new SyncWaterfallHook(["source", "chunk"]), modules: {
/** @type {SyncHook<[Hash]>} */ tap: util.deprecate(
hash: new SyncHook(["hash"]), (options, fn) => {
/** @type {SyncHook<[Hash, Chunk]>} */ getJavascriptModulesPlugin()
hashForChunk: new SyncHook(["hash", "chunk"]) .getCompilationHooks(compilation)
.renderChunk.tap(options, (source, renderContext) =>
fn(source, moduleTemplate, renderContext)
);
},
"ChunkTemplate.hooks.modules is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderChunk instead)",
"DEP_WEBPACK_CHUNK_TEMPLATE_MODULES"
)
},
render: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.renderChunk.tap(options, (source, renderContext) =>
fn(source, moduleTemplate, renderContext)
);
},
"ChunkTemplate.hooks.render is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderChunk instead)",
"DEP_WEBPACK_CHUNK_TEMPLATE_RENDER"
)
},
renderWithEntry: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.renderWithEntry.tap(options, (source, renderContext) => {
if (renderContext.chunk.hasRuntime()) return source;
return fn(source, renderContext.chunk);
});
},
"ChunkTemplate.hooks.renderWithEntry is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderWithEntry instead)",
"DEP_WEBPACK_CHUNK_TEMPLATE_RENDER_WITH_ENTRY"
)
},
hash: {
tap: util.deprecate(
(options, fn) => {
compilation.hooks.fullHash.tap(options, fn);
},
"ChunkTemplate.hooks.hash is deprecated (use Compilation.hooks.fullHash instead)",
"DEP_WEBPACK_CHUNK_TEMPLATE_HASH"
)
},
hashForChunk: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.chunkHash.tap(options, (chunk, hash, context) => {
if (chunk.hasRuntime()) return;
fn(hash, chunk, context);
});
},
"ChunkTemplate.hooks.hashForChunk is deprecated (use JavascriptModulesPlugin.getCompilationHooks().chunkHash instead)",
"DEP_WEBPACK_CHUNK_TEMPLATE_HASH_FOR_CHUNK"
)
}
}); });
} }
}
/** Object.defineProperty(ChunkTemplate.prototype, "outputOptions", {
* get: util.deprecate(
* @param {RenderManifestOptions} options render manifest options /**
* @returns {RenderManifestEntry[]} returns render manifest * @this {ChunkTemplate}
*/ * @returns {TODO} output options
getRenderManifest(options) { */
const result = []; function() {
return this._outputOptions;
},
"ChunkTemplate.outputOptions is deprecated (use Compilation.outputOptions instead)",
"DEP_WEBPACK_CHUNK_TEMPLATE_OUTPUT_OPTIONS"
)
});
this.hooks.renderManifest.call(result, options); module.exports = ChunkTemplate;
return result;
}
/**
* Updates hash with information from this template
* @param {Hash} hash the hash to update
* @returns {void}
*/
updateHash(hash) {
hash.update("ChunkTemplate");
hash.update("3");
this.hooks.hash.call(hash);
}
/**
* Updates hash with chunk-specific information from this template
* @param {Hash} hash the hash to update
* @param {Chunk} chunk the chunk
* @param {UpdateHashForChunkContext} context options object
* @returns {void}
*/
updateHashForChunk(hash, chunk, context) {
this.updateHash(hash);
this.hooks.hashForChunk.call(hash, chunk);
}
};

View File

@ -68,6 +68,7 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
/** @typedef {import("./ModuleFactory")} ModuleFactory */ /** @typedef {import("./ModuleFactory")} ModuleFactory */
/** @typedef {import("./RuntimeModule")} RuntimeModule */ /** @typedef {import("./RuntimeModule")} RuntimeModule */
/** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */ /** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */
/** @typedef {import("./Template").RenderManifestOptions} RenderManifestOptions */
/** @typedef {import("./WebpackError")} WebpackError */ /** @typedef {import("./WebpackError")} WebpackError */
/** @typedef {import("./dependencies/DependencyReference")} DependencyReference */ /** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
/** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */ /** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */
@ -127,6 +128,13 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
* @property {(Record<string, (length: number) => string>)=} contentHashWithLength * @property {(Record<string, (length: number) => string>)=} contentHashWithLength
*/ */
/**
* @typedef {Object} ChunkHashContext
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
*/
/** /**
* @typedef {Object} LogEntry * @typedef {Object} LogEntry
* @property {string} type * @property {string} type
@ -407,15 +415,21 @@ class Compilation {
/** @type {AsyncSeriesHook<[]>} */ /** @type {AsyncSeriesHook<[]>} */
afterSeal: new AsyncSeriesHook([]), afterSeal: new AsyncSeriesHook([]),
/** @type {SyncHook<[Chunk, Hash]>} */ /** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */
chunkHash: new SyncHook(["chunk", "chunkHash"]), renderManifest: new SyncWaterfallHook(["result", "options"]),
/** @type {SyncHook<[Hash]>} */
fullHash: new SyncHook(["hash"]),
/** @type {SyncHook<[Chunk, Hash, ChunkHashContext]>} */
chunkHash: new SyncHook(["chunk", "chunkHash", "ChunkHashContext"]),
/** @type {SyncHook<[Module, string]>} */ /** @type {SyncHook<[Module, string]>} */
moduleAsset: new SyncHook(["module", "filename"]), moduleAsset: new SyncHook(["module", "filename"]),
/** @type {SyncHook<[Chunk, string]>} */ /** @type {SyncHook<[Chunk, string]>} */
chunkAsset: new SyncHook(["chunk", "filename"]), chunkAsset: new SyncHook(["chunk", "filename"]),
/** @type {SyncWaterfallHook<[string, TODO]>} */ /** @type {SyncWaterfallHook<[string, object, AssetInfo]>} */
assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]),
/** @type {SyncBailHook<[], boolean>} */ /** @type {SyncBailHook<[], boolean>} */
needAdditionalPass: new SyncBailHook([]), needAdditionalPass: new SyncBailHook([]),
@ -471,18 +485,36 @@ class Compilation {
/** @type {boolean} */ /** @type {boolean} */
this.profile = (options && options.profile) || false; this.profile = (options && options.profile) || false;
this.mainTemplate = new MainTemplate(this.outputOptions); this.mainTemplate = new MainTemplate(this.outputOptions, this);
this.chunkTemplate = new ChunkTemplate(this.outputOptions); this.chunkTemplate = new ChunkTemplate(this.outputOptions, this);
this.runtimeTemplate = new RuntimeTemplate( this.runtimeTemplate = new RuntimeTemplate(
this.outputOptions, this.outputOptions,
this.requestShortener this.requestShortener
); );
/** @type {{asset: ModuleTemplate, javascript: ModuleTemplate, webassembly: ModuleTemplate}} */ /** @type {{javascript: ModuleTemplate}} */
this.moduleTemplates = { this.moduleTemplates = {
asset: new ModuleTemplate(this.runtimeTemplate, "asset"), javascript: new ModuleTemplate(this.runtimeTemplate, this)
javascript: new ModuleTemplate(this.runtimeTemplate, "javascript"),
webassembly: new ModuleTemplate(this.runtimeTemplate, "webassembly")
}; };
Object.defineProperties(this.moduleTemplates, {
asset: {
enumerable: false,
configurable: false,
get() {
throw new WebpackError(
"Compilation.moduleTemplates.asset has been removed"
);
}
},
webassembly: {
enumerable: false,
configurable: false,
get() {
throw new WebpackError(
"Compilation.moduleTemplates.webassembly has been removed"
);
}
}
});
this.moduleGraph = new ModuleGraph(); this.moduleGraph = new ModuleGraph();
this.chunkGraph = undefined; this.chunkGraph = undefined;
@ -1941,11 +1973,7 @@ class Compilation {
if (outputOptions.hashSalt) { if (outputOptions.hashSalt) {
hash.update(outputOptions.hashSalt); hash.update(outputOptions.hashSalt);
} }
this.mainTemplate.updateHash(hash); this.hooks.fullHash.call(hash);
this.chunkTemplate.updateHash(hash);
for (const key of Object.keys(this.moduleTemplates).sort()) {
this.moduleTemplates[key].updateHash(hash);
}
for (const child of this.children) { for (const child of this.children) {
hash.update(child.hash); hash.update(child.hash);
} }
@ -1993,15 +2021,11 @@ class Compilation {
chunkHash.update(outputOptions.hashSalt); chunkHash.update(outputOptions.hashSalt);
} }
chunk.updateHash(chunkHash, chunkGraph); chunk.updateHash(chunkHash, chunkGraph);
const template = chunk.hasRuntime() this.hooks.chunkHash.call(chunk, chunkHash, {
? this.mainTemplate
: this.chunkTemplate;
template.updateHashForChunk(chunkHash, chunk, {
chunkGraph, chunkGraph,
moduleGraph: this.moduleGraph, moduleGraph: this.moduleGraph,
runtimeTemplate: this.runtimeTemplate runtimeTemplate: this.runtimeTemplate
}); });
this.hooks.chunkHash.call(chunk, chunkHash);
chunk.hash = /** @type {string} */ (chunkHash.digest(hashDigest)); chunk.hash = /** @type {string} */ (chunkHash.digest(hashDigest));
hash.update(chunk.hash); hash.update(chunk.hash);
chunk.renderedHash = chunk.hash.substr(0, hashDigestLength); chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
@ -2150,6 +2174,14 @@ class Compilation {
} }
} }
/**
* @param {RenderManifestOptions} options options object
* @returns {RenderManifestEntry[]} manifest entries
*/
getRenderManifest(options) {
return this.hooks.renderManifest.call([], options);
}
/** /**
* @param {Callback} callback signals when the call finishes * @param {Callback} callback signals when the call finishes
* @returns {void} * @returns {void}
@ -2166,10 +2198,7 @@ class Compilation {
/** @type {RenderManifestEntry[]} */ /** @type {RenderManifestEntry[]} */
let manifest; let manifest;
try { try {
const template = chunk.hasRuntime() manifest = this.getRenderManifest({
? this.mainTemplate
: this.chunkTemplate;
manifest = template.getRenderManifest({
chunk, chunk,
hash: this.hash, hash: this.hash,
fullHash: this.fullHash, fullHash: this.fullHash,
@ -2179,7 +2208,7 @@ class Compilation {
chunkGraph: this.chunkGraph, chunkGraph: this.chunkGraph,
moduleGraph: this.moduleGraph, moduleGraph: this.moduleGraph,
runtimeTemplate: this.runtimeTemplate runtimeTemplate: this.runtimeTemplate
}); // [{ render(), filenameTemplate, pathOptions, identifier, hash }] });
} catch (err) { } catch (err) {
this.errors.push(new ChunkRenderError(chunk, "", err)); this.errors.push(new ChunkRenderError(chunk, "", err));
return callback(); return callback();
@ -2294,14 +2323,14 @@ class Compilation {
* @param {PathData} data context data * @param {PathData} data context data
* @returns {string} interpolated path * @returns {string} interpolated path
*/ */
getPath(filename, data) { getPath(filename, data = {}) {
if (!data.hash) { if (!data.hash) {
data = { data = {
hash: this.hash, hash: this.hash,
...data ...data
}; };
} }
return this.mainTemplate.getAssetPath(filename, data); return this.getAssetPath(filename, data);
} }
/** /**
@ -2309,10 +2338,43 @@ class Compilation {
* @param {PathData} data context data * @param {PathData} data context data
* @returns {{ path: string, info: AssetInfo }} interpolated path and asset info * @returns {{ path: string, info: AssetInfo }} interpolated path and asset info
*/ */
getPathWithInfo(filename, data) { getPathWithInfo(filename, data = {}) {
data = data || {}; if (!data.hash) {
data.hash = data.hash || this.hash; data = {
return this.mainTemplate.getAssetPathWithInfo(filename, data); hash: this.hash,
...data
};
}
return this.getAssetPathWithInfo(filename, data);
}
/**
* @param {string | function(PathData, AssetInfo=): string} filename used to get asset path with hash
* @param {PathData} data context data
* @returns {string} interpolated path
*/
getAssetPath(filename, data) {
return this.hooks.assetPath.call(
typeof filename === "function" ? filename(data) : filename,
data,
undefined
);
}
/**
* @param {string | function(PathData, AssetInfo=): string} filename used to get asset path with hash
* @param {PathData} data context data
* @returns {{ path: string, info: AssetInfo }} interpolated path and asset info
*/
getAssetPathWithInfo(filename, data) {
const assetInfo = {};
// TODO webpack 5: refactor assetPath hook to receive { path, info } object
const newPath = this.hooks.assetPath.call(
typeof filename === "function" ? filename(data, assetInfo) : filename,
data,
assetInfo
);
return { path: newPath, info: assetInfo };
} }
/** /**

View File

@ -1,27 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const FunctionModuleTemplatePlugin = require("./FunctionModuleTemplatePlugin");
/** @typedef {import("./Compiler")} Compiler */
class FunctionModulePlugin {
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap("FunctionModulePlugin", compilation => {
new FunctionModuleTemplatePlugin({
compilation
}).apply(compilation.moduleTemplates.javascript);
});
}
}
module.exports = FunctionModulePlugin;

View File

@ -69,4 +69,26 @@ const makeWebpackErrorCallback = (callback, hook) => {
callback(null, result); callback(null, result);
}; };
}; };
module.exports.makeWebpackErrorCallback = makeWebpackErrorCallback; module.exports.makeWebpackErrorCallback = makeWebpackErrorCallback;
/**
* @template T
* @param {function(): T} fn function which will be wrapping in try catch
* @param {string} hook name of hook
* @returns {T} the result
*/
const tryRunOrWebpackError = (fn, hook) => {
let r;
try {
r = fn();
} catch (err) {
if (err instanceof WebpackError) {
throw err;
}
throw new HookWebpackError(err, hook);
}
return r;
};
module.exports.tryRunOrWebpackError = tryRunOrWebpackError;

View File

@ -342,7 +342,7 @@ class HotModuleReplacementPlugin {
newRuntimeModules newRuntimeModules
); );
hotUpdateChunk.removedModules = removedModules; hotUpdateChunk.removedModules = removedModules;
const renderManifest = chunkTemplate.getRenderManifest({ const renderManifest = compilation.getRenderManifest({
chunk: hotUpdateChunk, chunk: hotUpdateChunk,
hash: records.hash, hash: records.hash,
fullHash: records.hash, fullHash: records.hash,

View File

@ -5,10 +5,18 @@
"use strict"; "use strict";
const { ConcatSource } = require("webpack-sources"); const { SyncWaterfallHook, SyncHook } = require("tapable");
const {
ConcatSource,
OriginalSource,
PrefixSource
} = require("webpack-sources");
const Compilation = require("./Compilation");
const { tryRunOrWebpackError } = require("./HookWebpackError");
const HotUpdateChunk = require("./HotUpdateChunk"); const HotUpdateChunk = require("./HotUpdateChunk");
const JavascriptGenerator = require("./JavascriptGenerator"); const JavascriptGenerator = require("./JavascriptGenerator");
const JavascriptParser = require("./JavascriptParser"); const JavascriptParser = require("./JavascriptParser");
const RuntimeGlobals = require("./RuntimeGlobals");
const Template = require("./Template"); const Template = require("./Template");
const { compareModulesByIdOrIdentifier } = require("./util/comparators"); const { compareModulesByIdOrIdentifier } = require("./util/comparators");
const createHash = require("./util/createHash"); const createHash = require("./util/createHash");
@ -17,12 +25,13 @@ const createHash = require("./util/createHash");
/** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./ChunkGraph")} ChunkGraph */ /** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./ChunkTemplate")} ChunkTemplate */ /** @typedef {import("./ChunkTemplate")} ChunkTemplate */
/** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./Compilation").ChunkHashContext} ChunkHashContext */
/** @typedef {import("./Compiler")} Compiler */ /** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module")} Module */ /** @typedef {import("./Module")} Module */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */ /** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./ModuleTemplate").RenderContext} RenderContext */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./util/Hash")} Hash */
/** /**
* @param {Chunk} chunk a chunk * @param {Chunk} chunk a chunk
@ -40,7 +49,89 @@ const chunkHasJs = (chunk, chunkGraph) => {
return false; return false;
}; };
/**
* @typedef {Object} RenderContext
* @property {Chunk} chunk the chunk
* @property {DependencyTemplates} dependencyTemplates the dependency templates
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
*/
/**
* @typedef {Object} MainRenderContext
* @property {Chunk} chunk the chunk
* @property {DependencyTemplates} dependencyTemplates the dependency templates
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {string} hash hash to be used for render call
*/
/**
* @typedef {Object} RenderBootstrapContext
* @property {Chunk} chunk the chunk
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {string} hash hash to be used for render call
*/
/**
* @typedef {Object} CompilationHooks
* @property {SyncWaterfallHook<[Source, Module, RenderContext]>} renderModuleContent
* @property {SyncWaterfallHook<[Source, Module, RenderContext]>} renderModuleContainer
* @property {SyncWaterfallHook<[Source, Module, RenderContext]>} renderModulePackage
* @property {SyncWaterfallHook<[Source, RenderContext]>} renderChunk
* @property {SyncWaterfallHook<[Source, RenderContext]>} renderMain
* @property {SyncWaterfallHook<[Source, RenderContext]>} renderWithEntry
* @property {SyncWaterfallHook<[string, RenderBootstrapContext]>} renderRequire
* @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash
*/
/** @type {WeakMap<Compilation, CompilationHooks>} */
const compilationHooksMap = new WeakMap();
class JavascriptModulesPlugin { class JavascriptModulesPlugin {
/**
* @param {Compilation} compilation the compilation
* @returns {CompilationHooks} the attached hooks
*/
static getCompilationHooks(compilation) {
if (!(compilation instanceof Compilation)) {
throw new TypeError(
"The 'compilation' argument must be an instance of JavascriptParser"
);
}
let hooks = compilationHooksMap.get(compilation);
if (hooks === undefined) {
hooks = {
renderModuleContent: new SyncWaterfallHook([
"source",
"module",
"renderContext"
]),
renderModuleContainer: new SyncWaterfallHook([
"source",
"module",
"renderContext"
]),
renderModulePackage: new SyncWaterfallHook([
"source",
"module",
"renderContext"
]),
renderWithEntry: new SyncWaterfallHook(["source", "renderContext"]),
renderChunk: new SyncWaterfallHook(["source", "renderContext"]),
renderMain: new SyncWaterfallHook(["source", "renderContext"]),
renderRequire: new SyncWaterfallHook(["code", "renderContext"]),
chunkHash: new SyncHook(["chunk", "hash", "context"])
};
compilationHooksMap.set(compilation, hooks);
}
return hooks;
}
/** /**
* @param {Compiler} compiler webpack compiler * @param {Compiler} compiler webpack compiler
* @returns {void} * @returns {void}
@ -49,6 +140,7 @@ class JavascriptModulesPlugin {
compiler.hooks.compilation.tap( compiler.hooks.compilation.tap(
"JavascriptModulesPlugin", "JavascriptModulesPlugin",
(compilation, { normalModuleFactory }) => { (compilation, { normalModuleFactory }) => {
const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
const moduleGraph = compilation.moduleGraph; const moduleGraph = compilation.moduleGraph;
normalModuleFactory.hooks.createParser normalModuleFactory.hooks.createParser
.for("javascript/auto") .for("javascript/auto")
@ -86,7 +178,6 @@ class JavascriptModulesPlugin {
const chunk = options.chunk; const chunk = options.chunk;
const hash = options.hash; const hash = options.hash;
const outputOptions = options.outputOptions; const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates; const dependencyTemplates = options.dependencyTemplates;
const filenameTemplate = const filenameTemplate =
@ -94,14 +185,17 @@ class JavascriptModulesPlugin {
result.push({ result.push({
render: () => render: () =>
compilation.mainTemplate.render(moduleTemplates.javascript, { this.renderMain(
hash, {
chunk, hash,
dependencyTemplates, chunk,
runtimeTemplate: options.runtimeTemplate, dependencyTemplates,
moduleGraph: options.moduleGraph, runtimeTemplate: options.runtimeTemplate,
chunkGraph: options.chunkGraph moduleGraph: options.moduleGraph,
}), chunkGraph: options.chunkGraph
},
hooks
),
filenameTemplate, filenameTemplate,
pathOptions: { pathOptions: {
chunk, chunk,
@ -121,7 +215,6 @@ class JavascriptModulesPlugin {
const hotUpdateChunk = const hotUpdateChunk =
chunk instanceof HotUpdateChunk ? chunk : null; chunk instanceof HotUpdateChunk ? chunk : null;
const outputOptions = options.outputOptions; const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates; const dependencyTemplates = options.dependencyTemplates;
if (!hotUpdateChunk && !chunkHasJs(chunk, chunkGraph)) { if (!hotUpdateChunk && !chunkHasJs(chunk, chunkGraph)) {
@ -141,17 +234,17 @@ class JavascriptModulesPlugin {
result.push({ result.push({
render: () => render: () =>
this.renderJavascript( this.renderChunk(
compilation, compilation,
compilation.chunkTemplate, compilation.chunkTemplate,
moduleTemplates.javascript,
{ {
chunk, chunk,
dependencyTemplates, dependencyTemplates,
runtimeTemplate: compilation.runtimeTemplate, runtimeTemplate: compilation.runtimeTemplate,
moduleGraph, moduleGraph,
chunkGraph: compilation.chunkGraph chunkGraph: compilation.chunkGraph
} },
hooks
), ),
filenameTemplate, filenameTemplate,
pathOptions: { pathOptions: {
@ -166,6 +259,30 @@ class JavascriptModulesPlugin {
return result; return result;
} }
); );
compilation.hooks.chunkHash.tap(
"JavascriptModulesPlugin",
(chunk, hash, context) => {
hooks.chunkHash.call(chunk, hash, context);
if (chunk.hasRuntime()) {
const bootstrap = this.renderBootstrap(
{
hash: "0000",
chunk,
chunkGraph: context.chunkGraph,
moduleGraph: context.moduleGraph,
runtimeTemplate: context.runtimeTemplate
},
hooks
);
for (const key of Object.keys(bootstrap)) {
hash.update(key);
for (const line of bootstrap[key]) {
hash.update(line);
}
}
}
}
);
compilation.hooks.contentHash.tap("JavascriptModulesPlugin", chunk => { compilation.hooks.contentHash.tap("JavascriptModulesPlugin", chunk => {
const { const {
chunkGraph, chunkGraph,
@ -181,12 +298,9 @@ class JavascriptModulesPlugin {
const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null; const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
const hash = createHash(hashFunction); const hash = createHash(hashFunction);
if (hashSalt) hash.update(hashSalt); if (hashSalt) hash.update(hashSalt);
const template = chunk.hasRuntime()
? compilation.mainTemplate
: compilation.chunkTemplate;
hash.update(`${chunk.id} `); hash.update(`${chunk.id} `);
hash.update(chunk.ids ? chunk.ids.join(",") : ""); hash.update(chunk.ids ? chunk.ids.join(",") : "");
template.updateHashForChunk(hash, chunk, { hooks.chunkHash.call(chunk, hash, {
chunkGraph, chunkGraph,
moduleGraph, moduleGraph,
runtimeTemplate runtimeTemplate
@ -209,36 +323,411 @@ class JavascriptModulesPlugin {
); );
} }
/**
* @param {Module} module the rendered module
* @param {RenderContext} renderContext options object
* @param {CompilationHooks} hooks hooks
* @returns {Source} the newly generated source from rendering
*/
renderModule(module, renderContext, hooks) {
const {
chunkGraph,
moduleGraph,
runtimeTemplate,
dependencyTemplates
} = renderContext;
try {
const moduleSource = module.source({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type: "javascript"
});
const moduleSourcePostContent = tryRunOrWebpackError(
() =>
hooks.renderModuleContent.call(moduleSource, module, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderModuleContent"
);
const source = new ConcatSource();
const args = [];
const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
module
);
const needModule = runtimeRequirements.has(RuntimeGlobals.module);
const needExports = runtimeRequirements.has(RuntimeGlobals.exports);
const needRequire =
runtimeRequirements.has(RuntimeGlobals.require) ||
runtimeRequirements.has(RuntimeGlobals.requireScope);
const needThisAsExports = runtimeRequirements.has(
RuntimeGlobals.thisAsExports
);
if (needExports || needRequire || needModule)
args.push(
needModule
? module.moduleArgument
: "__unused_webpack_" + module.moduleArgument
);
if (needExports || needRequire)
args.push(
needExports
? module.exportsArgument
: "__unused_webpack_" + module.exportsArgument
);
if (needRequire) args.push("__webpack_require__");
if (!needThisAsExports && runtimeTemplate.supportsArrowFunction()) {
source.add("/***/ ((" + args.join(", ") + ") => {\n\n");
} else {
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
}
if (module.buildInfo.strict) source.add('"use strict";\n');
source.add(moduleSourcePostContent);
source.add("\n\n/***/ })");
const moduleSourcePostContainer = tryRunOrWebpackError(
() => hooks.renderModuleContainer.call(source, module, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer"
);
return tryRunOrWebpackError(
() =>
hooks.renderModulePackage.call(
moduleSourcePostContainer,
module,
renderContext
),
"JavascriptModulesPlugin.getCompilationHooks().renderModulePackage"
);
} catch (e) {
e.module = module;
throw e;
}
}
/** /**
* @param {Compilation} compilation the compilation * @param {Compilation} compilation the compilation
* @param {ChunkTemplate} chunkTemplate the chunk template * @param {ChunkTemplate} chunkTemplate the chunk template
* @param {ModuleTemplate} moduleTemplate the module template
* @param {RenderContext} renderContext the render context * @param {RenderContext} renderContext the render context
* @param {CompilationHooks} hooks hooks
* @returns {Source} the rendered source * @returns {Source} the rendered source
*/ */
renderJavascript(compilation, chunkTemplate, moduleTemplate, renderContext) { renderChunk(compilation, chunkTemplate, renderContext, hooks) {
const chunk = renderContext.chunk; const chunk = renderContext.chunk;
const moduleSources = Template.renderChunkModules( const moduleSources = Template.renderChunkModules(
renderContext, renderContext,
m => m.getSourceTypes().has("javascript"), m => m.getSourceTypes().has("javascript"),
moduleTemplate module => this.renderModule(module, renderContext, hooks)
); );
const core = chunkTemplate.hooks.modules.call( let source = tryRunOrWebpackError(
moduleSources, () => hooks.renderChunk.call(moduleSources, renderContext),
moduleTemplate, "JavascriptModulesPlugin.getCompilationHooks().renderChunk"
renderContext
);
let source = chunkTemplate.hooks.render.call(
core,
moduleTemplate,
renderContext
); );
if (renderContext.chunkGraph.getNumberOfEntryModules(chunk) > 0) { if (renderContext.chunkGraph.getNumberOfEntryModules(chunk) > 0) {
source = chunkTemplate.hooks.renderWithEntry.call(source, chunk); source = tryRunOrWebpackError(
() => hooks.renderWithEntry.call(source, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderWithEntry"
);
} }
chunk.rendered = true; chunk.rendered = true;
return new ConcatSource(source, ";"); return new ConcatSource(source, ";");
} }
/**
* @param {MainRenderContext} renderContext options object
* @param {CompilationHooks} hooks hooks
* @returns {Source} the newly generated source from rendering
*/
renderMain(renderContext, hooks) {
const { chunk, chunkGraph, runtimeTemplate } = renderContext;
let source = new ConcatSource();
if (runtimeTemplate.supportsConst()) {
source.add("/******/ (() => { // webpackBootstrap\n");
} else {
source.add("/******/ (function() { // webpackBootstrap\n");
}
source.add("/******/ \tvar __webpack_modules__ = (");
source.add(
Template.renderChunkModules(
renderContext,
m => m.getSourceTypes().has("javascript"),
module => this.renderModule(module, renderContext, hooks),
"/******/ \t"
)
);
source.add(");\n");
const bootstrap = this.renderBootstrap(renderContext, hooks);
source.add(
"/************************************************************************/\n"
);
source.add(
new PrefixSource(
"/******/",
new OriginalSource(
Template.prefix(bootstrap.header, " \t") + "\n",
"webpack/bootstrap"
)
)
);
const runtimeModules = renderContext.chunkGraph.getChunkRuntimeModulesInOrder(
chunk
);
if (runtimeModules.length > 0) {
source.add(
"/************************************************************************/\n"
);
source.add(
Template.renderMainRuntimeModules(runtimeModules, renderContext)
);
}
source.add(
"/************************************************************************/\n"
);
source.add(
new PrefixSource(
"/******/",
new OriginalSource(
Template.prefix(bootstrap.startup, " \t") + "\n",
"webpack/startup"
)
)
);
source.add("/******/ })()\n");
/** @type {Source} */
let finalSource = tryRunOrWebpackError(
() => hooks.renderMain.call(source, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderMain"
);
if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
finalSource = tryRunOrWebpackError(
() => hooks.renderWithEntry.call(finalSource, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderWithEntry"
);
}
if (!finalSource) {
throw new Error(
"Compiler error: MainTemplate plugin 'render' should return something"
);
}
chunk.rendered = true;
return new ConcatSource(finalSource, ";");
}
/**
* @param {RenderBootstrapContext} renderContext options object
* @param {CompilationHooks} hooks hooks
* @returns {{ header: string[], startup: string[] }} the generated source of the bootstrap code
*/
renderBootstrap(renderContext, hooks) {
const { chunkGraph, chunk, runtimeTemplate } = renderContext;
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
const requireFunction = runtimeRequirements.has(RuntimeGlobals.require);
const moduleCache = runtimeRequirements.has(RuntimeGlobals.moduleCache);
const moduleUsed = runtimeRequirements.has(RuntimeGlobals.module);
const exportsUsed = runtimeRequirements.has(RuntimeGlobals.exports);
const requireScopeUsed = runtimeRequirements.has(
RuntimeGlobals.requireScope
);
const interceptModuleExecution = runtimeRequirements.has(
RuntimeGlobals.interceptModuleExecution
);
const returnExportsFromRuntime = runtimeRequirements.has(
RuntimeGlobals.returnExportsFromRuntime
);
const useRequire =
requireFunction ||
interceptModuleExecution ||
returnExportsFromRuntime ||
moduleUsed ||
exportsUsed;
const result = {
header: [],
startup: []
};
let buf = result.header;
let startup = result.startup;
if (useRequire || moduleCache) {
buf.push("// The module cache");
buf.push("var __webpack_module_cache__ = {};");
buf.push("");
}
if (useRequire) {
buf.push("// The require function");
buf.push(`function __webpack_require__(moduleId) {`);
buf.push(Template.indent('"use strict";'));
buf.push(Template.indent(this.renderRequire(renderContext, hooks)));
buf.push("}");
buf.push("");
} else if (runtimeRequirements.has(RuntimeGlobals.requireScope)) {
buf.push("// The require scope");
buf.push("var __webpack_require__ = {};");
}
if (runtimeRequirements.has(RuntimeGlobals.moduleFactories)) {
buf.push("");
buf.push("// expose the modules object (__webpack_modules__)");
buf.push(`${RuntimeGlobals.moduleFactories} = __webpack_modules__;`);
}
if (moduleCache) {
buf.push("");
buf.push("// expose the module cache");
buf.push(`${RuntimeGlobals.moduleCache} = __webpack_module_cache__;`);
}
if (interceptModuleExecution) {
buf.push("");
buf.push("// expose the module execution interceptor");
buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`);
}
buf.push("");
if (!runtimeRequirements.has(RuntimeGlobals.startupNoDefault)) {
if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
/** @type {string[]} */
const buf2 = [];
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(
chunk
);
buf2.push(
returnExportsFromRuntime
? "// Load entry module and return exports"
: "// Load entry module"
);
let i = chunkGraph.getNumberOfEntryModules(chunk);
for (const entryModule of chunkGraph.getChunkEntryModulesIterable(
chunk
)) {
const mayReturn =
--i === 0 && returnExportsFromRuntime ? "return " : "";
const moduleId = chunkGraph.getModuleId(entryModule);
let moduleIdExpr = JSON.stringify(moduleId);
if (runtimeRequirements.has(RuntimeGlobals.entryModuleId)) {
moduleIdExpr = `${RuntimeGlobals.entryModuleId} = ${moduleIdExpr}`;
}
if (useRequire) {
buf2.push(`${mayReturn}__webpack_require__(${moduleIdExpr});`);
} else if (requireScopeUsed) {
buf2.push(
`__webpack_modules__[${moduleIdExpr}](0, 0, __webpack_require__);`
);
} else {
buf2.push(`__webpack_modules__[${moduleIdExpr}]();`);
}
}
if (runtimeRequirements.has(RuntimeGlobals.startup)) {
buf.push(
Template.asString([
"// the startup function",
`${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction(
"",
buf2
)};`
])
);
startup.push("// run startup");
startup.push(`return ${RuntimeGlobals.startup}();`);
} else {
startup.push(
Template.asString(["// startup", Template.asString(buf2)])
);
}
} else if (runtimeRequirements.has(RuntimeGlobals.startup)) {
buf.push(
Template.asString([
"// the startup function",
"// It's empty as no entry modules are in this chunk",
`${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction(
"",
""
)}`
])
);
}
} else if (runtimeRequirements.has(RuntimeGlobals.startup)) {
startup.push("// run startup");
startup.push(`return ${RuntimeGlobals.startup}();`);
}
return result;
}
/**
* @param {RenderBootstrapContext} renderContext options object
* @param {CompilationHooks} hooks hooks
* @returns {string} the generated source of the require function
*/
renderRequire(renderContext, hooks) {
const {
chunk,
chunkGraph,
runtimeTemplate: { outputOptions }
} = renderContext;
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
const moduleExecution = runtimeRequirements.has(
RuntimeGlobals.interceptModuleExecution
)
? Template.asString([
"var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };",
`${RuntimeGlobals.interceptModuleExecution}.forEach(function(handler) { handler(execOptions); });`,
"module = execOptions.module;",
"execOptions.factory.call(module.exports, module, module.exports, execOptions.require);"
])
: runtimeRequirements.has(RuntimeGlobals.thisAsExports)
? Template.asString([
"__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);"
])
: Template.asString([
"__webpack_modules__[moduleId](module, module.exports, __webpack_require__);"
]);
const content = Template.asString([
"// Check if module is in cache",
"if(__webpack_module_cache__[moduleId]) {",
Template.indent("return __webpack_module_cache__[moduleId].exports;"),
"}",
"// Create a new module (and put it into the cache)",
"var module = __webpack_module_cache__[moduleId] = {",
Template.indent(["i: moduleId,", "l: false,", "exports: {}"]),
"};",
"",
outputOptions.strictModuleExceptionHandling
? Template.asString([
"// Execute the module function",
"var threw = true;",
"try {",
Template.indent([moduleExecution, "threw = false;"]),
"} finally {",
Template.indent([
"if(threw) delete __webpack_module_cache__[moduleId];"
]),
"}"
])
: Template.asString([
"// Execute the module function",
moduleExecution
]),
"",
"// Flag the module as loaded",
"module.l = true;",
"",
"// Return the exports of the module",
"return module.exports;"
]);
return tryRunOrWebpackError(
() => hooks.renderRequire.call(content, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderRequire"
);
}
} }
module.exports = JavascriptModulesPlugin; module.exports = JavascriptModulesPlugin;

View File

@ -5,19 +5,16 @@
"use strict"; "use strict";
const { SyncWaterfallHook, SyncHook } = require("tapable"); const { SyncWaterfallHook } = require("tapable");
const { const util = require("util");
ConcatSource,
OriginalSource,
PrefixSource
} = require("webpack-sources");
const RuntimeGlobals = require("./RuntimeGlobals"); const RuntimeGlobals = require("./RuntimeGlobals");
const Template = require("./Template"); const memorize = require("./util/memorize");
/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */ /** @typedef {import("webpack-sources").ConcatSource} ConcatSource */
/** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */ /** @typedef {import("./ModuleTemplate")} ModuleTemplate */
/** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./Compilation").AssetInfo} AssetInfo */ /** @typedef {import("./Compilation").AssetInfo} AssetInfo */
/** @typedef {import("./Module")} Module} */ /** @typedef {import("./Module")} Module} */
/** @typedef {import("./util/Hash")} Hash} */ /** @typedef {import("./util/Hash")} Hash} */
@ -29,53 +26,93 @@ const Template = require("./Template");
/** @typedef {import("./Template").RenderManifestOptions} RenderManifestOptions} */ /** @typedef {import("./Template").RenderManifestOptions} RenderManifestOptions} */
/** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry} */ /** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry} */
/** const getJavascriptModulesPlugin = memorize(() =>
* @typedef {Object} MainRenderContext require("./JavascriptModulesPlugin")
* @property {Chunk} chunk the chunk );
* @property {DependencyTemplates} dependencyTemplates the dependency templates
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {string} hash hash to be used for render call
*/
/** // TODO webpack 6 remove this class
* @typedef {Object} RenderBootstrapContext class MainTemplate {
* @property {Chunk} chunk the chunk
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {string} hash hash to be used for render call
*/
/**
* @typedef {Object} UpdateHashForChunkContext
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
*/
module.exports = class MainTemplate {
/** /**
* *
* @param {TODO=} outputOptions output options for the MainTemplate * @param {TODO=} outputOptions output options for the MainTemplate
* @param {Compilation} compilation the compilation
*/ */
constructor(outputOptions) { constructor(outputOptions, compilation) {
/** @type {TODO?} */ /** @type {TODO?} */
this.outputOptions = outputOptions || {}; this._outputOptions = outputOptions || {};
this.hooks = Object.freeze({ this.hooks = Object.freeze({
/** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */ renderManifest: {
renderManifest: new SyncWaterfallHook(["result", "options"]), tap: util.deprecate(
/** @type {SyncWaterfallHook<[string, RenderBootstrapContext]>} */ (options, fn) => {
require: new SyncWaterfallHook(["source", "renderContext"]), compilation.hooks.renderManifest.tap(
/** @type {SyncWaterfallHook<[Source, Chunk, string]>} */ options,
renderWithEntry: new SyncWaterfallHook(["source", "chunk", "hash"]), (entries, options) => {
/** @type {SyncWaterfallHook<[string, object, AssetInfo]>} */ if (!options.chunk.hasRuntime()) return entries;
assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]), return fn(entries, options);
/** @type {SyncHook<[Hash]>} */ }
hash: new SyncHook(["hash"]), );
/** @type {SyncHook<[Hash, Chunk]>} */ },
hashForChunk: new SyncHook(["hash", "chunk"]), "MainTemplate.hooks.renderManifest is deprecated (use Compilation.hooks.renderManifest instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_RENDER_MANIFEST"
)
},
require: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.renderRequire.tap(options, fn);
},
"MainTemplate.hooks.require is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderRequire instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_REQUIRE"
)
},
renderWithEntry: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.renderWithEntry.tap(options, (source, renderContext) => {
if (!renderContext.chunk.hasRuntime()) return source;
return fn(source, renderContext.chunk, compilation.hash);
});
},
"MainTemplate.hooks.renderWithEntry is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderWithEntry instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_RENDER_WITH_ENTRY"
)
},
assetPath: {
tap: util.deprecate(
(options, fn) => {
compilation.hooks.assetPath.tap(options, fn);
},
"MainTemplate.hooks.assetPath is deprecated (use Compilation.hooks.assetPath instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_ASSET_PATH"
)
},
hash: {
tap: util.deprecate(
(options, fn) => {
compilation.hooks.fullHash.tap(options, fn);
},
"MainTemplate.hooks.hash is deprecated (use Compilation.hooks.fullHash instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_HASH"
)
},
hashForChunk: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.chunkHash.tap(options, (chunk, hash) => {
if (!chunk.hasRuntime()) return;
return fn(hash, chunk);
});
},
"MainTemplate.hooks.hashForChunk is deprecated (use JavascriptModulesPlugin.getCompilationHooks().chunkHash instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_HASH_FOR_CHUNK"
)
},
// for compatibility: // for compatibility:
/** @type {SyncWaterfallHook<[string, Chunk, string, ModuleTemplate, DependencyTemplates]>} */ /** @type {SyncWaterfallHook<[string, Chunk, string, ModuleTemplate, DependencyTemplates]>} */
@ -98,379 +135,78 @@ module.exports = class MainTemplate {
"chunkIdExpression" "chunkIdExpression"
]) ])
}); });
this.hooks.require.tap("MainTemplate", (source, renderContext) => {
const { chunk, chunkGraph } = renderContext;
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
const moduleExecution = runtimeRequirements.has(
RuntimeGlobals.interceptModuleExecution
)
? Template.asString([
"var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };",
`${RuntimeGlobals.interceptModuleExecution}.forEach(function(handler) { handler(execOptions); });`,
"module = execOptions.module;",
"execOptions.factory.call(module.exports, module, module.exports, execOptions.require);"
])
: runtimeRequirements.has(RuntimeGlobals.thisAsExports)
? Template.asString([
"__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);"
])
: Template.asString([
"__webpack_modules__[moduleId](module, module.exports, __webpack_require__);"
]);
return Template.asString([
source,
"// Check if module is in cache",
"if(__webpack_module_cache__[moduleId]) {",
Template.indent("return __webpack_module_cache__[moduleId].exports;"),
"}",
"// Create a new module (and put it into the cache)",
"var module = __webpack_module_cache__[moduleId] = {",
Template.indent(["i: moduleId,", "l: false,", "exports: {}"]),
"};",
"",
outputOptions.strictModuleExceptionHandling
? Template.asString([
"// Execute the module function",
"var threw = true;",
"try {",
Template.indent([moduleExecution, "threw = false;"]),
"} finally {",
Template.indent([
"if(threw) delete __webpack_module_cache__[moduleId];"
]),
"}"
])
: Template.asString([
"// Execute the module function",
moduleExecution
]),
"",
"// Flag the module as loaded",
"module.l = true;",
"",
"// Return the exports of the module",
"return module.exports;"
]);
});
}
// TODO webpack 6 remove this.renderCurrentHashCode = util.deprecate(
// BACKWARD COMPAT START /**
get requireFn() { * @deprecated
return "__webpack_require__"; * @param {string} hash the hash
} * @param {number=} length length of the hash
* @returns {string} generated code
/** */ (hash, length) => {
* @deprecated if (length) {
* @param {string} hash the hash return `${RuntimeGlobals.getFullHash} ? ${
* @param {number=} length length of the hash RuntimeGlobals.getFullHash
* @returns {string} generated code }().slice(0, ${length}) : ${hash.slice(0, length)}`;
*/
renderCurrentHashCode(hash, length) {
if (length) {
return `${RuntimeGlobals.getFullHash} ? ${
RuntimeGlobals.getFullHash
}().slice(0, ${length}) : ${hash.slice(0, length)}`;
}
return `${RuntimeGlobals.getFullHash} ? ${RuntimeGlobals.getFullHash}() : ${hash}`;
}
// BACKWARD COMPAT END
/**
*
* @param {RenderManifestOptions} options render manifest options
* @returns {RenderManifestEntry[]} returns render manifest
*/
getRenderManifest(options) {
const result = [];
this.hooks.renderManifest.call(result, options);
return result;
}
/**
* @param {RenderBootstrapContext} renderContext options object
* @returns {{ header: string[], startup: string[] }} the generated source of the bootstrap code
*/
renderBootstrap(renderContext) {
const { chunkGraph, chunk, runtimeTemplate } = renderContext;
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
const requireFunction = runtimeRequirements.has(RuntimeGlobals.require);
const moduleCache = runtimeRequirements.has(RuntimeGlobals.moduleCache);
const moduleUsed = runtimeRequirements.has(RuntimeGlobals.module);
const exportsUsed = runtimeRequirements.has(RuntimeGlobals.exports);
const requireScopeUsed = runtimeRequirements.has(
RuntimeGlobals.requireScope
);
const interceptModuleExecution = runtimeRequirements.has(
RuntimeGlobals.interceptModuleExecution
);
const returnExportsFromRuntime = runtimeRequirements.has(
RuntimeGlobals.returnExportsFromRuntime
);
const useRequire =
requireFunction ||
interceptModuleExecution ||
returnExportsFromRuntime ||
moduleUsed ||
exportsUsed;
const result = {
header: [],
startup: []
};
let buf = result.header;
let startup = result.startup;
if (useRequire || moduleCache) {
buf.push("// The module cache");
buf.push("var __webpack_module_cache__ = {};");
buf.push("");
}
if (useRequire) {
buf.push("// The require function");
buf.push(`function __webpack_require__(moduleId) {`);
buf.push(Template.indent('"use strict";'));
buf.push(Template.indent(this.hooks.require.call("", renderContext)));
buf.push("}");
buf.push("");
} else if (runtimeRequirements.has(RuntimeGlobals.requireScope)) {
buf.push("// The require scope");
buf.push("var __webpack_require__ = {};");
}
if (runtimeRequirements.has(RuntimeGlobals.moduleFactories)) {
buf.push("");
buf.push("// expose the modules object (__webpack_modules__)");
buf.push(`${RuntimeGlobals.moduleFactories} = __webpack_modules__;`);
}
if (moduleCache) {
buf.push("");
buf.push("// expose the module cache");
buf.push(`${RuntimeGlobals.moduleCache} = __webpack_module_cache__;`);
}
if (interceptModuleExecution) {
buf.push("");
buf.push("// expose the module execution interceptor");
buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`);
}
buf.push("");
if (!runtimeRequirements.has(RuntimeGlobals.startupNoDefault)) {
if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
/** @type {string[]} */
const buf2 = [];
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(
chunk
);
buf2.push(
returnExportsFromRuntime
? "// Load entry module and return exports"
: "// Load entry module"
);
let i = chunkGraph.getNumberOfEntryModules(chunk);
for (const entryModule of chunkGraph.getChunkEntryModulesIterable(
chunk
)) {
const mayReturn =
--i === 0 && returnExportsFromRuntime ? "return " : "";
const moduleId = chunkGraph.getModuleId(entryModule);
let moduleIdExpr = JSON.stringify(moduleId);
if (runtimeRequirements.has(RuntimeGlobals.entryModuleId)) {
moduleIdExpr = `${RuntimeGlobals.entryModuleId} = ${moduleIdExpr}`;
}
if (useRequire) {
buf2.push(`${mayReturn}__webpack_require__(${moduleIdExpr});`);
} else if (requireScopeUsed) {
buf2.push(
`__webpack_modules__[${moduleIdExpr}](0, 0, __webpack_require__);`
);
} else {
buf2.push(`__webpack_modules__[${moduleIdExpr}]();`);
}
} }
if (runtimeRequirements.has(RuntimeGlobals.startup)) { return `${RuntimeGlobals.getFullHash} ? ${RuntimeGlobals.getFullHash}() : ${hash}`;
buf.push( },
Template.asString([ "MainTemplate.renderCurrentHashCode is deprecated (use RuntimeGlobals.getFullHash runtime function instead)",
"// the startup function", "DEP_WEBPACK_MAIN_TEMPLATE_RENDER_CURRENT_HASH_CODE"
`${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction( );
"",
buf2 this.getPublicPath = util.deprecate(
)};` /**
]) *
); * @param {object} options get public path options
startup.push("// run startup"); * @returns {string} hook call
startup.push(`return ${RuntimeGlobals.startup}();`); */ options => {
} else { return compilation.getAssetPath(
startup.push( compilation.outputOptions.publicPath,
Template.asString(["// startup", Template.asString(buf2)]) options
);
}
} else if (runtimeRequirements.has(RuntimeGlobals.startup)) {
buf.push(
Template.asString([
"// the startup function",
"// It's empty as no entry modules are in this chunk",
`${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction(
"",
""
)}`
])
); );
} },
} else if (runtimeRequirements.has(RuntimeGlobals.startup)) { "MainTemplate.getPublicPath is depreacted (use Compilation.getAssetPath(compilation.outputOptions.publicPath, options) instead)",
startup.push("// run startup"); "DEP_WEBPACK_MAIN_TEMPLATE_GET_PUBLIC_PATH"
startup.push(`return ${RuntimeGlobals.startup}();`);
}
return result;
}
/**
* @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render
* @param {MainRenderContext} renderContext options object
* @returns {Source} the newly generated source from rendering
*/
render(moduleTemplate, renderContext) {
const { hash, chunk, chunkGraph, runtimeTemplate } = renderContext;
let source = new ConcatSource();
if (runtimeTemplate.supportsConst()) {
source.add("/******/ (() => { // webpackBootstrap\n");
} else {
source.add("/******/ (function() { // webpackBootstrap\n");
}
source.add("/******/ \tvar __webpack_modules__ = (");
source.add(
Template.renderChunkModules(
renderContext,
m => m.getSourceTypes().has("javascript"),
moduleTemplate,
"/******/ \t"
)
);
source.add(");\n");
const bootstrap = this.renderBootstrap(renderContext);
source.add(
"/************************************************************************/\n"
);
source.add(
new PrefixSource(
"/******/",
new OriginalSource(
Template.prefix(bootstrap.header, " \t") + "\n",
"webpack/bootstrap"
)
)
); );
const runtimeModules = renderContext.chunkGraph.getChunkRuntimeModulesInOrder( this.getAssetPath = util.deprecate(
chunk (path, options) => {
return compilation.getAssetPath(path, options);
},
"MainTemplate.getAssetPath is deprecated (use Compilation.getAssetPath instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_GET_ASSET_PATH"
); );
if (runtimeModules.length > 0) { this.getAssetPathWithInfo = util.deprecate(
source.add( (path, options) => {
"/************************************************************************/\n" return compilation.getAssetPathWithInfo(path, options);
); },
source.add( "MainTemplate.getAssetPathWithInfo is deprecated (use Compilation.getAssetPath instead)",
Template.renderMainRuntimeModules(runtimeModules, renderContext) "DEP_WEBPACK_MAIN_TEMPLATE_GET_ASSET_PATH_WITH_INFO"
);
}
source.add(
"/************************************************************************/\n"
);
source.add(
new PrefixSource(
"/******/",
new OriginalSource(
Template.prefix(bootstrap.startup, " \t") + "\n",
"webpack/startup"
)
)
);
source.add("/******/ })()\n");
/** @type {Source} */
let finalSource = source;
if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
finalSource = this.hooks.renderWithEntry.call(finalSource, chunk, hash);
}
if (!finalSource) {
throw new Error(
"Compiler error: MainTemplate plugin 'render' should return something"
);
}
chunk.rendered = true;
return new ConcatSource(finalSource, ";");
}
/**
*
* @param {object} options get public path options
* @returns {string} hook call
*/
getPublicPath(options) {
return this.hooks.assetPath.call(
this.outputOptions.publicPath || "",
options,
undefined
); );
} }
}
getAssetPath(path, options) { Object.defineProperty(MainTemplate.prototype, "requireFn", {
return this.hooks.assetPath.call(path, options, undefined); get: util.deprecate(
} () => "__webpack_require__",
'MainTemplate.requireFn is deprecated (use "__webpack_require__")',
"DEP_WEBPACK_MAIN_TEMPLATE_REQUIRE_FN"
)
});
getAssetPathWithInfo(path, options) { Object.defineProperty(MainTemplate.prototype, "outputOptions", {
const assetInfo = {}; get: util.deprecate(
// TODO webpack 5: refactor assetPath hook to receive { path, info } object /**
const newPath = this.hooks.assetPath.call(path, options, assetInfo); * @this {MainTemplate}
return { path: newPath, info: assetInfo }; * @returns {TODO} output options
} */
function() {
return this._outputOptions;
},
"MainTemplate.outputOptions is deprecated (use Compilation.outputOptions instead)",
"DEP_WEBPACK_MAIN_TEMPLATE_OUTPUT_OPTIONS"
)
});
/** module.exports = MainTemplate;
* Updates hash with information from this template
* @param {Hash} hash the hash to update
* @returns {void}
*/
updateHash(hash) {
hash.update("maintemplate");
hash.update("3");
this.hooks.hash.call(hash);
}
/**
* Updates hash with chunk-specific information from this template
* @param {Hash} hash the hash to update
* @param {Chunk} chunk the chunk
* @param {UpdateHashForChunkContext} context options object
* @returns {void}
*/
updateHashForChunk(hash, chunk, context) {
this.updateHash(hash);
this.hooks.hashForChunk.call(hash, chunk);
const bootstrap = this.renderBootstrap({
hash: "0000",
chunk,
chunkGraph: context.chunkGraph,
moduleGraph: context.moduleGraph,
runtimeTemplate: context.runtimeTemplate
});
for (const key of Object.keys(bootstrap)) {
hash.update(key);
for (const line of bootstrap[key]) {
hash.update(line);
}
}
}
};

View File

@ -6,9 +6,10 @@
"use strict"; "use strict";
const { ConcatSource } = require("webpack-sources"); const { ConcatSource } = require("webpack-sources");
const RuntimeGlobals = require("./RuntimeGlobals"); const JavascriptModulesPlugin = require("./JavascriptModulesPlugin");
const Template = require("./Template"); const Template = require("./Template");
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */ /** @typedef {import("./ModuleTemplate")} ModuleTemplate */
const joinIterableWithComma = iterable => { const joinIterableWithComma = iterable => {
@ -53,66 +54,24 @@ const printExportsInfoToSource = (source, indent, exportsInfo) => {
} }
}; };
class FunctionModuleTemplatePlugin { class ModuleInfoHeaderPlugin {
constructor({ compilation }) {
this.compilation = compilation;
}
/** /**
* @param {ModuleTemplate} moduleTemplate a module template * @param {Compiler} compiler the compiler
* @returns {void} * @returns {void}
*/ */
apply(moduleTemplate) { apply(compiler) {
const arrow = this.compilation.runtimeTemplate.supportsArrowFunction(); compiler.hooks.compilation.tap("ModuleInfoHeaderPlugin", compilation => {
moduleTemplate.hooks.render.tap( const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
"FunctionModuleTemplatePlugin", hooks.renderModulePackage.tap(
(moduleSource, module) => { "ModuleInfoHeaderPlugin",
const { chunkGraph } = this.compilation; (
const source = new ConcatSource(); moduleSource,
const args = []; module,
const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements( { chunkGraph, moduleGraph, runtimeTemplate }
module ) => {
);
const needModule = runtimeRequirements.has(RuntimeGlobals.module);
const needExports = runtimeRequirements.has(RuntimeGlobals.exports);
const needRequire =
runtimeRequirements.has(RuntimeGlobals.require) ||
runtimeRequirements.has(RuntimeGlobals.requireScope);
const needThisAsExports = runtimeRequirements.has(
RuntimeGlobals.thisAsExports
);
if (needExports || needRequire || needModule)
args.push(
needModule
? module.moduleArgument
: "__unused" + module.moduleArgument
);
if (needExports || needRequire)
args.push(
needExports
? module.exportsArgument
: "__unused" + module.exportsArgument
);
if (needRequire) args.push("__webpack_require__");
if (arrow && !needThisAsExports) {
source.add("/***/ ((" + args.join(", ") + ") => {\n\n");
} else {
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
}
if (module.buildInfo.strict) source.add('"use strict";\n');
source.add(moduleSource);
source.add("\n\n/***/ })");
return source;
}
);
moduleTemplate.hooks.package.tap(
"FunctionModuleTemplatePlugin",
(moduleSource, module, { moduleGraph, chunkGraph }) => {
if (moduleTemplate.runtimeTemplate.outputOptions.pathinfo) {
const source = new ConcatSource(); const source = new ConcatSource();
const req = module.readableIdentifier( const req = module.readableIdentifier(
moduleTemplate.runtimeTemplate.requestShortener runtimeTemplate.requestShortener
); );
const reqStr = req.replace(/\*\//g, "*_/"); const reqStr = req.replace(/\*\//g, "*_/");
const reqStrStar = "*".repeat(reqStr.length); const reqStrStar = "*".repeat(reqStr.length);
@ -135,7 +94,7 @@ class FunctionModuleTemplatePlugin {
for (const text of optimizationBailout) { for (const text of optimizationBailout) {
let code; let code;
if (typeof text === "function") { if (typeof text === "function") {
code = text(moduleTemplate.runtimeTemplate.requestShortener); code = text(runtimeTemplate.requestShortener);
} else { } else {
code = text; code = text;
} }
@ -145,14 +104,12 @@ class FunctionModuleTemplatePlugin {
source.add(moduleSource); source.add(moduleSource);
return source; return source;
} }
return moduleSource; );
} hooks.chunkHash.tap("ModuleInfoHeaderPlugin", (chunk, hash) => {
); hash.update("ModuleInfoHeaderPlugin");
hash.update("1");
moduleTemplate.hooks.hash.tap("FunctionModuleTemplatePlugin", hash => { });
hash.update("FunctionModuleTemplatePlugin");
hash.update("2");
}); });
} }
} }
module.exports = FunctionModuleTemplatePlugin; module.exports = ModuleInfoHeaderPlugin;

View File

@ -5,17 +5,23 @@
"use strict"; "use strict";
const { SyncWaterfallHook, SyncHook } = require("tapable"); const util = require("util");
const memorize = require("./util/memorize");
/** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./ChunkGraph")} ChunkGraph */ /** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */ /** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module")} Module */ /** @typedef {import("./Module")} Module */
/** @typedef {import("./ModuleGraph")} ModuleGraph */ /** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./util/Hash")} Hash */ /** @typedef {import("./util/Hash")} Hash */
const getJavascriptModulesPlugin = memorize(() =>
require("./JavascriptModulesPlugin")
);
/** /**
* @typedef {Object} RenderContext * @typedef {Object} RenderContext
* @property {Chunk} chunk the chunk * @property {Chunk} chunk the chunk
@ -25,77 +31,69 @@ const { SyncWaterfallHook, SyncHook } = require("tapable");
* @property {ChunkGraph} chunkGraph the chunk graph * @property {ChunkGraph} chunkGraph the chunk graph
*/ */
// TODO webpack 6: remove this class
module.exports = class ModuleTemplate { module.exports = class ModuleTemplate {
/** /**
* @param {RuntimeTemplate} runtimeTemplate the runtime template * @param {RuntimeTemplate} runtimeTemplate the runtime template
* @param {string} type the module template type * @param {Compilation} compilation the compilation
*/ */
constructor(runtimeTemplate, type) { constructor(runtimeTemplate, compilation) {
this.runtimeTemplate = runtimeTemplate; this.runtimeTemplate = runtimeTemplate;
this.type = type; this.type = "javascript";
this.hooks = Object.freeze({ this.hooks = Object.freeze({
/** @type {SyncWaterfallHook<[Source, Module, RenderContext]>} */ content: {
content: new SyncWaterfallHook(["source", "module", "context"]), tap: util.deprecate(
/** @type {SyncWaterfallHook<[Source, Module, RenderContext]>} */ (options, fn) => {
module: new SyncWaterfallHook(["source", "module", "context"]), getJavascriptModulesPlugin()
/** @type {SyncWaterfallHook<[Source, Module, RenderContext]>} */ .getCompilationHooks(compilation)
render: new SyncWaterfallHook(["source", "module", "context"]), .renderModuleContent.tap(options, fn);
/** @type {SyncWaterfallHook<[Source, Module, RenderContext]>} */ },
package: new SyncWaterfallHook(["source", "module", "context"]), "ModuleTemplate.hooks.content is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderModuleContent instead)",
/** @type {SyncHook<[Hash]>} */ "DEP_MODULE_TEMPLATE_CONTENT"
hash: new SyncHook(["hash"]) )
},
module: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.renderModuleContent.tap(options, fn);
},
"ModuleTemplate.hooks.module is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderModuleContent instead)",
"DEP_MODULE_TEMPLATE_MODULE"
)
},
render: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.renderModuleContainer.tap(options, fn);
},
"ModuleTemplate.hooks.render is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer instead)",
"DEP_MODULE_TEMPLATE_RENDER"
)
},
package: {
tap: util.deprecate(
(options, fn) => {
getJavascriptModulesPlugin()
.getCompilationHooks(compilation)
.renderModulePackage.tap(options, fn);
},
"ModuleTemplate.hooks.package is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderModulePackage instead)",
"DEP_MODULE_TEMPLATE_PACKAGE"
)
},
hash: {
tap: util.deprecate(
(options, fn) => {
compilation.hooks.fullHash.tap(options, fn);
},
"ModuleTemplate.hooks.package is deprecated (use Compilation.hooks.fullHash instead)",
"DEP_MODULE_TEMPLATE_HASH"
)
}
}); });
} }
/**
* @param {Module} module the module
* @param {RenderContext} ctx render ctx
* @returns {Source} the source
*/
render(module, ctx) {
try {
const {
runtimeTemplate,
dependencyTemplates,
moduleGraph,
chunkGraph
} = ctx;
const moduleSource = module.source({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type: this.type
});
const moduleSourcePostContent = this.hooks.content.call(
moduleSource,
module,
ctx
);
const moduleSourcePostModule = this.hooks.module.call(
moduleSourcePostContent,
module,
ctx
);
const moduleSourcePostRender = this.hooks.render.call(
moduleSourcePostModule,
module,
ctx
);
return this.hooks.package.call(moduleSourcePostRender, module, ctx);
} catch (e) {
e.message = `${module.identifier()}\n${e.message}`;
throw e;
}
}
/**
* Updates hash with information from this template
* @param {Hash} hash the hash to update
* @returns {void}
*/
updateHash(hash) {
hash.update("1");
this.hooks.hash.call(hash);
}
}; };

View File

@ -44,7 +44,7 @@ const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g;
* @property {string} hash * @property {string} hash
* @property {string} fullHash * @property {string} fullHash
* @property {TODO} outputOptions * @property {TODO} outputOptions
* @property {{asset: ModuleTemplate, javascript: ModuleTemplate, webassembly: ModuleTemplate}} moduleTemplates * @property {{javascript: ModuleTemplate}} moduleTemplates
* @property {DependencyTemplates} dependencyTemplates * @property {DependencyTemplates} dependencyTemplates
* @property {RuntimeTemplate} runtimeTemplate * @property {RuntimeTemplate} runtimeTemplate
* @property {ModuleGraph} moduleGraph * @property {ModuleGraph} moduleGraph
@ -226,14 +226,14 @@ class Template {
/** /**
* @param {RenderContext} renderContext render context * @param {RenderContext} renderContext render context
* @param {ModuleFilterPredicate} filterFn function used to filter modules from chunk to render * @param {ModuleFilterPredicate} filterFn function used to filter modules from chunk to render
* @param {ModuleTemplate} moduleTemplate ModuleTemplate instance used to render modules * @param {function(Module): Source} renderModule function to render a module
* @param {string=} prefix applying prefix strings * @param {string=} prefix applying prefix strings
* @returns {Source} rendered chunk modules in a Source object * @returns {Source} rendered chunk modules in a Source object
*/ */
static renderChunkModules( static renderChunkModules(
renderContext, renderContext,
filterFn, filterFn,
moduleTemplate, renderModule,
prefix = "" prefix = ""
) { ) {
const { chunk, chunkGraph } = renderContext; const { chunk, chunkGraph } = renderContext;
@ -256,7 +256,7 @@ class Template {
const allModules = modules.map(module => { const allModules = modules.map(module => {
return { return {
id: chunkGraph.getModuleId(module), id: chunkGraph.getModuleId(module),
source: moduleTemplate.render(module, renderContext) source: renderModule(module)
}; };
}); });
if (removedModules && removedModules.length > 0) { if (removedModules && removedModules.length > 0) {

View File

@ -12,8 +12,8 @@ const JsonModulesPlugin = require("./JsonModulesPlugin");
const EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin"); const EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin");
const EvalSourceMapDevToolPlugin = require("./EvalSourceMapDevToolPlugin"); const EvalSourceMapDevToolPlugin = require("./EvalSourceMapDevToolPlugin");
const FunctionModulePlugin = require("./FunctionModulePlugin");
const LoaderTargetPlugin = require("./LoaderTargetPlugin"); const LoaderTargetPlugin = require("./LoaderTargetPlugin");
const ModuleInfoHeaderPlugin = require("./ModuleInfoHeaderPlugin");
const SourceMapDevToolPlugin = require("./SourceMapDevToolPlugin"); const SourceMapDevToolPlugin = require("./SourceMapDevToolPlugin");
const EntryOptionPlugin = require("./EntryOptionPlugin"); const EntryOptionPlugin = require("./EntryOptionPlugin");
@ -81,7 +81,6 @@ class WebpackOptionsApply extends OptionsApply {
mangleImports: options.optimization.mangleWasmImports mangleImports: options.optimization.mangleWasmImports
}).apply(compiler); }).apply(compiler);
new FetchCompileAsyncWasmPlugin().apply(compiler); new FetchCompileAsyncWasmPlugin().apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeSourcePlugin(options.node).apply(compiler); new NodeSourcePlugin(options.node).apply(compiler);
new LoaderTargetPlugin(options.target).apply(compiler); new LoaderTargetPlugin(options.target).apply(compiler);
break; break;
@ -97,7 +96,6 @@ class WebpackOptionsApply extends OptionsApply {
mangleImports: options.optimization.mangleWasmImports mangleImports: options.optimization.mangleWasmImports
}).apply(compiler); }).apply(compiler);
new FetchCompileAsyncWasmPlugin().apply(compiler); new FetchCompileAsyncWasmPlugin().apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeSourcePlugin(options.node).apply(compiler); new NodeSourcePlugin(options.node).apply(compiler);
new LoaderTargetPlugin(options.target).apply(compiler); new LoaderTargetPlugin(options.target).apply(compiler);
new StartupChunkDependenciesPlugin({ new StartupChunkDependenciesPlugin({
@ -119,7 +117,6 @@ class WebpackOptionsApply extends OptionsApply {
mangleImports: options.optimization.mangleWasmImports mangleImports: options.optimization.mangleWasmImports
}).apply(compiler); }).apply(compiler);
new ReadFileCompileAsyncWasmPlugin().apply(compiler); new ReadFileCompileAsyncWasmPlugin().apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeTargetPlugin().apply(compiler); new NodeTargetPlugin().apply(compiler);
new LoaderTargetPlugin("node").apply(compiler); new LoaderTargetPlugin("node").apply(compiler);
new StartupChunkDependenciesPlugin({ new StartupChunkDependenciesPlugin({
@ -133,7 +130,6 @@ class WebpackOptionsApply extends OptionsApply {
const ExternalsPlugin = require("./ExternalsPlugin"); const ExternalsPlugin = require("./ExternalsPlugin");
const StartupChunkDependenciesPlugin = require("./runtime/StartupChunkDependenciesPlugin"); const StartupChunkDependenciesPlugin = require("./runtime/StartupChunkDependenciesPlugin");
new JsonpTemplatePlugin().apply(compiler); new JsonpTemplatePlugin().apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeTargetPlugin().apply(compiler); new NodeTargetPlugin().apply(compiler);
new ExternalsPlugin("commonjs", "nw.gui").apply(compiler); new ExternalsPlugin("commonjs", "nw.gui").apply(compiler);
new LoaderTargetPlugin(options.target).apply(compiler); new LoaderTargetPlugin(options.target).apply(compiler);
@ -150,7 +146,6 @@ class WebpackOptionsApply extends OptionsApply {
new NodeTemplatePlugin({ new NodeTemplatePlugin({
asyncChunkLoading: true asyncChunkLoading: true
}).apply(compiler); }).apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeTargetPlugin().apply(compiler); new NodeTargetPlugin().apply(compiler);
new ExternalsPlugin("commonjs", [ new ExternalsPlugin("commonjs", [
"app", "app",
@ -202,7 +197,6 @@ class WebpackOptionsApply extends OptionsApply {
mangleImports: options.optimization.mangleWasmImports mangleImports: options.optimization.mangleWasmImports
}).apply(compiler); }).apply(compiler);
new FetchCompileAsyncWasmPlugin().apply(compiler); new FetchCompileAsyncWasmPlugin().apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeTargetPlugin().apply(compiler); new NodeTargetPlugin().apply(compiler);
new ExternalsPlugin("commonjs", [ new ExternalsPlugin("commonjs", [
"clipboard", "clipboard",
@ -250,6 +244,10 @@ class WebpackOptionsApply extends OptionsApply {
).apply(compiler); ).apply(compiler);
} }
if (options.output.pathinfo) {
new ModuleInfoHeaderPlugin().apply(compiler);
}
if ( if (
options.devtool && options.devtool &&
(options.devtool.includes("sourcemap") || (options.devtool.includes("sourcemap") ||

View File

@ -17,8 +17,6 @@ const AssetParser = require("./AssetParser");
/** @typedef {import("../Compiler")} Compiler */ /** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../MainTemplate")} MainTemplate */ /** @typedef {import("../MainTemplate")} MainTemplate */
/** @typedef {import("../Module")} Module */ /** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleTemplate")} ModuleTemplate */
/** @typedef {import("../ModuleTemplate").RenderContext} RenderContext */
const type = "asset"; const type = "asset";
const plugin = "AssetModulesPlugin"; const plugin = "AssetModulesPlugin";
@ -47,12 +45,7 @@ class AssetModulesPlugin {
plugin, plugin,
(result, options) => { (result, options) => {
const { chunkGraph, moduleGraph } = compilation; const { chunkGraph, moduleGraph } = compilation;
const { const { chunk, dependencyTemplates, runtimeTemplate } = options;
chunk,
moduleTemplates,
dependencyTemplates,
runtimeTemplate
} = options;
const { outputOptions } = runtimeTemplate; const { outputOptions } = runtimeTemplate;
@ -66,12 +59,12 @@ class AssetModulesPlugin {
result.push({ result.push({
render: () => render: () =>
this.renderAsset(module, moduleTemplates.asset, { module.source({
chunk,
chunkGraph,
moduleGraph,
dependencyTemplates, dependencyTemplates,
runtimeTemplate runtimeTemplate,
moduleGraph,
chunkGraph,
type
}), }),
filenameTemplate, filenameTemplate,
pathOptions: { pathOptions: {
@ -92,17 +85,6 @@ class AssetModulesPlugin {
} }
); );
} }
/**
* @param {Module} module the module to render
* @param {ModuleTemplate} moduleTemplate the module template
* @param {RenderContext} renderContext the render context
* @returns {Source} the rendered source
*/
/* eslint-enable */
renderAsset(module, moduleTemplate, renderContext) {
return moduleTemplate.render(module, renderContext);
}
} }
module.exports = AssetModulesPlugin; module.exports = AssetModulesPlugin;

View File

@ -206,7 +206,7 @@ class ProfilingPlugin {
"Context Module Factory" "Context Module Factory"
); );
interceptAllParserHooks(normalModuleFactory, tracer); interceptAllParserHooks(normalModuleFactory, tracer);
interceptTemplateInstancesFrom(compilation, tracer); interceptAllJavascriptModulesPluginHooks(compilation, tracer);
} }
); );
@ -276,37 +276,6 @@ class ProfilingPlugin {
} }
} }
const interceptTemplateInstancesFrom = (compilation, tracer) => {
const { mainTemplate, chunkTemplate, moduleTemplates } = compilation;
const { javascript, webassembly } = moduleTemplates;
[
{
instance: mainTemplate,
name: "MainTemplate"
},
{
instance: chunkTemplate,
name: "ChunkTemplate"
},
{
instance: javascript,
name: "JavaScriptModuleTemplate"
},
{
instance: webassembly,
name: "WebAssemblyModuleTemplate"
}
].forEach(templateObject => {
Object.keys(templateObject.instance.hooks).forEach(hookName => {
templateObject.instance.hooks[hookName].intercept(
makeInterceptorFor(templateObject.name, tracer)(hookName)
);
});
});
};
const interceptAllHooksFor = (instance, tracer, logLabel) => { const interceptAllHooksFor = (instance, tracer, logLabel) => {
if (Reflect.has(instance, "hooks")) { if (Reflect.has(instance, "hooks")) {
Object.keys(instance.hooks).forEach(hookName => { Object.keys(instance.hooks).forEach(hookName => {
@ -336,6 +305,18 @@ const interceptAllParserHooks = (moduleFactory, tracer) => {
}); });
}; };
const interceptAllJavascriptModulesPluginHooks = (compilation, tracer) => {
interceptAllHooksFor(
{
hooks: require("../JavascriptModulesPlugin").getCompilationHooks(
compilation
)
},
tracer,
"JavascriptModulesPlugin"
);
};
const makeInterceptorFor = (instance, tracer) => hookName => ({ const makeInterceptorFor = (instance, tracer) => hookName => ({
register: ({ name, type, context, fn }) => { register: ({ name, type, context, fn }) => {
const newFn = makeNewProfiledTapFn(hookName, tracer, { const newFn = makeNewProfiledTapFn(hookName, tracer, {

View File

@ -4,8 +4,16 @@
"use strict"; "use strict";
/** @template T @typedef {function(): T} FunctionReturning */
/**
* @template T
* @param {FunctionReturning<T>} fn memorized function
* @returns {FunctionReturning<T>} new function
*/
const memorize = fn => { const memorize = fn => {
let memorized = false; let memorized = false;
/** @type {T} */
let result = undefined; let result = undefined;
return () => { return () => {
if (memorized) { if (memorized) {

View File

@ -5,18 +5,65 @@
"use strict"; "use strict";
const { SyncWaterfallHook } = require("tapable");
const Compilation = require("../Compilation");
const Generator = require("../Generator"); const Generator = require("../Generator");
const { tryRunOrWebpackError } = require("../HookWebpackError");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
const { compareModulesById } = require("../util/comparators"); const { compareModulesById } = require("../util/comparators");
const AsyncWebAssemblyGenerator = require("./AsyncWebAssemblyGenerator"); const AsyncWebAssemblyGenerator = require("./AsyncWebAssemblyGenerator");
const AsyncWebAssemblyJavascriptGenerator = require("./AsyncWebAssemblyJavascriptGenerator"); const AsyncWebAssemblyJavascriptGenerator = require("./AsyncWebAssemblyJavascriptGenerator");
const AsyncWebAssemblyParser = require("./AsyncWebAssemblyParser"); const AsyncWebAssemblyParser = require("./AsyncWebAssemblyParser");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../Compiler")} Compiler */ /** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions} */ /** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions} */
/** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry} */ /** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry} */
/**
* @typedef {Object} RenderContext
* @property {Chunk} chunk the chunk
* @property {DependencyTemplates} dependencyTemplates the dependency templates
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
*/
/**
* @typedef {Object} CompilationHooks
* @property {SyncWaterfallHook<[Source, Module, RenderContext]>} renderModuleContent
*/
/** @type {WeakMap<Compilation, CompilationHooks>} */
const compilationHooksMap = new WeakMap();
class AsyncWebAssemblyModulesPlugin { class AsyncWebAssemblyModulesPlugin {
/**
* @param {Compilation} compilation the compilation
* @returns {CompilationHooks} the attached hooks
*/
static getCompilationHooks(compilation) {
if (!(compilation instanceof Compilation)) {
throw new TypeError(
"The 'compilation' argument must be an instance of JavascriptParser"
);
}
let hooks = compilationHooksMap.get(compilation);
if (hooks === undefined) {
hooks = {
renderModuleContent: new SyncWaterfallHook([
"source",
"module",
"renderContext"
])
};
compilationHooksMap.set(compilation, hooks);
}
return hooks;
}
constructor(options) { constructor(options) {
this.options = options; this.options = options;
} }
@ -29,6 +76,9 @@ class AsyncWebAssemblyModulesPlugin {
compiler.hooks.compilation.tap( compiler.hooks.compilation.tap(
"AsyncWebAssemblyModulesPlugin", "AsyncWebAssemblyModulesPlugin",
(compilation, { normalModuleFactory }) => { (compilation, { normalModuleFactory }) => {
const hooks = AsyncWebAssemblyModulesPlugin.getCompilationHooks(
compilation
);
compilation.dependencyFactories.set( compilation.dependencyFactories.set(
WebAssemblyImportDependency, WebAssemblyImportDependency,
normalModuleFactory normalModuleFactory
@ -50,62 +100,81 @@ class AsyncWebAssemblyModulesPlugin {
}); });
}); });
/** compilation.hooks.renderManifest.tap(
* "WebAssemblyModulesPlugin",
* @param {RenderManifestEntry[]} result render entries (result, options) => {
* @param {RenderManifestOptions} options context options const { moduleGraph, chunkGraph, runtimeTemplate } = compilation;
* @returns {RenderManifestEntry[]} render entries const chunk = options.chunk;
*/ const outputOptions = options.outputOptions;
const handler = (result, options) => { const dependencyTemplates = options.dependencyTemplates;
const { moduleGraph, chunkGraph, runtimeTemplate } = compilation;
const chunk = options.chunk;
const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates;
for (const module of chunkGraph.getOrderedChunkModulesIterable( for (const module of chunkGraph.getOrderedChunkModulesIterable(
chunk, chunk,
compareModulesById(chunkGraph) compareModulesById(chunkGraph)
)) { )) {
if (module.type === "webassembly/async") { if (module.type === "webassembly/async") {
const filenameTemplate = outputOptions.webassemblyModuleFilename; const filenameTemplate =
outputOptions.webassemblyModuleFilename;
result.push({ result.push({
render: () => render: () =>
moduleTemplates.webassembly.render(module, { this.renderModule(
chunk, module,
dependencyTemplates, {
runtimeTemplate, chunk,
moduleGraph, dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
},
hooks
),
filenameTemplate,
pathOptions: {
module,
chunkGraph chunkGraph
}), },
filenameTemplate, auxiliary: true,
pathOptions: { identifier: `webassemblyAsyncModule${chunkGraph.getModuleId(
module, module
chunkGraph )}`,
}, hash: chunkGraph.getModuleHash(module)
auxiliary: true, });
identifier: `webassemblyAsyncModule${chunkGraph.getModuleId( }
module
)}`,
hash: chunkGraph.getModuleHash(module)
});
} }
}
return result; return result;
}; }
compilation.chunkTemplate.hooks.renderManifest.tap(
"WebAssemblyModulesPlugin",
handler
);
compilation.mainTemplate.hooks.renderManifest.tap(
"WebAssemblyModulesPlugin",
handler
); );
} }
); );
} }
renderModule(module, renderContext, hooks) {
const {
chunkGraph,
moduleGraph,
runtimeTemplate,
dependencyTemplates
} = renderContext;
try {
const moduleSource = module.source({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type: "webassembly"
});
return tryRunOrWebpackError(
() =>
hooks.renderModuleContent.call(moduleSource, module, renderContext),
"AsyncWebAssemblyModulesPlugin.getCompilationHooks().renderModuleContent"
);
} catch (e) {
e.module = module;
throw e;
}
}
} }
module.exports = AsyncWebAssemblyModulesPlugin; module.exports = AsyncWebAssemblyModulesPlugin;

View File

@ -64,7 +64,6 @@ class WebAssemblyModulesPlugin {
const { moduleGraph, chunkGraph, runtimeTemplate } = compilation; const { moduleGraph, chunkGraph, runtimeTemplate } = compilation;
const chunk = options.chunk; const chunk = options.chunk;
const outputOptions = options.outputOptions; const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates; const dependencyTemplates = options.dependencyTemplates;
for (const module of chunkGraph.getOrderedChunkModulesIterable( for (const module of chunkGraph.getOrderedChunkModulesIterable(
@ -77,17 +76,12 @@ class WebAssemblyModulesPlugin {
result.push({ result.push({
render: () => render: () =>
this.renderWebAssembly( module.source({
module, dependencyTemplates,
moduleTemplates.webassembly, runtimeTemplate,
{ moduleGraph,
chunk, chunkGraph
dependencyTemplates, }),
runtimeTemplate,
moduleGraph,
chunkGraph
}
),
filenameTemplate, filenameTemplate,
pathOptions: { pathOptions: {
module, module,
@ -132,17 +126,6 @@ class WebAssemblyModulesPlugin {
} }
); );
} }
/**
*
* @param {Module} module the wasm module
* @param {ModuleTemplate} moduleTemplate the module tempalte
* @param {RenderContext} renderContext render context
* @returns {Source} rendered source
*/
renderWebAssembly(module, moduleTemplate, renderContext) {
return moduleTemplate.render(module, renderContext);
}
} }
module.exports = WebAssemblyModulesPlugin; module.exports = WebAssemblyModulesPlugin;

View File

@ -1294,7 +1294,7 @@
}, },
{ {
"instanceof": "Function", "instanceof": "Function",
"tsType": "Function" "tsType": "((pathData: import(\"../lib/Compilation\").PathData, assetInfo?: import(\"../lib/Compilation\").AssetInfo) => string)"
} }
] ]
}, },

View File

@ -160,7 +160,10 @@ describe("StatsTestCases", () => {
const testPath = path.join(base, testName); const testPath = path.join(base, testName);
actual = actual actual = actual
.replace(/\r\n?/g, "\n") .replace(/\r\n?/g, "\n")
.replace(/\(.+\) DeprecationWarning.+(\n\s+at .*)*\n?/g, "") .replace(
/\([^)]+\) (\[[^\]]+\]\s*)?DeprecationWarning.+(\n\s+at .*)*\n?/g,
""
)
.replace(/[\t ]*Version:.+\n/g, "") .replace(/[\t ]*Version:.+\n/g, "")
.replace(new RegExp(quotemeta(testPath), "g"), "Xdir/" + testName) .replace(new RegExp(quotemeta(testPath), "g"), "Xdir/" + testName)
.replace(/(\w)\\(\w)/g, "$1/$2") .replace(/(\w)\\(\w)/g, "$1/$2")

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ it("should include only one use strict per module", function() {
expect(matches).toEqual([ expect(matches).toEqual([
'/* unused harmony default export */ var _unused_webpack_default_export = ("a");', '/* unused harmony default export */ var _unused_webpack_default_export = ("a");',
"/******/", "/******/ // Check if module is in cache",
"__webpack_require__.r(__webpack_exports__);", "__webpack_require__.r(__webpack_exports__);",
"__webpack_require__.r(__webpack_exports__);", "__webpack_require__.r(__webpack_exports__);",
"__webpack_require__.r(__webpack_exports__);", "__webpack_require__.r(__webpack_exports__);",

View File

@ -1,6 +1,7 @@
const { CachedSource } = require("webpack-sources"); const { CachedSource } = require("webpack-sources");
const AsyncWebAssemblyModulesPlugin = require("../../../../lib/wasm-async/AsyncWebAssemblyModulesPlugin");
/** @typedef {import("../../../lib/Compilation")} Compilation */ /** @typedef {import("../../../../lib/Compilation")} Compilation */
module.exports = { module.exports = {
module: { module: {
@ -25,13 +26,12 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
compilation => { compilation => {
compilation.moduleTemplates.webassembly.hooks.package.tap( AsyncWebAssemblyModulesPlugin.getCompilationHooks(
"Test", compilation
source => { ).renderModuleContent.tap("Test", source => {
// this is important to make each returned value a new instance // this is important to make each returned value a new instance
return new CachedSource(source); return new CachedSource(source);
} });
);
} }
); );
} }

View File

@ -1,5 +1,4 @@
const NodeTemplatePlugin = require("../../../../lib/node/NodeTemplatePlugin"); const NodeTemplatePlugin = require("../../../../lib/node/NodeTemplatePlugin");
const FunctionModulePlugin = require("../../../../lib/FunctionModulePlugin");
const SingleEntryPlugin = require("../../../../lib/SingleEntryPlugin"); const SingleEntryPlugin = require("../../../../lib/SingleEntryPlugin");
const compilerCache = new WeakMap(); const compilerCache = new WeakMap();
@ -14,7 +13,6 @@ module.exports = function(source) {
}, },
[ [
new NodeTemplatePlugin(), new NodeTemplatePlugin(),
new FunctionModulePlugin(),
new SingleEntryPlugin(this.context, this.resource) new SingleEntryPlugin(this.context, this.resource)
] ]
); );