UNPKG

@quasar/app-webpack

Version:

Quasar Framework App CLI with Webpack

289 lines (235 loc) 6.82 kB
const { ProgressPlugin } = require('webpack') const throttle = require('lodash/throttle.js') const { green, gray, bold, trueColor } = require('kolorist') const { success, info, error, warning, clearConsole, dot } = require('../utils/logger.js') const { isMinimalTerminal } = require('../utils/is-minimal-terminal.js') const { printWebpackWarnings, printWebpackErrors } = require('../utils/print-webpack-issue/index.js') const { progressLog } = require('../utils/progress-log.js') let maxLengthName = 0 let isDev = false const compilations = [] function isCompilationIdle() { return compilations.every(entry => entry.idle === true) } function createState(name) { const state = { name, idle: true, compiled: false, warnings: null, errors: null, startTime: null, progress: null, progressMessage: '', progressDetails: '' } const len = name.length if (len > maxLengthName) { maxLengthName = len } compilations.push(state) return state } /** * Progress bar related */ const barLength = 20 const barProgressFactor = barLength / 100 const barString = Array.apply(null, { length: barLength }).map((_, index) => { const p = index / barLength const colorize = p <= 0.5 ? trueColor(255, Math.round(p * 510), 0) : trueColor(255 - Math.round(p * 122), 255, 0) return colorize('█') }) function printBars() { if (progressLog.isActive !== true) return const prefixLen = compilations.length - 1 const lines = compilations.map((state, index) => { const prefix = index < prefixLen ? '├──' : '└──' const name = green(state.name.padEnd(maxLengthName)) const barWidth = Math.floor(state.progress * barProgressFactor) const bar = barString .map((char, i) => (i <= barWidth ? char : ' ')) .join('') const details = state.idle === false ? state.progress + '% ' + [ state.progressMessage, state.progressDetails ? [state.progressDetails[0], state.progressDetails[1]] .filter(s => s) .join(' ') : '' ] .filter(m => m) .join(' ') : 'idle' return ` ${prefix} ${name} ${bar} ${gray(details)}\n` }) progressLog( `\n ${dot} ${green(bold('Compiling with Webpack'))}:\n` + lines.join('') ) } const renderBars = throttle(printBars, 200) /** * Status related */ function printStatus() { if (isDev === true && isCompilationIdle() === false) return const entriesWithErrors = compilations.filter(entry => entry.errors !== null) if (entriesWithErrors.length > 0) { if (isDev === true) clearConsole() entriesWithErrors.forEach(entry => { printWebpackErrors(entry.name, entry.errors) }) console.log() error('Please check the log above for details.\n', 'COMPILATION FAILED') if (isDev === false) { process.exit(1) } return } if (isDev !== true && isCompilationIdle() === false) return const entriesWithWarnings = compilations.filter( entry => entry.warnings !== null ) if (entriesWithWarnings.length > 0) { entriesWithWarnings.forEach(entry => { printWebpackWarnings(entry.name, entry.warnings) }) console.log() warning( 'Compilation succeeded but there are warning(s). Please check the log above.\n' ) } } module.exports.WebpackProgressPlugin = class WebpackProgressPlugin extends ( ProgressPlugin ) { constructor({ name, quasarConf }) { const useBars = isMinimalTerminal !== true && quasarConf.build.webpackShowProgress === true if (useBars === true) { super({ handler: (percent, msg, ...details) => { this.updateBars(percent, msg, details) } }) } else { super({ handler: () => {} }) } this.opts = { quasarConf, name, useBars } isDev = quasarConf.ctx.dev === true } apply(compiler) { if (this.opts.useBars) { super.apply(compiler) } compiler.hooks.beforeCompile.tapAsync( 'QuasarProgressPlugin', (_, callback) => { progressLog.init().then(() => { callback() }) } ) compiler.hooks.watchClose.tap('QuasarProgressPlugin', () => { const index = compilations.indexOf(this.state) compilations.splice(index, 1) delete this.state if (this.opts.useBars === true) { if (compilations.length === 0) { // ensure progress log is stopped! progressLog.stop() } maxLengthName = compilations.reduce( (acc, entry) => (entry.name.length > acc ? entry.name.length : acc), 0 ) } }) compiler.hooks.compile.tap('QuasarProgressPlugin', () => { if (this.state === void 0) { this.state = createState(this.opts.name) } else { this.resetStats() } this.state.idle = false info( `Compiling of "${this.state.name}" by Webpack in progress...`, 'WAIT' ) if (this.opts.useBars === true) { progressLog.start() } this.state.startTime = Number(new Date()) }) compiler.hooks.done.tap('QuasarStatusPlugin', stats => { this.state.idle = true this.resetStats() if (stats.hasErrors()) { this.state.errors = stats } else { this.state.compiled = true if (stats.hasWarnings()) { this.state.warnings = stats } } if (this.opts.useBars === true && isCompilationIdle() === true) { progressLog.stop() } const diffTime = Number(new Date()) - this.state.startTime if (this.state.errors !== null) { error( `"${this.state.name}" compiled by Webpack with errors ${dot} ${diffTime}ms`, 'DONE' ) } else if (this.state.warnings !== null) { warning( `"${this.state.name}" compiled by Webpack, but with warnings ${dot} ${diffTime}ms`, 'DONE' ) } else { success( `"${this.state.name}" compiled with success by Webpack ${dot} ${diffTime}ms`, 'DONE' ) } printStatus() }) } resetStats() { this.state.errors = null this.state.warnings = null } updateBars(percent, msg, details) { // it may still be called even after compilation was closed // due to Webpack's delayed call of handler if (this.state === void 0) return const progress = Math.floor(percent * 100) const running = progress < 100 this.state.progress = progress this.state.progressMessage = running && msg ? msg : '' this.state.progressDetails = details if (this.opts.useBars === true) renderBars() } }