@ima/cli
Version:
IMA.js CLI tool to build, develop and work with IMA.js applications.
196 lines (195 loc) • 7.56 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatWebpackErrors = formatWebpackErrors;
exports.formatWebpackWarnings = formatWebpackWarnings;
exports.formatStats = formatStats;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const cliUtils_1 = require("@ima/dev-utils/cliUtils");
const logger_1 = require("@ima/dev-utils/logger");
const chalk_1 = __importDefault(require("chalk"));
const pretty_bytes_1 = __importDefault(require("pretty-bytes"));
const pretty_ms_1 = __importDefault(require("pretty-ms"));
const warningsCache = new Set();
/**
* Prints formatted webpack errors (stripped from duplicates) into console.
*/
async function formatWebpackErrors(stats, args) {
if (!stats?.hasErrors()) {
return;
}
// Raw verbose
if (args.verbose) {
return logger_1.logger.write(stats.toString({ all: false, errors: true }));
}
const { errors } = stats.toJson({ all: false, errors: true });
if (!Array.isArray(errors)) {
return;
}
const uniqueErrorTracker = [];
for (const error of errors) {
// Format error
try {
const parsedErrorData = await (0, cliUtils_1.parseError)(error, 'compile');
const formattedError = await (0, cliUtils_1.formatError)(parsedErrorData, args.rootDir, uniqueErrorTracker);
// Print unique error
formattedError && logger_1.logger.error(formattedError);
}
catch {
// Fallback to original error messsage
logger_1.logger.error(await (0, cliUtils_1.formatError)({
name: error?.name,
message: error?.message,
fileUri: error?.file,
stack: error?.stack,
}, args.rootDir, uniqueErrorTracker));
}
}
}
/**
* Prints cleaned up webpack warnings.
*/
function formatWebpackWarnings(stats, args) {
if (args.ignoreWarnings) {
return;
}
if (!stats?.hasWarnings()) {
return;
}
const { warnings } = stats.toJson({ all: false, warnings: true });
const newWarnings = [];
// Cache unique warnings
if (Array.isArray(warnings)) {
for (const warning of warnings) {
// Ignore source-map-loader warnings
if (warning.message.includes('Failed to parse source map')) {
continue;
}
if (!warningsCache.has(warning.message)) {
warningsCache.add(warning.message);
newWarnings.push(warning);
}
}
}
if (newWarnings.length === 0) {
return;
}
// Minimal (default) verbose
newWarnings?.forEach(warning => {
logger_1.logger.warn(`at ${chalk_1.default.blueBright.bold.underline(warning.moduleName)}`);
const lines = warning.message.split('\n');
logger_1.logger.write(chalk_1.default.underline(lines.shift()));
logger_1.logger.write(lines.join('\n'));
});
}
/**
* Extracts asset paths from it's name (containing basePath)
* and output directory.
*/
function extractAssetPaths(name, outDir) {
const fullPath = path_1.default.join(outDir, name);
const lastSlashIndex = fullPath.lastIndexOf('/');
const fileName = fullPath.substring(lastSlashIndex + 1);
const basePath = fullPath
.substring(0, lastSlashIndex + 1)
.replace(outDir, '');
return {
fileName,
fullPath,
basePath,
};
}
/**
* Print formatted info about given asset
*/
function printAssetInfo(asset, outDir, isLastItem = false) {
let result = '';
if (!asset || !asset.name) {
return;
}
const assetPaths = extractAssetPaths(asset.name, outDir);
// Print output
result += chalk_1.default.gray(isLastItem ? ' └ ' : ' ├ ');
result += chalk_1.default.gray(assetPaths.basePath);
result += chalk_1.default.bold.cyan(assetPaths.fileName);
result += ` ${chalk_1.default.green.bold((0, pretty_bytes_1.default)(asset.size))}`;
// Prints brotli and gzip sizes
Object.values(asset?.info?.related ?? {})
.map(assetName => extractAssetPaths(assetName?.toString() ?? '', outDir))
.filter(({ fullPath }) => fs_1.default.existsSync(fullPath))
.forEach(({ fileName, fullPath }) => {
result += '\n';
result += chalk_1.default.gray(isLastItem ? ' ' : ' ǀ ');
result += fileName;
result += chalk_1.default.yellow(` ${(0, pretty_bytes_1.default)(fs_1.default.statSync(path_1.default.join(fullPath)).size)}`);
});
logger_1.logger.write(result);
}
/**
* Handles stats logging during webpack build and watch tasks.
*
* @param {MultiStats|undefined} stats Webpack stats object.
* @param {ImaCliArgs} args Cli and build args.
* @returns {void}
*/
function formatStats(stats, args) {
if (!stats) {
return logger_1.logger.error('Unknown error, stats are empty');
}
// Print raw webpack log
if (args?.verbose) {
return logger_1.logger.write(stats.toString({
warnings: !args.ignoreWarnings,
colors: true,
}));
}
const jsonStats = stats.toJson({
all: false,
assets: true,
timings: true,
version: true,
outputPath: true,
chunkGroups: true,
});
if (!Array.isArray(jsonStats.children) || jsonStats.children?.length === 0) {
return;
}
let totalAssetCount = 0;
let chunkAssetsCount = 0;
const outDir = jsonStats.children[0].outputPath ?? '';
logger_1.logger.info(`Compilation was ${chalk_1.default.green('successful')} using webpack version: ${chalk_1.default.magenta(jsonStats.children[0].version)}`);
args.command === 'dev' &&
logger_1.logger.info(`Client assets are served from ${args.writeToDisk
? chalk_1.default.blueBright('disk')
: chalk_1.default.yellowBright('memory')}`);
logger_1.logger.info(`Output folder ${chalk_1.default.magenta(outDir)}, produced:\n`);
// Print info about emitted assets
jsonStats.children?.forEach(child => {
logger_1.logger.write(`${chalk_1.default.underline.bold(child.name)} ${chalk_1.default.gray(`[${(0, pretty_ms_1.default)(child.time ?? 0)}]`)}`);
// Count total number of generated assets
totalAssetCount +=
child?.assets?.reduce((acc, cur) => {
acc += cur?.filteredRelated ?? 0 + 1;
return acc;
}, 0) ?? 0;
if (!(child.name && child.namedChunkGroups?.[child.name])) {
return;
}
// Child assets
const filteredAssets = child.namedChunkGroups?.[child.name]?.assets?.map(({ name }) => child?.assets?.find(childAsset => childAsset.name === name)) ?? [];
// Print chunk assets
filteredAssets?.forEach((asset, index) => {
// Count also related (plugin generated) files
chunkAssetsCount += asset?.filteredRelated ?? 0;
printAssetInfo(asset, outDir, index === filteredAssets?.length - 1);
});
logger_1.logger.write('');
});
// Total number of additional assets
const additionalAssetsCount = totalAssetCount - chunkAssetsCount;
// Print more information for build task
logger_1.logger.write(`The compilation generated ${chalk_1.default.green.bold(additionalAssetsCount)} additional assets.\n`);
}