2013-01-31 01:49:25 +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-01-13 11:53:12 +08:00
|
|
|
"use strict";
|
|
|
|
|
2018-11-23 16:37:33 +08:00
|
|
|
const { SyncWaterfallHook } = require("tapable");
|
2019-10-04 18:24:52 +08:00
|
|
|
const { ConcatSource } = require("webpack-sources");
|
2018-11-23 16:37:33 +08:00
|
|
|
const Compilation = require("../Compilation");
|
2019-10-04 18:24:52 +08:00
|
|
|
const HotUpdateChunk = require("../HotUpdateChunk");
|
2018-11-23 16:37:33 +08:00
|
|
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
|
|
|
const Template = require("../Template");
|
2019-10-11 21:46:57 +08:00
|
|
|
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
|
2020-06-25 01:44:02 +08:00
|
|
|
const chunkHasJs = require("../javascript/JavascriptModulesPlugin").chunkHasJs;
|
2018-11-23 16:37:33 +08:00
|
|
|
const JsonpChunkLoadingRuntimeModule = require("./JsonpChunkLoadingRuntimeModule");
|
2020-02-07 17:05:51 +08:00
|
|
|
const { getEntryInfo, needEntryDeferringCode } = require("./JsonpHelpers");
|
2017-01-13 11:53:12 +08:00
|
|
|
|
2018-11-23 16:37:33 +08:00
|
|
|
/** @typedef {import("../Chunk")} Chunk */
|
|
|
|
/** @typedef {import("../Compilation")} Compilation */
|
2018-11-09 05:59:19 +08:00
|
|
|
/** @typedef {import("../Compiler")} Compiler */
|
|
|
|
|
2018-11-23 16:37:33 +08:00
|
|
|
/**
|
|
|
|
* @typedef {Object} JsonpCompilationPluginHooks
|
2018-12-09 19:54:17 +08:00
|
|
|
* @property {SyncWaterfallHook<[string, Chunk, string]>} linkPreload
|
|
|
|
* @property {SyncWaterfallHook<[string, Chunk, string]>} linkPrefetch
|
2018-11-23 16:37:33 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** @type {WeakMap<Compilation, JsonpCompilationPluginHooks>} */
|
|
|
|
const compilationHooksMap = new WeakMap();
|
|
|
|
|
2017-01-13 11:53:12 +08:00
|
|
|
class JsonpTemplatePlugin {
|
2018-11-23 16:37:33 +08:00
|
|
|
/**
|
|
|
|
* @param {Compilation} compilation the compilation
|
|
|
|
* @returns {JsonpCompilationPluginHooks} hooks
|
|
|
|
*/
|
|
|
|
static getCompilationHooks(compilation) {
|
|
|
|
if (!(compilation instanceof Compilation)) {
|
|
|
|
throw new TypeError(
|
2019-10-04 18:24:52 +08:00
|
|
|
"The 'compilation' argument must be an instance of Compilation"
|
2018-11-23 16:37:33 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
let hooks = compilationHooksMap.get(compilation);
|
|
|
|
if (hooks === undefined) {
|
|
|
|
hooks = {
|
|
|
|
linkPreload: new SyncWaterfallHook(["source", "chunk", "hash"]),
|
|
|
|
linkPrefetch: new SyncWaterfallHook(["source", "chunk", "hash"])
|
|
|
|
};
|
|
|
|
compilationHooksMap.set(compilation, hooks);
|
|
|
|
}
|
|
|
|
return hooks;
|
|
|
|
}
|
|
|
|
|
2018-11-09 05:59:19 +08:00
|
|
|
/**
|
2020-04-23 16:48:36 +08:00
|
|
|
* Apply the plugin
|
2018-11-09 05:59:19 +08:00
|
|
|
* @param {Compiler} compiler the compiler instance
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2017-01-13 11:53:12 +08:00
|
|
|
apply(compiler) {
|
2018-02-25 09:00:20 +08:00
|
|
|
compiler.hooks.thisCompilation.tap("JsonpTemplatePlugin", compilation => {
|
2019-10-04 18:24:52 +08:00
|
|
|
const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
|
|
|
|
hooks.renderChunk.tap("JsonpTemplatePlugin", (modules, renderContext) => {
|
|
|
|
const { chunk, chunkGraph, runtimeTemplate } = renderContext;
|
|
|
|
const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
|
|
|
|
const globalObject = runtimeTemplate.outputOptions.globalObject;
|
|
|
|
const source = new ConcatSource();
|
|
|
|
const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
|
|
|
|
const runtimePart =
|
|
|
|
runtimeModules.length > 0 &&
|
|
|
|
Template.renderChunkRuntimeModules(runtimeModules, renderContext);
|
|
|
|
if (hotUpdateChunk) {
|
|
|
|
const jsonpFunction = runtimeTemplate.outputOptions.hotUpdateFunction;
|
|
|
|
source.add(`${globalObject}[${JSON.stringify(jsonpFunction)}](`);
|
|
|
|
source.add(`${JSON.stringify(chunk.id)},`);
|
|
|
|
source.add(modules);
|
|
|
|
if (runtimePart) {
|
|
|
|
source.add(",\n");
|
|
|
|
source.add(runtimePart);
|
|
|
|
}
|
|
|
|
source.add(")");
|
|
|
|
} else {
|
|
|
|
const jsonpFunction = runtimeTemplate.outputOptions.jsonpFunction;
|
|
|
|
source.add(
|
|
|
|
`(${globalObject}[${JSON.stringify(
|
|
|
|
jsonpFunction
|
|
|
|
)}] = ${globalObject}[${JSON.stringify(
|
|
|
|
jsonpFunction
|
|
|
|
)}] || []).push([`
|
|
|
|
);
|
|
|
|
source.add(`${JSON.stringify(chunk.ids)},`);
|
|
|
|
source.add(modules);
|
2020-06-25 01:44:02 +08:00
|
|
|
const entries = getEntryInfo(chunkGraph, chunk, c =>
|
|
|
|
chunkHasJs(c, chunkGraph)
|
|
|
|
);
|
2019-10-04 18:24:52 +08:00
|
|
|
const entriesPart =
|
|
|
|
entries.length > 0 && `,${JSON.stringify(entries)}`;
|
2019-12-19 18:53:54 +08:00
|
|
|
if (entriesPart || runtimePart) {
|
2019-10-04 18:24:52 +08:00
|
|
|
source.add(entriesPart || ",0");
|
|
|
|
}
|
2019-12-19 18:53:54 +08:00
|
|
|
if (runtimePart) {
|
2019-10-04 18:24:52 +08:00
|
|
|
source.add(",\n");
|
2019-12-19 18:53:54 +08:00
|
|
|
source.add(runtimePart);
|
2019-10-04 18:24:52 +08:00
|
|
|
}
|
|
|
|
source.add("])");
|
|
|
|
}
|
|
|
|
return source;
|
|
|
|
});
|
|
|
|
hooks.chunkHash.tap(
|
|
|
|
"JsonpTemplatePlugin",
|
|
|
|
(chunk, hash, { chunkGraph, runtimeTemplate }) => {
|
2019-10-09 21:55:21 +08:00
|
|
|
if (chunk.hasRuntime()) return;
|
2019-10-04 18:24:52 +08:00
|
|
|
hash.update("JsonpTemplatePlugin");
|
|
|
|
hash.update("1");
|
2020-06-25 01:44:02 +08:00
|
|
|
hash.update(
|
|
|
|
JSON.stringify(
|
|
|
|
getEntryInfo(chunkGraph, chunk, c => chunkHasJs(c, chunkGraph))
|
|
|
|
)
|
|
|
|
);
|
2019-10-04 18:24:52 +08:00
|
|
|
hash.update(`${runtimeTemplate.outputOptions.jsonpFunction}`);
|
|
|
|
hash.update(`${runtimeTemplate.outputOptions.hotUpdateFunction}`);
|
|
|
|
hash.update(`${runtimeTemplate.outputOptions.globalObject}`);
|
|
|
|
}
|
2018-08-14 17:18:22 +08:00
|
|
|
);
|
2018-11-23 16:37:33 +08:00
|
|
|
|
|
|
|
const {
|
|
|
|
linkPreload,
|
|
|
|
linkPrefetch
|
|
|
|
} = JsonpTemplatePlugin.getCompilationHooks(compilation);
|
|
|
|
|
|
|
|
linkPreload.tap("JsonpTemplatePlugin", (_, chunk, hash) => {
|
2020-06-25 04:05:21 +08:00
|
|
|
const { crossOriginLoading, scriptType } = compilation.outputOptions;
|
2018-11-23 16:37:33 +08:00
|
|
|
|
|
|
|
return Template.asString([
|
|
|
|
"var link = document.createElement('link');",
|
2020-06-25 04:05:21 +08:00
|
|
|
scriptType ? `link.type = ${JSON.stringify(scriptType)};` : "",
|
2018-11-23 16:37:33 +08:00
|
|
|
"link.charset = 'utf-8';",
|
|
|
|
`if (${RuntimeGlobals.scriptNonce}) {`,
|
|
|
|
Template.indent(
|
|
|
|
`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
|
|
|
|
),
|
|
|
|
"}",
|
|
|
|
'link.rel = "preload";',
|
|
|
|
'link.as = "script";',
|
2019-06-13 16:51:12 +08:00
|
|
|
`link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId);`,
|
2018-11-23 16:37:33 +08:00
|
|
|
crossOriginLoading
|
|
|
|
? Template.asString([
|
|
|
|
"if (link.href.indexOf(window.location.origin + '/') !== 0) {",
|
|
|
|
Template.indent(
|
|
|
|
`link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
|
|
|
|
),
|
|
|
|
"}"
|
|
|
|
])
|
|
|
|
: ""
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
linkPrefetch.tap("JsonpTemplatePlugin", (_, chunk, hash) => {
|
2019-10-04 18:24:52 +08:00
|
|
|
const { crossOriginLoading } = compilation.outputOptions;
|
2018-11-23 16:37:33 +08:00
|
|
|
|
|
|
|
return Template.asString([
|
|
|
|
"var link = document.createElement('link');",
|
|
|
|
crossOriginLoading
|
|
|
|
? `link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
|
|
|
|
: "",
|
|
|
|
`if (${RuntimeGlobals.scriptNonce}) {`,
|
|
|
|
Template.indent(
|
|
|
|
`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
|
|
|
|
),
|
|
|
|
"}",
|
|
|
|
'link.rel = "prefetch";',
|
|
|
|
'link.as = "script";',
|
2019-06-13 16:51:12 +08:00
|
|
|
`link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId);`
|
2018-11-23 16:37:33 +08:00
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
const onceForChunkSet = new WeakSet();
|
|
|
|
const handler = (chunk, set) => {
|
|
|
|
if (onceForChunkSet.has(chunk)) return;
|
|
|
|
onceForChunkSet.add(chunk);
|
2019-10-09 04:29:46 +08:00
|
|
|
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
|
2019-12-03 21:27:39 +08:00
|
|
|
set.add(RuntimeGlobals.hasOwnProperty);
|
2018-11-23 16:37:33 +08:00
|
|
|
compilation.addRuntimeModule(
|
|
|
|
chunk,
|
2020-08-19 21:05:49 +08:00
|
|
|
new JsonpChunkLoadingRuntimeModule(set, linkPreload, linkPrefetch)
|
2018-11-23 16:37:33 +08:00
|
|
|
);
|
|
|
|
};
|
2020-07-28 00:09:48 +08:00
|
|
|
RuntimeGlobals.ensureChunkHandlers;
|
|
|
|
RuntimeGlobals.hmrDownloadUpdateHandlers;
|
2018-11-23 16:37:33 +08:00
|
|
|
compilation.hooks.runtimeRequirementInTree
|
|
|
|
.for(RuntimeGlobals.ensureChunkHandlers)
|
|
|
|
.tap("JsonpTemplatePlugin", handler);
|
2018-11-28 20:07:40 +08:00
|
|
|
compilation.hooks.runtimeRequirementInTree
|
|
|
|
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
|
|
|
.tap("JsonpTemplatePlugin", handler);
|
|
|
|
compilation.hooks.runtimeRequirementInTree
|
|
|
|
.for(RuntimeGlobals.hmrDownloadManifest)
|
|
|
|
.tap("JsonpTemplatePlugin", handler);
|
|
|
|
|
2018-11-23 16:37:33 +08:00
|
|
|
compilation.hooks.runtimeRequirementInTree
|
|
|
|
.for(RuntimeGlobals.ensureChunkHandlers)
|
|
|
|
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
2018-11-28 20:07:40 +08:00
|
|
|
set.add(RuntimeGlobals.publicPath);
|
2020-07-28 00:09:48 +08:00
|
|
|
set.add(RuntimeGlobals.loadScript);
|
2018-11-23 16:37:33 +08:00
|
|
|
set.add(RuntimeGlobals.getChunkScriptFilename);
|
2018-11-28 20:07:40 +08:00
|
|
|
});
|
|
|
|
compilation.hooks.runtimeRequirementInTree
|
|
|
|
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
|
|
|
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
2018-11-23 16:37:33 +08:00
|
|
|
set.add(RuntimeGlobals.publicPath);
|
2020-07-28 00:09:48 +08:00
|
|
|
set.add(RuntimeGlobals.loadScript);
|
2018-11-28 20:07:40 +08:00
|
|
|
set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
|
|
|
|
set.add(RuntimeGlobals.moduleCache);
|
|
|
|
set.add(RuntimeGlobals.hmrModuleData);
|
2019-10-09 04:29:46 +08:00
|
|
|
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
|
2018-11-28 20:07:40 +08:00
|
|
|
});
|
|
|
|
compilation.hooks.runtimeRequirementInTree
|
|
|
|
.for(RuntimeGlobals.hmrDownloadManifest)
|
|
|
|
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
|
|
|
set.add(RuntimeGlobals.publicPath);
|
|
|
|
set.add(RuntimeGlobals.getUpdateManifestFilename);
|
2018-11-23 16:37:33 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
compilation.hooks.additionalTreeRuntimeRequirements.tap(
|
|
|
|
"JsonpTemplatePlugin",
|
|
|
|
(chunk, set) => {
|
2020-02-07 17:05:51 +08:00
|
|
|
const withDefer = needEntryDeferringCode(compilation, chunk);
|
2019-12-19 18:53:54 +08:00
|
|
|
if (withDefer) {
|
2018-11-23 16:37:33 +08:00
|
|
|
set.add(RuntimeGlobals.startup);
|
2019-12-19 18:53:54 +08:00
|
|
|
set.add(RuntimeGlobals.startupNoDefault);
|
2018-12-29 19:48:59 +08:00
|
|
|
handler(chunk, set);
|
2018-11-23 16:37:33 +08:00
|
|
|
}
|
2019-09-30 16:08:08 +08:00
|
|
|
if (withDefer) {
|
|
|
|
set.add(RuntimeGlobals.require);
|
|
|
|
}
|
2018-11-23 16:37:33 +08:00
|
|
|
}
|
|
|
|
);
|
2017-01-13 11:53:12 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2013-01-31 01:49:25 +08:00
|
|
|
|
|
|
|
module.exports = JsonpTemplatePlugin;
|