New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ProgressPlugin: support progress by entry points #8279
Changes from 2 commits
3e707b8
905929b
aa8cb0f
351114f
8c5e74f
64e3826
56d8a8f
3d74504
6be1411
e35d084
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* This file was automatically generated. | ||
* DO NOT MODIFY BY HAND. | ||
* Run `yarn special-lint-fix` to update | ||
*/ | ||
|
||
export type ProgressPluginArgument = ProgressPluginOptions | HandlerFunction; | ||
/** | ||
* Function that executes for every progress step | ||
*/ | ||
export type HandlerFunction = (( | ||
percentage: number, | ||
msg: string, | ||
...args | ||
) => void); | ||
|
||
export interface ProgressPluginOptions { | ||
/** | ||
* Function that executes for every progress step | ||
*/ | ||
handler?: HandlerFunction; | ||
/** | ||
* Counting mode. Default: modules | ||
*/ | ||
mode?: "modules" | "entries"; | ||
/** | ||
* Minimum modules count to start with. Only for mode=modules. Default: 500 | ||
*/ | ||
modulesCount?: number; | ||
/** | ||
* Collect profile data for progress steps. Default: false | ||
*/ | ||
profile?: true | false | null; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,12 @@ | |
*/ | ||
"use strict"; | ||
|
||
const validateOptions = require("schema-utils"); | ||
const schema = require("../schemas/plugins/ProgressPlugin.json"); | ||
|
||
/** @typedef {import("../declarations/plugins/ProgressPlugin").ProgressPluginArgument} ProgressPluginArgument */ | ||
/** @typedef {import("../declarations/plugins/ProgressPlugin").ProgressPluginOptions} ProgressPluginOptions */ | ||
|
||
const createDefaultHandler = profile => { | ||
let lineCaretPosition = 0; | ||
let lastState; | ||
|
@@ -66,18 +72,28 @@ const createDefaultHandler = profile => { | |
}; | ||
|
||
class ProgressPlugin { | ||
/** | ||
* @param {ProgressPluginArgument} options options | ||
*/ | ||
constructor(options) { | ||
if (typeof options === "function") { | ||
options = { | ||
handler: options | ||
}; | ||
} | ||
|
||
options = options || {}; | ||
validateOptions(schema, options, "Progress Plugin"); | ||
options = Object.assign(ProgressPlugin.defaultOptions, options); | ||
smelukov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
this.profile = options.profile; | ||
this.handler = options.handler; | ||
this.mode = options.mode; | ||
smelukov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.modulesCount = options.modulesCount; | ||
} | ||
|
||
apply(compiler) { | ||
const { mode, modulesCount } = this; | ||
const handler = this.handler || createDefaultHandler(this.profile); | ||
if (compiler.compilers) { | ||
const states = new Array(compiler.compilers.length); | ||
|
@@ -94,16 +110,16 @@ class ProgressPlugin { | |
}).apply(compiler); | ||
}); | ||
} else { | ||
let lastModulesCount = 0; | ||
let moduleCount = 500; | ||
let lastCount = 0; | ||
let count = mode === "modules" ? modulesCount : 0; | ||
let doneModules = 0; | ||
const activeModules = []; | ||
|
||
const update = module => { | ||
handler( | ||
0.1 + (doneModules / Math.max(lastModulesCount, moduleCount)) * 0.6, | ||
"building modules", | ||
`${doneModules}/${moduleCount} modules`, | ||
0.1 + (doneModules / Math.max(lastCount, count)) * 0.6, | ||
`building ${mode}`, | ||
`${doneModules}/${count} ${mode}`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be much more useful if the handler took raw data (as an object or arguments in a particular order), rather than pre-made strings. E.g. in my implementation of a progress bar using the ProgressPlugin I have to resort to regexps/splits to re-parse the data out of the strings in order to be able to position them: If instead we provided a default handler that makes these strings above, we can get the same behavior, and still give greater flexibility to consumers, alternative handlers. I would imagine handler being most flexible e.g. when called like this: handler({compilerIndex, currentStage, doneModules, activeModules, lastModulesCount, moduleCount, count, mode}) And some of those parameters would obviously be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
`${activeModules.length} active`, | ||
activeModules[activeModules.length - 1] | ||
); | ||
|
@@ -120,20 +136,44 @@ class ProgressPlugin { | |
}; | ||
compiler.hooks.compilation.tap("ProgressPlugin", compilation => { | ||
if (compilation.compiler.isChild()) return; | ||
lastModulesCount = moduleCount; | ||
moduleCount = 0; | ||
lastCount = count; | ||
count = 0; | ||
doneModules = 0; | ||
handler(0, "compiling"); | ||
compilation.hooks.buildModule.tap("ProgressPlugin", module => { | ||
moduleCount++; | ||
const addHook = | ||
mode === "modules" | ||
? compilation.hooks.buildModule | ||
: compilation.hooks.addEntry; | ||
const startHook = | ||
mode === "modules" | ||
? compilation.hooks.buildModule | ||
: compilation.hooks.buildEntry; | ||
const failedHook = | ||
mode === "modules" | ||
? compilation.hooks.failedModule | ||
: compilation.hooks.failedEntry; | ||
const succeedHook = | ||
mode === "modules" | ||
? compilation.hooks.succeedModule | ||
: compilation.hooks.succeedEntry; | ||
|
||
lastCount = count; | ||
count = 0; | ||
doneModules = 0; | ||
|
||
addHook.tap("ProgressPlugin", () => { | ||
count++; | ||
update(); | ||
}); | ||
startHook.tap("ProgressPlugin", module => { | ||
const ident = module.identifier(); | ||
if (ident) { | ||
activeModules.push(ident); | ||
} | ||
update(); | ||
}); | ||
compilation.hooks.failedModule.tap("ProgressPlugin", moduleDone); | ||
compilation.hooks.succeedModule.tap("ProgressPlugin", moduleDone); | ||
failedHook.tap("ProgressPlugin", moduleDone); | ||
succeedHook.tap("ProgressPlugin", moduleDone); | ||
const hooks = { | ||
finishModules: "finish module graph", | ||
seal: "sealing", | ||
|
@@ -243,4 +283,11 @@ class ProgressPlugin { | |
} | ||
} | ||
} | ||
|
||
ProgressPlugin.defaultOptions = { | ||
profile: false, | ||
mode: "modules", | ||
modulesCount: 500 | ||
}; | ||
|
||
module.exports = ProgressPlugin; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
{ | ||
"definitions": { | ||
"HandlerFunction": { | ||
"description": "Function that executes for every progress step", | ||
"instanceof": "Function", | ||
"tsType": "((percentage: number, msg: string, ...args) => void)" | ||
smelukov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}, | ||
"title": "ProgressPluginArgument", | ||
"oneOf": [ | ||
{ | ||
"title": "ProgressPluginOptions", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"handler": { | ||
"description": "Function that executes for every progress step", | ||
"anyOf": [ | ||
{ | ||
"$ref": "#/definitions/HandlerFunction" | ||
} | ||
] | ||
}, | ||
"mode": { | ||
"description": "Counting mode. Default: modules", | ||
"enum": ["modules", "entries"] | ||
}, | ||
"modulesCount": { | ||
"description": "Minimum modules count to start with. Only for mode=modules. Default: 500", | ||
"type": "number" | ||
}, | ||
"profile": { | ||
"description": "Collect profile data for progress steps. Default: false", | ||
"enum": [true, false, null] | ||
smelukov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
}, | ||
{ | ||
"$ref": "#/definitions/HandlerFunction" | ||
} | ||
] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to
buildEntry
and also passname
as argumentsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addEntry
is not the same thatbuildEntry
addEntry
will be called when adding an entry. This need to calculate total entriesbuildEntry
will be called when the module for an entry will be builtOr what do you mean? :)