improve public path runtime module

This commit is contained in:
Tobias Koppers 2020-09-18 09:48:53 +02:00
parent c67e03abc7
commit b5719c57e2
4 changed files with 378 additions and 390 deletions

View File

@ -160,7 +160,7 @@ class RuntimePlugin {
.tap("RuntimePlugin", (chunk, runtimeRequirements) => {
const { outputOptions } = compilation;
const { publicPath } = outputOptions;
const module = new PublicPathRuntimeModule(outputOptions);
const module = new PublicPathRuntimeModule();
if (
typeof publicPath !== "string" ||
@ -169,15 +169,13 @@ class RuntimePlugin {
module.fullHash = true;
}
const moduleRuntimeRequirements = PublicPathRuntimeModule.getRuntimeRequirements(
module
);
compilation.addRuntimeModule(chunk, module);
const moduleRuntimeRequirements = module.getRuntimeRequirements();
if (moduleRuntimeRequirements) {
for (const req of moduleRuntimeRequirements)
runtimeRequirements.add(req);
}
compilation.addRuntimeModule(chunk, module);
return true;
});
compilation.hooks.runtimeRequirementInTree

View File

@ -17,54 +17,71 @@ const { getUndoPath } = require("../util/identifier");
class PublicPathRuntimeModule extends RuntimeModule {
/**
* @param {PublicPathRuntimeModule} module module
* @returns {ReadonlyArray<string> | null} requirements
*/
static getRuntimeRequirements(module) {
if (module.publicPath !== "auto" || module.scriptType === "module")
return null;
getRuntimeRequirements() {
const { compilation } = this;
const { publicPath, scriptType } = compilation.outputOptions;
if (publicPath !== "auto" || scriptType === "module") return null;
return [RuntimeGlobals.global];
}
/**
* @param {OutputOptions} outputOptions output options
*/
constructor(outputOptions) {
super("publicPath");
const { publicPath, scriptType, importFunctionName } = outputOptions;
this.publicPath = publicPath;
this.scriptType = scriptType;
this.importName = importFunctionName;
constructor() {
super("publicPath", 5);
}
/**
* @returns {string} runtime code
*/
generate() {
const { compilation, importName, publicPath, scriptType } = this;
const { runtimeTemplate } = compilation;
const { compilation } = this;
const {
publicPath,
scriptType,
importFunctionName
} = compilation.outputOptions;
if (publicPath === "auto") {
if (scriptType === "module") {
return `${RuntimeGlobals.publicPath} = ${this.applyUndoPath(
`${importName}.meta.url.replace(/[^\\/]+$/, "")`,
runtimeTemplate
)};`;
}
return `${RuntimeGlobals.publicPath} = ${runtimeTemplate.iife(
"",
Template.indent([
`if ("document" in ${RuntimeGlobals.global} && "currentScript" in ${RuntimeGlobals.global}.document) `,
Template.indent(
`return ${this.applyUndoPath(
`${RuntimeGlobals.global}.document.currentScript.src.replace(/[^\\/]+$/, "")`,
runtimeTemplate
)};`
),
" else ",
Template.indent(`return ${this.definePath("")};`)
])
)}`;
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)};`;
}
@ -81,33 +98,6 @@ class PublicPathRuntimeModule extends RuntimeModule {
})
);
}
/**
* @param {string} code code
* @param {RuntimeTemplate} runtimeTemplate runtime template
* @returns {string} generated code
*/
applyUndoPath(code, runtimeTemplate) {
const chunkName = this.compilation.getPath(
JavascriptModulesPlugin.getChunkFilenameTemplate(
this.chunk,
this.compilation.outputOptions
),
{
chunk: this.chunk,
contentHashType: "javascript"
}
);
const undoPath = getUndoPath(chunkName, false);
if (!undoPath) return code;
if (runtimeTemplate.supportTemplateLiteral()) {
return `\`$\{${code}}$\{${JSON.stringify(undoPath)}}\``;
}
return `${code} + ${JSON.stringify(undoPath)}`;
}
}
module.exports = PublicPathRuntimeModule;

View File

@ -173,10 +173,10 @@ describe("Stats", () => {
"assets": Array [
Object {
"name": "entryB.js",
"size": 2452,
"size": 2651,
},
],
"assetsSize": 2452,
"assetsSize": 2651,
"auxiliaryAssets": undefined,
"auxiliaryAssetsSize": 0,
"childAssets": undefined,
@ -258,10 +258,10 @@ describe("Stats", () => {
"filteredRelated": undefined,
"info": Object {
"minimized": true,
"size": 2452,
"size": 2651,
},
"name": "entryB.js",
"size": 2452,
"size": 2651,
"type": "asset",
},
],

File diff suppressed because it is too large Load Diff