Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #8279 from smelukov/support-entry-progress
ProgressPlugin: support progress by entry points
  • Loading branch information
sokra committed Nov 5, 2018
2 parents 1ea411b + e35d084 commit 0293c3a
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 27 deletions.
42 changes: 42 additions & 0 deletions declarations/plugins/ProgressPlugin.d.ts
@@ -0,0 +1,42 @@
/**
* 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: string[]
) => void);

export interface ProgressPluginOptions {
/**
* Show active modules count and one active module in progress message
*/
activeModules?: boolean;
/**
* Show entries count in progress message
*/
entries?: boolean;
/**
* Function that executes for every progress step
*/
handler?: HandlerFunction;
/**
* Show modules count in progress message
*/
modules?: boolean;
/**
* 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;
}
11 changes: 11 additions & 0 deletions lib/Compilation.js
Expand Up @@ -224,6 +224,13 @@ class Compilation extends Tapable {
/** @type {SyncHook<Module>} */
succeedModule: new SyncHook(["module"]),

/** @type {SyncHook<Dependency, string>} */
addEntry: new SyncHook(["entry", "name"]),
/** @type {SyncHook<Dependency, string, Error>} */
failedEntry: new SyncHook(["entry", "name", "error"]),
/** @type {SyncHook<Dependency, string, Module>} */
succeedEntry: new SyncHook(["entry", "name", "module"]),

/** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
dependencyReference: new SyncWaterfallHook([
"dependencyReference",
Expand Down Expand Up @@ -1041,6 +1048,8 @@ class Compilation extends Tapable {
* @returns {void} returns
*/
addEntry(context, entry, name, callback) {
this.hooks.addEntry.call(entry, name);

const slot = {
name: name,
// TODO webpack 5 remove `request`
Expand Down Expand Up @@ -1068,6 +1077,7 @@ class Compilation extends Tapable {
},
(err, module) => {
if (err) {
this.hooks.failedEntry.call(entry, name, err);
return callback(err);
}

Expand All @@ -1079,6 +1089,7 @@ class Compilation extends Tapable {
this._preparedEntrypoints.splice(idx, 1);
}
}
this.hooks.succeedEntry.call(entry, name, module);
return callback(null, module);
}
);
Expand Down
139 changes: 112 additions & 27 deletions lib/ProgressPlugin.js
Expand Up @@ -4,8 +4,15 @@
*/
"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 lastMessage = "";
let lastState;
let lastStateTime;

Expand Down Expand Up @@ -46,8 +53,11 @@ const createDefaultHandler = profile => {
lastStateTime = now;
}
}
goToLineStart(msg);
process.stderr.write(msg);
if (lastMessage !== msg) {
goToLineStart(msg);
process.stderr.write(msg);
lastMessage = msg;
}
};

const goToLineStart = nextMessage => {
Expand All @@ -66,19 +76,34 @@ 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);

this.profile = options.profile;
this.handler = options.handler;
this.modulesCount = options.modulesCount;
this.showEntries = options.entries;
this.showModules = options.modules;
this.showActiveModules = options.activeModules;
}

apply(compiler) {
const { modulesCount } = this;
const handler = this.handler || createDefaultHandler(this.profile);
const showEntries = this.showEntries;
const showModules = this.showModules;
const showActiveModules = this.showActiveModules;
if (compiler.compilers) {
const states = new Array(compiler.compilers.length);
compiler.compilers.forEach((compiler, idx) => {
Expand All @@ -95,48 +120,97 @@ class ProgressPlugin {
});
} else {
let lastModulesCount = 0;
let moduleCount = 500;
let lastEntriesCount = 0;
let moduleCount = modulesCount;
let entriesCount = 1;
let doneModules = 0;
const activeModules = [];

const update = module => {
handler(
0.1 + (doneModules / Math.max(lastModulesCount, moduleCount)) * 0.6,
"building modules",
`${doneModules}/${moduleCount} modules`,
`${activeModules.length} active`,
activeModules[activeModules.length - 1]
);
let doneEntries = 0;
const activeModules = new Set();
let lastActiveModule = "";

const update = () => {
const percentByModules =
doneModules / Math.max(lastModulesCount, moduleCount);
const percentByEntries =
doneEntries / Math.max(lastEntriesCount, entriesCount);

const items = [
0.1 + Math.max(percentByModules, percentByEntries) * 0.6,
"building"
];
if (showEntries) {
items.push(`${doneEntries}/${entriesCount} entries`);
}
if (showModules) {
items.push(`${doneModules}/${moduleCount} modules`);
}
if (showActiveModules) {
items.push(`${activeModules.size} active`);
items.push(lastActiveModule);
}
handler(...items);
};

const moduleAdd = module => {
moduleCount++;
if (showActiveModules) {
const ident = module.identifier();
if (ident) {
activeModules.add(ident);
lastActiveModule = ident;
}
}
update();
};

const entryAdd = (entry, name) => {
entriesCount++;
update();
};

const moduleDone = module => {
doneModules++;
const ident = module.identifier();
if (ident) {
const idx = activeModules.indexOf(ident);
if (idx >= 0) activeModules.splice(idx, 1);
if (showActiveModules) {
const ident = module.identifier();
if (ident) {
activeModules.delete(ident);
if (lastActiveModule === ident) {
lastActiveModule = "";
for (const m of activeModules) {
lastActiveModule = m;
}
}
}
}
update();
};

const entryDone = (entry, name) => {
doneEntries++;
update();
};

compiler.hooks.compilation.tap("ProgressPlugin", compilation => {
if (compilation.compiler.isChild()) return;
lastModulesCount = moduleCount;
moduleCount = 0;
doneModules = 0;
lastEntriesCount = entriesCount;
moduleCount = entriesCount = 0;
doneModules = doneEntries = 0;
handler(0, "compiling");
compilation.hooks.buildModule.tap("ProgressPlugin", module => {
moduleCount++;
const ident = module.identifier();
if (ident) {
activeModules.push(ident);
}
update();
});

compilation.hooks.buildModule.tap("ProgressPlugin", moduleAdd);
compilation.hooks.failedModule.tap("ProgressPlugin", moduleDone);
compilation.hooks.succeedModule.tap("ProgressPlugin", moduleDone);

compilation.hooks.addEntry.tap("ProgressPlugin", entryAdd);
compilation.hooks.failedEntry.tap("ProgressPlugin", entryDone);
compilation.hooks.succeedEntry.tap("ProgressPlugin", entryDone);

const hooks = {
finishModules: "finish module graph",
seal: "sealing",
beforeChunks: "chunk graph",
afterChunks: "after chunk graph",
optimizeDependenciesBasic: "basic dependencies optimization",
optimizeDependencies: "dependencies optimization",
optimizeDependenciesAdvanced: "advanced dependencies optimization",
Expand Down Expand Up @@ -171,6 +245,7 @@ class ProgressPlugin {
recordModules: "record modules",
recordChunks: "record chunks",
beforeHash: "hashing",
contentHash: "content hashing",
afterHash: "after hashing",
recordHash: "record hash",
beforeModuleAssets: "module assets processing",
Expand Down Expand Up @@ -243,4 +318,14 @@ class ProgressPlugin {
}
}
}

ProgressPlugin.defaultOptions = {
profile: false,
modulesCount: 500,
modules: true,
activeModules: true,
// TODO webpack 5 default this to true
entries: false
};

module.exports = ProgressPlugin;
52 changes: 52 additions & 0 deletions schemas/plugins/ProgressPlugin.json
@@ -0,0 +1,52 @@
{
"definitions": {
"HandlerFunction": {
"description": "Function that executes for every progress step",
"instanceof": "Function",
"tsType": "((percentage: number, msg: string, ...args: string[]) => void)"
},
"ProgressPluginOptions": {
"type": "object",
"additionalProperties": false,
"properties": {
"activeModules": {
"description": "Show active modules count and one active module in progress message",
"type": "boolean"
},
"entries": {
"description": "Show entries count in progress message",
"type": "boolean"
},
"handler": {
"description": "Function that executes for every progress step",
"anyOf": [
{
"$ref": "#/definitions/HandlerFunction"
}
]
},
"modules": {
"description": "Show modules count in progress message",
"type": "boolean"
},
"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]
}
}
}
},
"title": "ProgressPluginArgument",
"oneOf": [
{
"$ref": "#/definitions/ProgressPluginOptions"
},
{
"$ref": "#/definitions/HandlerFunction"
}
]
}
1 change: 1 addition & 0 deletions test/NodeTemplatePlugin.test.js
Expand Up @@ -5,6 +5,7 @@ const path = require("path");
const webpack = require("../lib/webpack");

describe("NodeTemplatePlugin", () => {
jest.setTimeout(20000);
it("should compile and run a simple module", done => {
webpack(
{
Expand Down

0 comments on commit 0293c3a

Please sign in to comment.