split auto publicPath into separate module

This commit is contained in:
Tobias Koppers 2020-09-18 10:12:13 +02:00
parent b5719c57e2
commit aa74705297
3 changed files with 86 additions and 90 deletions

View File

@ -8,6 +8,7 @@
const RuntimeGlobals = require("./RuntimeGlobals");
const RuntimeRequirementsDependency = require("./dependencies/RuntimeRequirementsDependency");
const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
const AutoPublicPathRuntimeModule = require("./runtime/AutoPublicPathRuntimeModule");
const CompatGetDefaultExportRuntimeModule = require("./runtime/CompatGetDefaultExportRuntimeModule");
const CompatRuntimeModule = require("./runtime/CompatRuntimeModule");
const CreateFakeNamespaceObjectRuntimeModule = require("./runtime/CreateFakeNamespaceObjectRuntimeModule");
@ -157,24 +158,25 @@ class RuntimePlugin {
});
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.publicPath)
.tap("RuntimePlugin", (chunk, runtimeRequirements) => {
.tap("RuntimePlugin", (chunk, set) => {
const { outputOptions } = compilation;
const { publicPath } = outputOptions;
const module = new PublicPathRuntimeModule();
const { publicPath, scriptType } = outputOptions;
if (
typeof publicPath !== "string" ||
/\[(full)?hash\]/.test(publicPath)
) {
module.fullHash = true;
}
if (publicPath === "auto") {
const module = new AutoPublicPathRuntimeModule();
if (scriptType !== "module") set.add(RuntimeGlobals.global);
compilation.addRuntimeModule(chunk, module);
} else {
const module = new PublicPathRuntimeModule();
compilation.addRuntimeModule(chunk, module);
const moduleRuntimeRequirements = module.getRuntimeRequirements();
if (
typeof publicPath !== "string" ||
/\[(full)?hash\]/.test(publicPath)
) {
module.fullHash = true;
}
if (moduleRuntimeRequirements) {
for (const req of moduleRuntimeRequirements)
runtimeRequirements.add(req);
compilation.addRuntimeModule(chunk, module);
}
return true;
});

View File

@ -0,0 +1,67 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
const { getUndoPath } = require("../util/identifier");
class AutoPublicPathRuntimeModule extends RuntimeModule {
constructor() {
super("publicPath", 5);
}
/**
* @returns {string} runtime code
*/
generate() {
const { compilation } = this;
const { scriptType, importFunctionName } = compilation.outputOptions;
const chunkName = compilation.getPath(
JavascriptModulesPlugin.getChunkFilenameTemplate(
this.chunk,
compilation.outputOptions
),
{
chunk: this.chunk,
contentHashType: "javascript"
}
);
const undoPath = getUndoPath(chunkName, false);
return Template.asString([
"var scriptUrl;",
scriptType === "module"
? `if (typeof ${importFunctionName}.meta.url === "string") scriptUrl = ${importFunctionName}.meta.url`
: Template.asString([
`var document = ${RuntimeGlobals.global}.document;`,
"if (document) {",
Template.indent([
`if (document.currentScript)`,
Template.indent(`scriptUrl = document.currentScript.src`),
"if (!scriptUrl) {",
Template.indent([
'var scripts = document.getElementsByTagName("script");',
"if(scripts.length) scriptUrl = scripts[scripts.length - 1].src"
]),
"}"
]),
"}"
]),
"// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration",
'// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.',
'if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");',
'scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\\?.*$/, "").replace(/\\/[^\\/]+$/, "/");',
!undoPath
? `${RuntimeGlobals.publicPath} = scriptUrl;`
: `${RuntimeGlobals.publicPath} = scriptUrl + ${JSON.stringify(
undoPath
)};`
]);
}
}
module.exports = AutoPublicPathRuntimeModule;

View File

@ -6,27 +6,8 @@
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
const { getUndoPath } = require("../util/identifier");
/** @typedef {import("../../declarations/WebpackOptions").Output} OutputOptions */
/** @typedef {import("../../declarations/WebpackOptions").PublicPath} PublicPathOptions */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
class PublicPathRuntimeModule extends RuntimeModule {
/**
* @returns {ReadonlyArray<string> | null} requirements
*/
getRuntimeRequirements() {
const { compilation } = this;
const { publicPath, scriptType } = compilation.outputOptions;
if (publicPath !== "auto" || scriptType === "module") return null;
return [RuntimeGlobals.global];
}
constructor() {
super("publicPath", 5);
}
@ -36,67 +17,13 @@ class PublicPathRuntimeModule extends RuntimeModule {
*/
generate() {
const { compilation } = this;
const {
publicPath,
scriptType,
importFunctionName
} = compilation.outputOptions;
if (publicPath === "auto") {
const chunkName = compilation.getPath(
JavascriptModulesPlugin.getChunkFilenameTemplate(
this.chunk,
compilation.outputOptions
),
{
chunk: this.chunk,
contentHashType: "javascript"
}
);
const undoPath = getUndoPath(chunkName, false);
return Template.asString([
"var scriptUrl;",
scriptType === "module"
? `if (typeof ${importFunctionName}.meta.url === "string") scriptUrl = ${importFunctionName}.meta.url`
: Template.asString([
`var document = ${RuntimeGlobals.global}.document;`,
"if (document) {",
Template.indent([
`if (document.currentScript)`,
Template.indent(`scriptUrl = document.currentScript.src`),
"if (!scriptUrl) {",
Template.indent([
'var scripts = document.getElementsByTagName("script");',
"if(scripts.length) scriptUrl = scripts[scripts.length - 1].src"
]),
"}"
]),
"}"
]),
"// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration",
'// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.',
'if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");',
'scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\\?.*$/, "").replace(/\\/[^\\/]+$/, "/");',
!undoPath
? `${RuntimeGlobals.publicPath} = scriptUrl;`
: `${RuntimeGlobals.publicPath} = scriptUrl + ${JSON.stringify(
undoPath
)};`
]);
} else {
return `${RuntimeGlobals.publicPath} = ${this.definePath(publicPath)};`;
}
}
const { publicPath } = compilation.outputOptions;
/**
* @param {PublicPathOptions} publicPath public path
* @returns {string} runtime code
*/
definePath(publicPath) {
return JSON.stringify(
return `${RuntimeGlobals.publicPath} = ${JSON.stringify(
this.compilation.getPath(publicPath || "", {
hash: this.compilation.hash || "XXXX"
})
);
)};`;
}
}