jetpack
Version:
Jetpack wraps webpack and nodemon to give you the best development workflow.
181 lines (158 loc) • 4.77 kB
JavaScript
const path = require('path')
const chalk = require('picocolors')
module.exports = function reporter(compiler, log, options = {}) {
let builds = 0
function onError(errors) {
const sfx = errors.length > 1 ? 's' : ''
log.error(`Failed to compile! Found ${chalk.bold(chalk.red(errors.length))} error${sfx}:`)
errors.forEach((x) => console.log('\n ' + x.replace(/(\r?\n)/g, '$1 ') + '\n'))
}
function onWarning(warnings) {
const sfx = warnings.length > 1 ? 's' : ''
log.warn(`Compiled with ${chalk.bold(chalk.yellow(warnings.length))} warning${sfx}:`)
warnings.forEach((x) => console.log('\n ' + x.replace(/(\r?\n)/g, '$1 ') + '\n'))
}
compiler.hooks.invalid.tap('jetpack', (file) => {
file = path.relative(options.dir, file)
log.info(`File changed: ${chalk.bold(chalk.white(file))}`)
})
compiler.hooks.failed.tap('jetpack', (error) => {
log.error('Failed to compile!', error)
})
compiler.hooks.done.tap('jetpack', (stats) => {
builds++
const format = require('webpack-format-messages')
const { errors, warnings } = format(stats)
if (errors.length > 0) {
return onError(errors)
}
if (warnings.length > 0) {
onWarning(warnings)
}
if (options.printAssets) {
printAssets(stats.toJson(), log)
}
log.info(`${builds > 1 ? 'Rebuilt' : 'Built'} in ${formatTime(stats.endTime - stats.startTime)}`)
})
}
const getText = (arr, row, col) => {
return arr[row][col].value
}
const table = (array, align, log) => {
const rows = array.length
const cols = array[0].length
const colSizes = new Array(cols)
for (let col = 0; col < cols; col++) colSizes[col] = 0
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const value = `${getText(array, row, col)}`
if (value.length > colSizes[col]) {
colSizes[col] = value.length
}
}
}
for (let row = 0; row < rows; row++) {
let buf = ''
for (let col = 0; col < cols; col++) {
const format = (...args) => {
buf += array[row][col].color(...args)
}
const value = `${getText(array, row, col)}`
let l = value.length
if (align[col] === 'l') format(value)
if (col !== cols - 1) {
for (; l < colSizes[col]; l++) buf += chalk.white(' ')
}
if (align[col] === 'r') format(value)
if (col + 1 < cols && colSizes[col] !== 0) {
buf += chalk.white(' ')
}
}
console.log(' ' + buf)
}
}
const getAssetColor = (asset, defaultColor) => {
if (
asset.name.endsWith('.js.map') ||
asset.name.endsWith('.hot-update.js') ||
asset.name.endsWith('.hot-update.json')
) {
return chalk.gray
}
if (asset.isOverSizeLimit) {
return chalk.yellow
}
return defaultColor
}
function printAssets(obj, log) {
const modules = {}
obj.modules.forEach((module) => {
module.chunks.forEach((chunk) => {
modules[chunk] = modules[chunk] || 0
modules[chunk] += 1
})
})
const assets = obj.assets
.sort((a, b) => {
return a.name > b.name ? 1 : -1
})
.sort((a, b) => {
const aExt = a.name.split('.')[a.name.split('.').length - 1]
const bExt = b.name.split('.')[b.name.split('.').length - 1]
return aExt > bExt ? 1 : -1
})
if (assets && obj.assets.length > 0) {
const t = [
[
{
value: 'Asset',
color: chalk.bold
},
{
value: 'Modules',
color: chalk.bold
},
{
value: 'Size',
color: chalk.bold
}
]
]
for (const asset of assets) {
t.push([
{
value: asset.name,
color: getAssetColor(asset, chalk.white)
},
{
value:
asset.name.endsWith('.js') && !asset.name.endsWith('.hot-update.js') && !asset.name.startsWith('runtime~')
? asset.chunks.reduce((acc, chunk) => acc + modules[chunk], 0)
: '-',
color:
asset.name.endsWith('.js') && !asset.name.endsWith('.hot-update.js') && !asset.name.startsWith('runtime~')
? getAssetColor(asset, chalk.white)
: chalk.gray
},
{
value: formatSize(asset.size),
color: getAssetColor(asset, chalk.white)
}
])
}
console.log('')
table(t, 'lll', log)
console.log('')
}
}
function formatSize(size) {
if (size <= 0) {
return '0 bytes'
}
const abbreviations = ['bytes', 'KiB', 'MiB', 'GiB']
const index = Math.floor(Math.log(size) / Math.log(1024))
return `${+(size / Math.pow(1024, index)).toPrecision(3)} ${abbreviations[index]}`
}
function formatTime(ms = 0) {
return (ms / 1000).toFixed(2) + 's'
}