Merge pull request #9304 from webpack/bugifx/issue-9296
allow filename as function at more places
This commit is contained in:
commit
d675f4e3ee
|
@ -973,9 +973,11 @@ export interface OptimizationSplitChunksOptions {
|
|||
minSize?: OptimizationSplitChunksSizes;
|
||||
};
|
||||
/**
|
||||
* Sets the template for the filename for created chunks (Only works for initial chunks)
|
||||
* Sets the template for the filename for created chunks
|
||||
*/
|
||||
filename?: string;
|
||||
filename?:
|
||||
| string
|
||||
| ((pathData: import("../lib/Compilation").PathData) => string);
|
||||
/**
|
||||
* Prevents exposing path info when creating names for parts splitted by maxSize
|
||||
*/
|
||||
|
@ -1037,9 +1039,11 @@ export interface OptimizationSplitChunksCacheGroup {
|
|||
*/
|
||||
enforce?: boolean;
|
||||
/**
|
||||
* Sets the template for the filename for created chunks (Only works for initial chunks)
|
||||
* Sets the template for the filename for created chunks
|
||||
*/
|
||||
filename?: string;
|
||||
filename?:
|
||||
| string
|
||||
| ((pathData: import("../lib/Compilation").PathData) => string);
|
||||
/**
|
||||
* Sets the hint for chunk id
|
||||
*/
|
||||
|
@ -1156,7 +1160,9 @@ export interface OutputOptions {
|
|||
/**
|
||||
* Specifies the name of each output file on disk. You must **not** specify an absolute path here! The `output.path` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
||||
*/
|
||||
filename?: string | Function;
|
||||
filename?:
|
||||
| string
|
||||
| ((pathData: import("../lib/Compilation").PathData) => string);
|
||||
/**
|
||||
* An expression which is used to address the global object/scope in runtime code
|
||||
*/
|
||||
|
|
|
@ -19,6 +19,7 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
|
|||
/** @typedef {import("./ChunkGraph").ModuleFilterPredicate} ModuleFilterPredicate */
|
||||
/** @typedef {import("./ChunkGroup")} ChunkGroup */
|
||||
/** @typedef {import("./Compilation")} Compilation */
|
||||
/** @typedef {import("./Compilation").PathData} PathData */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
@ -70,7 +71,7 @@ class Chunk {
|
|||
this.idNameHints = new SortableSet();
|
||||
/** @type {boolean} */
|
||||
this.preventIntegration = false;
|
||||
/** @type {string?} */
|
||||
/** @type {(string | function(PathData): string)?} */
|
||||
this.filenameTemplate = undefined;
|
||||
/** @private @type {SortableSet<ChunkGroup>} */
|
||||
this._groups = new SortableSet(undefined, sortChunkGroupById);
|
||||
|
|
|
@ -25,6 +25,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
/** @typedef {import("../../declarations/WebpackOptions").OptimizationSplitChunksSizes} OptimizationSplitChunksSizes */
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../Compilation").PathData} PathData */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
|
@ -60,7 +61,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
* @property {number=} minChunks
|
||||
* @property {number=} maxAsyncRequests
|
||||
* @property {number=} maxInitialRequests
|
||||
* @property {string=} filename
|
||||
* @property {(string | function(PathData): string)=} filename
|
||||
* @property {string=} idHint
|
||||
* @property {string} automaticNameDelimiter
|
||||
* @property {boolean=} reuseExistingChunk
|
||||
|
@ -81,7 +82,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
* @property {number=} minChunks
|
||||
* @property {number=} maxAsyncRequests
|
||||
* @property {number=} maxInitialRequests
|
||||
* @property {string=} filename
|
||||
* @property {(string | function(PathData): string)=} filename
|
||||
* @property {string=} idHint
|
||||
* @property {string} automaticNameDelimiter
|
||||
* @property {boolean=} reuseExistingChunk
|
||||
|
@ -127,7 +128,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
* @property {number} maxAsyncRequests
|
||||
* @property {number} maxInitialRequests
|
||||
* @property {boolean} hidePathInfo
|
||||
* @property {string} filename
|
||||
* @property {string | function(PathData): string} filename
|
||||
* @property {string} automaticNameDelimiter
|
||||
* @property {GetCacheGroups} getCacheGroups
|
||||
* @property {GetName} getName
|
||||
|
|
|
@ -8,7 +8,22 @@ const RuntimeGlobals = require("../RuntimeGlobals");
|
|||
const RuntimeModule = require("../RuntimeModule");
|
||||
const Template = require("../Template");
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
/** @typedef {import("../Compilation").PathData} PathData */
|
||||
|
||||
/** @typedef {function(PathData): string} FilenameFunction */
|
||||
|
||||
class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
||||
/**
|
||||
* @param {Compilation} compilation the compilation
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {string} contentType the contentType to use the content hash for
|
||||
* @param {string} name kind of filename
|
||||
* @param {string} global function name to be assigned
|
||||
* @param {function(Chunk): string | FilenameFunction} getFilenameForChunk functor to get the filename or function
|
||||
* @param {boolean} allChunks when false, only async chunks are included
|
||||
*/
|
||||
constructor(
|
||||
compilation,
|
||||
chunk,
|
||||
|
@ -41,9 +56,16 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
|||
} = this;
|
||||
const mainTemplate = compilation.mainTemplate;
|
||||
|
||||
/** @type {Map<string | FilenameFunction, Set<Chunk>>} */
|
||||
const chunkFilenames = new Map();
|
||||
let maxChunks = 0;
|
||||
/** @type {string} */
|
||||
let dynamicFilename;
|
||||
|
||||
/**
|
||||
* @param {Chunk} c the chunk
|
||||
* @returns {void}
|
||||
*/
|
||||
const addChunk = c => {
|
||||
const chunkFilename = getFilenameForChunk(c);
|
||||
if (chunkFilename) {
|
||||
|
@ -52,18 +74,21 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
|||
chunkFilenames.set(chunkFilename, (set = new Set()));
|
||||
}
|
||||
set.add(c);
|
||||
if (set.size < maxChunks) return;
|
||||
if (set.size === maxChunks) {
|
||||
if (chunkFilename.length < dynamicFilename.length) return;
|
||||
if (chunkFilename.length === dynamicFilename.length) {
|
||||
if (chunkFilename < dynamicFilename) return;
|
||||
if (typeof chunkFilename === "string") {
|
||||
if (set.size < maxChunks) return;
|
||||
if (set.size === maxChunks) {
|
||||
if (chunkFilename.length < dynamicFilename.length) return;
|
||||
if (chunkFilename.length === dynamicFilename.length) {
|
||||
if (chunkFilename < dynamicFilename) return;
|
||||
}
|
||||
}
|
||||
maxChunks = set.size;
|
||||
dynamicFilename = chunkFilename;
|
||||
}
|
||||
maxChunks = set.size;
|
||||
dynamicFilename = chunkFilename;
|
||||
}
|
||||
};
|
||||
|
||||
/** @type {string[]} */
|
||||
const includedChunksMessages = [];
|
||||
if (allChunks) {
|
||||
includedChunksMessages.push("all chunks");
|
||||
|
@ -88,23 +113,43 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
|||
}
|
||||
}
|
||||
|
||||
/** @type {Map<string, Set<string | number>>} */
|
||||
const staticUrls = new Map();
|
||||
/** @type {Set<Chunk>} */
|
||||
const dynamicUrlChunks = new Set();
|
||||
|
||||
/**
|
||||
* @param {Chunk} c the chunk
|
||||
* @param {string | FilenameFunction} chunkFilename the filename template for the chunk
|
||||
* @returns {void}
|
||||
*/
|
||||
const addStaticUrl = (c, chunkFilename) => {
|
||||
/**
|
||||
* @param {string | number} value a value
|
||||
* @returns {string} string to put in quotes
|
||||
*/
|
||||
const unquotedStringify = value => {
|
||||
const str = `${value}`;
|
||||
if (str.length >= 5 && str === `${c.id}`) {
|
||||
// This is shorter and generates the same result
|
||||
return `" + chunkId + "`;
|
||||
return '" + chunkId + "';
|
||||
}
|
||||
const s = JSON.stringify(str);
|
||||
return s.slice(1, s.length - 2);
|
||||
};
|
||||
const unquotedStringifyWithLength = value => length =>
|
||||
unquotedStringify(`${value}`.slice(0, length));
|
||||
const chunkFilenameValue =
|
||||
typeof chunkFilename === "function"
|
||||
? JSON.stringify(
|
||||
chunkFilename({
|
||||
chunk: c,
|
||||
contentHashType: contentType
|
||||
})
|
||||
)
|
||||
: JSON.stringify(chunkFilename);
|
||||
const staticChunkFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(chunkFilename),
|
||||
chunkFilenameValue,
|
||||
{
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
|
@ -141,6 +186,10 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {function(Chunk): string | number} fn function from chunk to value
|
||||
* @returns {string} code with static mapping of results of fn
|
||||
*/
|
||||
const createMap = fn => {
|
||||
const obj = {};
|
||||
let useId = false;
|
||||
|
@ -168,9 +217,19 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
|||
? `(${JSON.stringify(obj)}[chunkId] || chunkId)`
|
||||
: `${JSON.stringify(obj)}[chunkId]`;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {function(Chunk): string | number} fn function from chunk to value
|
||||
* @returns {string} code with static mapping of results of fn for including in quoted string
|
||||
*/
|
||||
const mapExpr = fn => {
|
||||
return `" + ${createMap(fn)} + "`;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {function(Chunk): string | number} fn function from chunk to value
|
||||
* @returns {function(number): string} function which generates code with static mapping of results of fn for including in quoted string for specific length
|
||||
*/
|
||||
const mapExprWithLength = fn => length => {
|
||||
return `" + ${createMap(c => `${fn(c)}`.slice(0, length))} + "`;
|
||||
};
|
||||
|
|
|
@ -642,9 +642,18 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"filename": {
|
||||
"description": "Sets the template for the filename for created chunks (Only works for initial chunks)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
"description": "Sets the template for the filename for created chunks",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"absolutePath": false,
|
||||
"minLength": 1
|
||||
},
|
||||
{
|
||||
"instanceof": "Function",
|
||||
"tsType": "((pathData: import(\"../lib/Compilation\").PathData) => string)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"idHint": {
|
||||
"description": "Sets the hint for chunk id",
|
||||
|
@ -858,9 +867,18 @@
|
|||
}
|
||||
},
|
||||
"filename": {
|
||||
"description": "Sets the template for the filename for created chunks (Only works for initial chunks)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
"description": "Sets the template for the filename for created chunks",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"absolutePath": false,
|
||||
"minLength": 1
|
||||
},
|
||||
{
|
||||
"instanceof": "Function",
|
||||
"tsType": "((pathData: import(\"../lib/Compilation\").PathData) => string)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hidePathInfo": {
|
||||
"description": "Prevents exposing path info when creating names for parts splitted by maxSize",
|
||||
|
@ -1041,11 +1059,12 @@
|
|||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"absolutePath": false
|
||||
"absolutePath": false,
|
||||
"minLength": 1
|
||||
},
|
||||
{
|
||||
"instanceof": "Function",
|
||||
"tsType": "Function"
|
||||
"tsType": "((pathData: import(\"../lib/Compilation\").PathData) => string)"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -120,7 +120,7 @@ describe("Validation", () => {
|
|||
- configuration.entry[0] should be a string.
|
||||
-> A non-empty string
|
||||
- configuration.output.filename should be one of these:
|
||||
string | function
|
||||
non-empty string | function
|
||||
-> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The \`output.path\` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
||||
Details:
|
||||
* configuration.output.filename should be a string.
|
||||
|
@ -147,7 +147,7 @@ describe("Validation", () => {
|
|||
- configuration[0].entry[0] should be a string.
|
||||
-> A non-empty string
|
||||
- configuration[1].output.filename should be one of these:
|
||||
string | function
|
||||
non-empty string | function
|
||||
-> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The \`output.path\` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
||||
Details:
|
||||
* configuration[1].output.filename should be a string.
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import "./shared1";
|
||||
import "./common1";
|
||||
|
||||
it("should be able to load the split chunk on demand (shared)", () => {
|
||||
return import(/* webpackChunkName: "theName" */ "./shared2");
|
||||
});
|
||||
|
||||
it("should be able to load the split chunk on demand (common)", () => {
|
||||
return Promise.all([
|
||||
import(/* webpackChunkName: "otherName1" */ "./common2"),
|
||||
import(/* webpackChunkName: "otherName2" */ "./common3")
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
import "./shared1";
|
||||
import "./shared2";
|
||||
import "./common1";
|
||||
import "./common2";
|
||||
import "./common3";
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
findBundle: function(i, options) {
|
||||
return ["a.js"];
|
||||
}
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
module.exports = {
|
||||
entry: {
|
||||
a: "./a",
|
||||
b: "./b"
|
||||
},
|
||||
output: {
|
||||
filename: data => `${data.chunk.name || data.chunk.id}.js`,
|
||||
libraryTarget: "commonjs2"
|
||||
},
|
||||
optimization: {
|
||||
chunkIds: "named",
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
shared: {
|
||||
chunks: "all",
|
||||
test: /shared/,
|
||||
filename: data => `shared-${data.chunk.name || data.chunk.id}.js`,
|
||||
enforce: true
|
||||
},
|
||||
common: {
|
||||
chunks: "all",
|
||||
test: /common/,
|
||||
enforce: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue