2017-11-10 18:02:24 +08:00
|
|
|
/*
|
|
|
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
|
|
|
Author Tobias Koppers @sokra
|
|
|
|
|
*/
|
2018-07-30 23:08:51 +08:00
|
|
|
|
2017-11-10 18:02:24 +08:00
|
|
|
"use strict";
|
|
|
|
|
|
2018-03-22 19:05:58 +08:00
|
|
|
const { ConcatSource } = require("webpack-sources");
|
2018-11-28 20:07:40 +08:00
|
|
|
const HotUpdateChunk = require("./HotUpdateChunk");
|
2018-01-24 06:09:26 +08:00
|
|
|
const JavascriptGenerator = require("./JavascriptGenerator");
|
2018-07-30 23:08:51 +08:00
|
|
|
const JavascriptParser = require("./JavascriptParser");
|
|
|
|
|
const Template = require("./Template");
|
2018-08-14 17:18:22 +08:00
|
|
|
const { compareModulesById } = require("./util/comparators");
|
2018-03-23 02:52:11 +08:00
|
|
|
const createHash = require("./util/createHash");
|
2017-11-10 18:02:24 +08:00
|
|
|
|
2018-07-24 23:35:36 +08:00
|
|
|
/** @typedef {import("webpack-sources").Source} Source */
|
2018-08-23 22:54:02 +08:00
|
|
|
/** @typedef {import("./Chunk")} Chunk */
|
2018-07-24 23:35:36 +08:00
|
|
|
/** @typedef {import("./ChunkTemplate")} ChunkTemplate */
|
2018-12-03 22:00:32 +08:00
|
|
|
/** @typedef {import("./Compilation")} Compilation */
|
2018-07-24 23:35:36 +08:00
|
|
|
/** @typedef {import("./Compiler")} Compiler */
|
2018-08-23 22:54:02 +08:00
|
|
|
/** @typedef {import("./Module")} Module */
|
2018-07-24 23:35:36 +08:00
|
|
|
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
|
|
|
|
|
/** @typedef {import("./ModuleTemplate").RenderContext} RenderContext */
|
|
|
|
|
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
|
|
|
|
|
2017-11-10 18:02:24 +08:00
|
|
|
class JavascriptModulesPlugin {
|
2018-07-24 23:35:36 +08:00
|
|
|
/**
|
|
|
|
|
* @param {Compiler} compiler webpack compiler
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
2017-11-10 18:02:24 +08:00
|
|
|
apply(compiler) {
|
2018-02-25 09:00:20 +08:00
|
|
|
compiler.hooks.compilation.tap(
|
|
|
|
|
"JavascriptModulesPlugin",
|
|
|
|
|
(compilation, { normalModuleFactory }) => {
|
2018-08-16 22:11:20 +08:00
|
|
|
const moduleGraph = compilation.moduleGraph;
|
2018-02-25 09:00:20 +08:00
|
|
|
normalModuleFactory.hooks.createParser
|
|
|
|
|
.for("javascript/auto")
|
|
|
|
|
.tap("JavascriptModulesPlugin", options => {
|
2018-07-03 16:15:48 +08:00
|
|
|
return new JavascriptParser(options, "auto");
|
2018-02-25 09:00:20 +08:00
|
|
|
});
|
|
|
|
|
normalModuleFactory.hooks.createParser
|
|
|
|
|
.for("javascript/dynamic")
|
|
|
|
|
.tap("JavascriptModulesPlugin", options => {
|
2018-07-03 16:15:48 +08:00
|
|
|
return new JavascriptParser(options, "script");
|
2018-02-25 09:00:20 +08:00
|
|
|
});
|
|
|
|
|
normalModuleFactory.hooks.createParser
|
|
|
|
|
.for("javascript/esm")
|
|
|
|
|
.tap("JavascriptModulesPlugin", options => {
|
2018-07-03 16:15:48 +08:00
|
|
|
return new JavascriptParser(options, "module");
|
2018-02-25 09:00:20 +08:00
|
|
|
});
|
|
|
|
|
normalModuleFactory.hooks.createGenerator
|
|
|
|
|
.for("javascript/auto")
|
2018-03-28 11:16:12 +08:00
|
|
|
.tap("JavascriptModulesPlugin", () => {
|
|
|
|
|
return new JavascriptGenerator();
|
2018-02-25 09:00:20 +08:00
|
|
|
});
|
|
|
|
|
normalModuleFactory.hooks.createGenerator
|
|
|
|
|
.for("javascript/dynamic")
|
2018-03-28 11:16:12 +08:00
|
|
|
.tap("JavascriptModulesPlugin", () => {
|
|
|
|
|
return new JavascriptGenerator();
|
2018-02-25 09:00:20 +08:00
|
|
|
});
|
|
|
|
|
normalModuleFactory.hooks.createGenerator
|
|
|
|
|
.for("javascript/esm")
|
2018-03-28 11:16:12 +08:00
|
|
|
.tap("JavascriptModulesPlugin", () => {
|
|
|
|
|
return new JavascriptGenerator();
|
2018-02-25 09:00:20 +08:00
|
|
|
});
|
|
|
|
|
compilation.mainTemplate.hooks.renderManifest.tap(
|
|
|
|
|
"JavascriptModulesPlugin",
|
|
|
|
|
(result, options) => {
|
|
|
|
|
const chunk = options.chunk;
|
|
|
|
|
const hash = options.hash;
|
|
|
|
|
const outputOptions = options.outputOptions;
|
|
|
|
|
const moduleTemplates = options.moduleTemplates;
|
|
|
|
|
const dependencyTemplates = options.dependencyTemplates;
|
2018-01-24 16:39:49 +08:00
|
|
|
|
2018-05-29 20:50:40 +08:00
|
|
|
const filenameTemplate =
|
|
|
|
|
chunk.filenameTemplate || outputOptions.filename;
|
2018-01-24 16:39:49 +08:00
|
|
|
|
2018-02-25 09:00:20 +08:00
|
|
|
result.push({
|
|
|
|
|
render: () =>
|
2018-08-14 22:40:37 +08:00
|
|
|
compilation.mainTemplate.render(moduleTemplates.javascript, {
|
2018-02-25 09:00:20 +08:00
|
|
|
hash,
|
|
|
|
|
chunk,
|
2018-08-14 22:40:37 +08:00
|
|
|
dependencyTemplates,
|
|
|
|
|
runtimeTemplate: options.runtimeTemplate,
|
|
|
|
|
moduleGraph: options.moduleGraph,
|
|
|
|
|
chunkGraph: options.chunkGraph
|
|
|
|
|
}),
|
2018-02-25 09:00:20 +08:00
|
|
|
filenameTemplate,
|
|
|
|
|
pathOptions: {
|
2018-09-28 19:10:37 +08:00
|
|
|
chunk,
|
|
|
|
|
contentHashType: "javascript"
|
2018-02-25 09:00:20 +08:00
|
|
|
},
|
|
|
|
|
identifier: `chunk${chunk.id}`,
|
2018-10-23 23:09:32 +08:00
|
|
|
hash: chunk.hash
|
2018-02-25 09:00:20 +08:00
|
|
|
});
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
compilation.mainTemplate.hooks.modules.tap(
|
|
|
|
|
"JavascriptModulesPlugin",
|
2018-08-14 22:40:37 +08:00
|
|
|
(source, moduleTemplate, renderContext) => {
|
2018-02-25 09:00:20 +08:00
|
|
|
return Template.renderChunkModules(
|
2018-08-14 22:40:37 +08:00
|
|
|
renderContext,
|
2018-12-03 22:00:32 +08:00
|
|
|
m => m.getSourceTypes().has("javascript"),
|
2018-02-25 09:00:20 +08:00
|
|
|
moduleTemplate,
|
|
|
|
|
"/******/ "
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
compilation.chunkTemplate.hooks.renderManifest.tap(
|
|
|
|
|
"JavascriptModulesPlugin",
|
|
|
|
|
(result, options) => {
|
|
|
|
|
const chunk = options.chunk;
|
2018-11-28 20:07:40 +08:00
|
|
|
const hotUpdateChunk =
|
|
|
|
|
chunk instanceof HotUpdateChunk ? chunk : null;
|
2018-02-25 09:00:20 +08:00
|
|
|
const outputOptions = options.outputOptions;
|
|
|
|
|
const moduleTemplates = options.moduleTemplates;
|
|
|
|
|
const dependencyTemplates = options.dependencyTemplates;
|
2018-05-25 22:12:40 +08:00
|
|
|
|
|
|
|
|
let filenameTemplate;
|
2018-11-28 20:07:40 +08:00
|
|
|
if (hotUpdateChunk) {
|
|
|
|
|
filenameTemplate = outputOptions.hotUpdateChunkFilename;
|
|
|
|
|
} else if (chunk.filenameTemplate) {
|
2018-05-25 22:12:40 +08:00
|
|
|
filenameTemplate = chunk.filenameTemplate;
|
2018-06-27 19:55:01 +08:00
|
|
|
} else if (chunk.isOnlyInitial()) {
|
2018-05-25 22:12:40 +08:00
|
|
|
filenameTemplate = outputOptions.filename;
|
|
|
|
|
} else {
|
|
|
|
|
filenameTemplate = outputOptions.chunkFilename;
|
|
|
|
|
}
|
2018-01-24 16:39:49 +08:00
|
|
|
|
2018-02-25 09:00:20 +08:00
|
|
|
result.push({
|
|
|
|
|
render: () =>
|
|
|
|
|
this.renderJavascript(
|
2018-08-23 22:54:02 +08:00
|
|
|
compilation,
|
2018-02-25 09:00:20 +08:00
|
|
|
compilation.chunkTemplate,
|
|
|
|
|
moduleTemplates.javascript,
|
2018-07-24 23:35:36 +08:00
|
|
|
{
|
|
|
|
|
chunk,
|
|
|
|
|
dependencyTemplates,
|
|
|
|
|
runtimeTemplate: compilation.runtimeTemplate,
|
2018-08-22 17:49:27 +08:00
|
|
|
moduleGraph,
|
2018-08-14 17:18:22 +08:00
|
|
|
chunkGraph: compilation.chunkGraph
|
2018-07-24 23:35:36 +08:00
|
|
|
}
|
2018-02-25 09:00:20 +08:00
|
|
|
),
|
|
|
|
|
filenameTemplate,
|
|
|
|
|
pathOptions: {
|
2018-11-28 20:07:40 +08:00
|
|
|
hash: options.hash,
|
2018-03-23 02:52:11 +08:00
|
|
|
chunk,
|
|
|
|
|
contentHashType: "javascript"
|
2018-02-25 09:00:20 +08:00
|
|
|
},
|
|
|
|
|
identifier: `chunk${chunk.id}`,
|
|
|
|
|
hash: chunk.hash
|
|
|
|
|
});
|
2018-01-24 16:39:49 +08:00
|
|
|
|
2018-02-25 09:00:20 +08:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
);
|
2018-03-23 02:52:11 +08:00
|
|
|
compilation.hooks.contentHash.tap("JavascriptModulesPlugin", chunk => {
|
2018-03-24 18:21:41 +08:00
|
|
|
const {
|
2018-08-14 17:18:22 +08:00
|
|
|
chunkGraph,
|
2018-09-15 19:10:58 +08:00
|
|
|
moduleGraph,
|
|
|
|
|
runtimeTemplate,
|
2018-08-14 17:18:22 +08:00
|
|
|
outputOptions: {
|
|
|
|
|
hashSalt,
|
|
|
|
|
hashDigest,
|
|
|
|
|
hashDigestLength,
|
|
|
|
|
hashFunction
|
|
|
|
|
}
|
|
|
|
|
} = compilation;
|
2018-11-28 20:07:40 +08:00
|
|
|
const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
|
2018-03-23 02:52:11 +08:00
|
|
|
const hash = createHash(hashFunction);
|
|
|
|
|
if (hashSalt) hash.update(hashSalt);
|
|
|
|
|
const template = chunk.hasRuntime()
|
|
|
|
|
? compilation.mainTemplate
|
|
|
|
|
: compilation.chunkTemplate;
|
2018-08-20 15:47:10 +08:00
|
|
|
hash.update(`${chunk.id} `);
|
|
|
|
|
hash.update(chunk.ids ? chunk.ids.join(",") : "");
|
2018-09-15 19:10:58 +08:00
|
|
|
template.updateHashForChunk(hash, chunk, {
|
|
|
|
|
chunkGraph,
|
|
|
|
|
moduleGraph,
|
|
|
|
|
runtimeTemplate
|
|
|
|
|
});
|
2018-08-14 17:18:22 +08:00
|
|
|
for (const m of chunkGraph.getOrderedChunkModulesIterable(
|
|
|
|
|
chunk,
|
2018-08-28 17:50:33 +08:00
|
|
|
compareModulesById(chunkGraph)
|
2018-08-14 17:18:22 +08:00
|
|
|
)) {
|
2018-12-03 22:00:32 +08:00
|
|
|
if (m.getSourceTypes().has("javascript")) {
|
2018-08-23 01:23:48 +08:00
|
|
|
hash.update(chunkGraph.getModuleHash(m));
|
2018-03-23 02:52:11 +08:00
|
|
|
}
|
|
|
|
|
}
|
2018-11-28 20:07:40 +08:00
|
|
|
if (hotUpdateChunk) {
|
|
|
|
|
hash.update(JSON.stringify(hotUpdateChunk.removedModules));
|
|
|
|
|
}
|
2018-03-23 02:52:11 +08:00
|
|
|
chunk.contentHash.javascript = hash
|
|
|
|
|
.digest(hashDigest)
|
|
|
|
|
.substr(0, hashDigestLength);
|
|
|
|
|
});
|
2018-02-25 09:00:20 +08:00
|
|
|
}
|
|
|
|
|
);
|
2017-11-10 18:02:24 +08:00
|
|
|
}
|
2018-01-24 16:39:49 +08:00
|
|
|
|
2018-07-24 23:35:36 +08:00
|
|
|
/**
|
2018-08-23 22:54:02 +08:00
|
|
|
* @param {Compilation} compilation the compilation
|
2018-07-24 23:35:36 +08:00
|
|
|
* @param {ChunkTemplate} chunkTemplate the chunk template
|
|
|
|
|
* @param {ModuleTemplate} moduleTemplate the module template
|
|
|
|
|
* @param {RenderContext} renderContext the render context
|
|
|
|
|
* @returns {Source} the rendered source
|
|
|
|
|
*/
|
2018-08-23 22:54:02 +08:00
|
|
|
renderJavascript(compilation, chunkTemplate, moduleTemplate, renderContext) {
|
|
|
|
|
const chunk = renderContext.chunk;
|
2018-02-25 09:00:20 +08:00
|
|
|
const moduleSources = Template.renderChunkModules(
|
2018-07-24 23:35:36 +08:00
|
|
|
renderContext,
|
2018-12-03 22:00:32 +08:00
|
|
|
m => m.getSourceTypes().has("javascript"),
|
2018-07-24 23:35:36 +08:00
|
|
|
moduleTemplate
|
2018-02-25 09:00:20 +08:00
|
|
|
);
|
|
|
|
|
const core = chunkTemplate.hooks.modules.call(
|
|
|
|
|
moduleSources,
|
|
|
|
|
moduleTemplate,
|
2018-07-24 23:35:36 +08:00
|
|
|
renderContext
|
2018-02-25 09:00:20 +08:00
|
|
|
);
|
|
|
|
|
let source = chunkTemplate.hooks.render.call(
|
|
|
|
|
core,
|
|
|
|
|
moduleTemplate,
|
2018-07-24 23:35:36 +08:00
|
|
|
renderContext
|
2018-02-25 09:00:20 +08:00
|
|
|
);
|
2018-08-14 22:40:37 +08:00
|
|
|
if (renderContext.chunkGraph.getNumberOfEntryModules(chunk) > 0) {
|
2018-01-24 16:39:49 +08:00
|
|
|
source = chunkTemplate.hooks.renderWithEntry.call(source, chunk);
|
|
|
|
|
}
|
|
|
|
|
chunk.rendered = true;
|
|
|
|
|
return new ConcatSource(source, ";");
|
|
|
|
|
}
|
2017-11-10 18:02:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = JavascriptModulesPlugin;
|