line_push/node_modules/webpackbar/dist/webpackbar.js
2022-07-17 13:16:16 +08:00

707 lines
16 KiB
JavaScript

'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var webpack = require('webpack');
var env = _interopDefault(require('std-env'));
var prettyTime = _interopDefault(require('pretty-time'));
var path = require('path');
var path__default = _interopDefault(path);
var chalk = _interopDefault(require('chalk'));
var Consola = _interopDefault(require('consola'));
var textTable = _interopDefault(require('text-table'));
var figures = require('figures');
var ansiEscapes = _interopDefault(require('ansi-escapes'));
var wrapAnsi = _interopDefault(require('wrap-ansi'));
function first(arr) {
return arr[0];
}
function last(arr) {
return arr.length ? arr[arr.length - 1] : null;
}
function startCase(str) {
return str[0].toUpperCase() + str.substr(1);
}
function firstMatch(regex, str) {
const m = regex.exec(str);
return m ? m[0] : null;
}
function hasValue(s) {
return s && s.length;
}
function removeAfter(delimiter, str) {
return first(str.split(delimiter)) || '';
}
function removeBefore(delimiter, str) {
return last(str.split(delimiter)) || '';
}
function range(len) {
const arr = [];
for (let i = 0; i < len; i++) {
arr.push(i);
}
return arr;
}
function shortenPath(path$1 = '') {
const cwd = process.cwd() + path.sep;
return String(path$1).replace(cwd, '');
}
function objectValues(obj) {
return Object.keys(obj).map(key => obj[key]);
}
const nodeModules = `${path__default.delimiter}node_modules${path__default.delimiter}`;
const BAR_LENGTH = 25;
const BLOCK_CHAR = '█';
const BLOCK_CHAR2 = '█';
const NEXT = ' ' + chalk.blue(figures.pointerSmall) + ' ';
const BULLET = figures.bullet;
const TICK = figures.tick;
const CROSS = figures.cross;
const CIRCLE_OPEN = figures.radioOff;
const consola = Consola.withTag('webpackbar');
const colorize = color => {
if (color[0] === '#') {
return chalk.hex(color);
}
return chalk[color] || chalk.keyword(color);
};
const renderBar = (progress, color) => {
const w = progress * (BAR_LENGTH / 100);
const bg = chalk.white(BLOCK_CHAR);
const fg = colorize(color)(BLOCK_CHAR2);
return range(BAR_LENGTH).map(i => i < w ? fg : bg).join('');
};
function createTable(data) {
return textTable(data, {
align: data[0].map(() => 'l')
}).replace(/\n/g, '\n\n');
}
function ellipsisLeft(str, n) {
if (str.length <= n - 3) {
return str;
}
return `...${str.substr(str.length - n - 1)}`;
}
const parseRequest = requestStr => {
const parts = (requestStr || '').split('!');
const file = path__default.relative(process.cwd(), removeAfter('?', removeBefore(nodeModules, parts.pop())));
const loaders = parts.map(part => firstMatch(/[a-z0-9-@]+-loader/, part)).filter(hasValue);
return {
file: hasValue(file) ? file : null,
loaders
};
};
const formatRequest = request => {
const loaders = request.loaders.join(NEXT);
if (!loaders.length) {
return request.file || '';
}
return `${loaders}${NEXT}${request.file}`;
}; // Hook helper for webpack 3 + 4 support
function hook(compiler, hookName, fn) {
if (compiler.hooks) {
compiler.hooks[hookName].tap('WebpackBar:' + hookName, fn);
} else {
compiler.plugin(hookName, fn);
}
}
const originalWrite = Symbol('webpackbarWrite');
class LogUpdate {
constructor() {
this.prevLineCount = 0;
this.listening = false;
this.extraLines = '';
this._onData = this._onData.bind(this);
this._streams = [process.stdout, process.stderr];
}
render(lines) {
this.listen();
const wrappedLines = wrapAnsi(lines, this.columns, {
trim: false,
hard: true,
wordWrap: false
});
const data = ansiEscapes.eraseLines(this.prevLineCount) + wrappedLines + '\n' + this.extraLines;
this.write(data);
this.prevLineCount = data.split('\n').length;
}
get columns() {
return (process.stderr.columns || 80) - 2;
}
write(data) {
const stream = process.stderr;
if (stream.write[originalWrite]) {
stream.write[originalWrite].call(stream, data, 'utf-8');
} else {
stream.write(data, 'utf-8');
}
}
clear() {
this.done();
this.write(ansiEscapes.eraseLines(this.prevLineCount));
}
done() {
this.stopListen();
this.prevLineCount = 0;
this.extraLines = '';
}
_onData(data) {
const str = String(data);
const lines = str.split('\n').length - 1;
if (lines > 0) {
this.prevLineCount += lines;
this.extraLines += data;
}
}
listen() {
// Prevent listening more than once
if (this.listening) {
return;
} // Spy on all streams
for (const stream of this._streams) {
// Prevent overriding more than once
if (stream.write[originalWrite]) {
continue;
} // Create a wrapper fn
const write = (data, ...args) => {
if (!stream.write[originalWrite]) {
return stream.write(data, ...args);
}
this._onData(data);
return stream.write[originalWrite].call(stream, data, ...args);
}; // Backup original write fn
write[originalWrite] = stream.write; // Override write fn
stream.write = write;
}
this.listening = true;
}
stopListen() {
// Restore original write fns
for (const stream of this._streams) {
if (stream.write[originalWrite]) {
stream.write = stream.write[originalWrite];
}
}
this.listening = false;
}
}
/* eslint-disable no-console */
const logUpdate = new LogUpdate();
let lastRender = Date.now();
class FancyReporter {
allDone() {
logUpdate.done();
}
done(context) {
this._renderStates(context.statesArray);
if (context.hasErrors) {
logUpdate.done();
}
}
progress(context) {
if (Date.now() - lastRender > 50) {
this._renderStates(context.statesArray);
}
}
_renderStates(statesArray) {
lastRender = Date.now();
const renderedStates = statesArray.map(c => this._renderState(c)).join('\n\n');
logUpdate.render('\n' + renderedStates + '\n');
}
_renderState(state) {
const color = colorize(state.color);
let line1;
let line2;
if (state.progress >= 0 && state.progress < 100) {
// Running
line1 = [color(BULLET), color(state.name), renderBar(state.progress, state.color), state.message, `(${state.progress || 0}%)`, chalk.grey(state.details[0] || ''), chalk.grey(state.details[1] || '')].join(' ');
line2 = state.request ? ' ' + chalk.grey(ellipsisLeft(formatRequest(state.request), logUpdate.columns)) : '';
} else {
let icon = ' ';
if (state.hasErrors) {
icon = CROSS;
} else if (state.progress === 100) {
icon = TICK;
} else if (state.progress === -1) {
icon = CIRCLE_OPEN;
}
line1 = color(`${icon} ${state.name}`);
line2 = chalk.grey(' ' + state.message);
}
return line1 + '\n' + line2;
}
}
class SimpleReporter {
start(context) {
consola.info(`Compiling ${context.state.name}`);
}
change(context, {
shortPath
}) {
consola.debug(`${shortPath} changed.`, `Rebuilding ${context.state.name}`);
}
done(context) {
const {
hasError,
message,
name
} = context.state;
consola[hasError ? 'error' : 'success'](`${name}: ${message}`);
}
}
const DB = {
loader: {
get: loader => startCase(loader)
},
ext: {
get: ext => `${ext} files`,
vue: 'Vue Single File components',
js: 'JavaScript files',
sass: 'SASS files',
scss: 'SASS files',
unknown: 'Unknown files'
}
};
function getDescription(category, keyword) {
if (!DB[category]) {
return startCase(keyword);
}
if (DB[category][keyword]) {
return DB[category][keyword];
}
if (DB[category].get) {
return DB[category].get(keyword);
}
return '-';
}
function formatStats(allStats) {
const lines = [];
Object.keys(allStats).forEach(category => {
const stats = allStats[category];
lines.push(`> Stats by ${chalk.bold(startCase(category))}`);
let totalRequests = 0;
const totalTime = [0, 0];
const data = [[startCase(category), 'Requests', 'Time', 'Time/Request', 'Description']];
Object.keys(stats).forEach(item => {
const stat = stats[item];
totalRequests += stat.count || 0;
const description = getDescription(category, item);
totalTime[0] += stat.time[0];
totalTime[1] += stat.time[1];
const avgTime = [stat.time[0] / stat.count, stat.time[1] / stat.count];
data.push([item, stat.count || '-', prettyTime(stat.time), prettyTime(avgTime), description]);
});
data.push(['Total', totalRequests, prettyTime(totalTime), '', '']);
lines.push(createTable(data));
});
return `${lines.join('\n\n')}\n`;
}
class Profiler {
constructor() {
this.requests = [];
}
onRequest(request) {
if (!request) {
return;
} // Measure time for last request
if (this.requests.length) {
const lastReq = this.requests[this.requests.length - 1];
if (lastReq.start) {
lastReq.time = process.hrtime(lastReq.start);
delete lastReq.start;
}
} // Ignore requests without any file or loaders
if (!request.file || !request.loaders.length) {
return;
}
this.requests.push({
request,
start: process.hrtime()
});
}
getStats() {
const loaderStats = {};
const extStats = {};
const getStat = (stats, name) => {
if (!stats[name]) {
// eslint-disable-next-line no-param-reassign
stats[name] = {
count: 0,
time: [0, 0]
};
}
return stats[name];
};
const addToStat = (stats, name, count, time) => {
const stat = getStat(stats, name);
stat.count += count;
stat.time[0] += time[0];
stat.time[1] += time[1];
};
this.requests.forEach(({
request,
time = [0, 0]
}) => {
request.loaders.forEach(loader => {
addToStat(loaderStats, loader, 1, time);
});
const ext = request.file && path__default.extname(request.file).substr(1);
addToStat(extStats, ext && ext.length ? ext : 'unknown', 1, time);
});
return {
ext: extStats,
loader: loaderStats
};
}
getFormattedStats() {
return formatStats(this.getStats());
}
}
class ProfileReporter {
progress(context) {
if (!context.state.profiler) {
context.state.profiler = new Profiler();
}
context.state.profiler.onRequest(context.state.request);
}
done(context) {
if (context.state.profiler) {
context.state.profile = context.state.profiler.getFormattedStats();
delete context.state.profiler;
}
}
allDone(context) {
let str = '';
for (const state of context.statesArray) {
const color = colorize(state.color);
if (state.profile) {
str += color(`\nProfile results for ${chalk.bold(state.name)}\n`) + `\n${state.profile}\n`;
delete state.profile;
}
}
process.stderr.write(str);
}
}
class StatsReporter {
constructor(options) {
this.options = Object.assign({
chunks: false,
children: false,
modules: false,
colors: true,
warnings: true,
errors: true
}, options);
}
done(context, {
stats
}) {
const str = stats.toString(this.options);
if (context.hasErrors) {
process.stderr.write('\n' + str + '\n');
} else {
context.state.statsString = str;
}
}
allDone(context) {
let str = '';
for (const state of context.statesArray) {
if (state.statsString) {
str += '\n' + state.statsString + '\n';
delete state.statsString;
}
}
process.stderr.write(str);
}
}
var reporters = /*#__PURE__*/Object.freeze({
fancy: FancyReporter,
basic: SimpleReporter,
profile: ProfileReporter,
stats: StatsReporter
});
const DEFAULTS = {
name: 'webpack',
color: 'green',
reporters: env.minimalCLI ? ['basic'] : ['fancy'],
reporter: null // Default state object
};
const DEFAULT_STATE = {
start: null,
progress: -1,
done: false,
message: '',
details: [],
request: null,
hasErrors: false // Mapping from name => State
};
const globalStates = {};
class WebpackBarPlugin extends webpack.ProgressPlugin {
constructor(options) {
super();
this.options = Object.assign({}, DEFAULTS, options); // Assign a better handler to base ProgressPlugin
this.handler = (percent, message, ...details) => {
this.updateProgress(percent, message, details);
}; // Reporters
this.reporters = Array.from(this.options.reporters || []);
if (this.options.reporter) {
this.reporters.push(this.options.reporter);
} // Resolve reporters
this.reporters = this.reporters.filter(Boolean).map(_reporter => {
if (this.options[_reporter] === false) {
return false;
}
let reporter = _reporter;
let reporterOptions = this.options[reporter] || {};
if (Array.isArray(_reporter)) {
reporter = _reporter[0];
if (_reporter[1] === false) {
return false;
}
if (_reporter[1]) {
reporterOptions = _reporter[1];
}
}
if (typeof reporter === 'string') {
if (reporters[reporter]) {
// eslint-disable-line import/namespace
reporter = reporters[reporter]; // eslint-disable-line import/namespace
} else {
reporter = require(reporter);
}
}
if (typeof reporter === 'function') {
if (typeof reporter.constructor === 'function') {
const Reporter = reporter;
reporter = new Reporter(reporterOptions);
} else {
reporter = reporter(reporterOptions);
}
}
return reporter;
}).filter(Boolean);
}
callReporters(fn, payload = {}) {
for (const reporter of this.reporters) {
if (typeof reporter[fn] === 'function') {
try {
reporter[fn](this, payload);
} catch (e) {
process.stdout.write(e.stack + '\n');
}
}
}
}
get hasRunning() {
return objectValues(this.states).some(state => !state.done);
}
get hasErrors() {
return objectValues(this.states).some(state => state.hasErrors);
}
get statesArray() {
return objectValues(this.states).sort((s1, s2) => s1.name.localeCompare(s2.name));
}
get states() {
return globalStates;
}
get state() {
return globalStates[this.options.name];
}
_ensureState() {
// Keep our state in shared object
if (!this.states[this.options.name]) {
this.states[this.options.name] = { ...DEFAULT_STATE,
color: this.options.color,
name: startCase(this.options.name)
};
}
}
apply(compiler) {
// Prevent adding multi instances to the same compiler
if (compiler.webpackbar) {
return;
}
compiler.webpackbar = this; // Apply base hooks
super.apply(compiler); // Register our state after all plugins initialized
hook(compiler, 'afterPlugins', () => {
this._ensureState();
}); // Hook into the compiler before a new compilation is created.
hook(compiler, 'compile', () => {
this._ensureState();
Object.assign(this.state, { ...DEFAULT_STATE,
start: process.hrtime()
});
this.callReporters('start');
}); // Watch compilation has been invalidated.
hook(compiler, 'invalid', (fileName, changeTime) => {
this._ensureState();
this.callReporters('change', {
path: fileName,
shortPath: shortenPath(fileName),
time: changeTime
});
}); // Compilation has completed
hook(compiler, 'done', stats => {
this._ensureState(); // Prevent calling done twice
if (this.state.done) {
return;
}
const hasErrors = stats.hasErrors();
const status = hasErrors ? 'with some errors' : 'successfully';
const time = this.state.start ? ' in ' + prettyTime(process.hrtime(this.state.start), 2) : '';
Object.assign(this.state, { ...DEFAULT_STATE,
progress: 100,
done: true,
message: `Compiled ${status}${time}`,
hasErrors
});
this.callReporters('progress');
this.callReporters('done', {
stats
});
if (!this.hasRunning) {
this.callReporters('beforeAllDone');
this.callReporters('allDone');
this.callReporters('afterAllDone');
}
});
}
updateProgress(percent = 0, message = '', details = []) {
const progress = Math.floor(percent * 100);
Object.assign(this.state, {
progress,
message: message || '',
details,
request: parseRequest(details[2])
});
this.callReporters('progress');
}
}
module.exports = WebpackBarPlugin;