Add better CLI logging for dev/build (#126)

* Add better CLI logging for dev/build

This adds better CLI logging for dev and build.

* Fix the sorting
This commit is contained in:
Matthew Phillips 2021-04-23 13:28:00 -04:00 committed by GitHub
parent 510e7920d2
commit 9b9bdbf4a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 16 deletions

View file

@ -3,11 +3,12 @@ import type { LogOptions } from './logger';
import type { AstroRuntime, LoadResult } from './runtime';
import { existsSync, promises as fsPromises } from 'fs';
import { bold, green, yellow, underline } from 'kleur/colors';
import path from 'path';
import cheerio from 'cheerio';
import { fileURLToPath } from 'url';
import { fdir } from 'fdir';
import { defaultLogDestination, error, info } from './logger.js';
import { defaultLogDestination, error, info, trapWarn } from './logger.js';
import { createRuntime } from './runtime.js';
import { bundle, collectDynamicImports } from './build/bundle.js';
import { generateRSS } from './build/rss.js';
@ -15,6 +16,7 @@ import { generateSitemap } from './build/sitemap.js';
import { collectStatics } from './build/static.js';
import { canonicalURL } from './build/util.js';
const { mkdir, readFile, writeFile } = fsPromises;
interface PageBuildOptions {
@ -197,7 +199,11 @@ export async function build(astroConfig: AstroConfig): Promise<0 | 1> {
const pages = await allPages(pageRoot);
let builtURLs: string[] = [];
try {
info(logging , 'build', yellow('! building pages...'));
// Vue also console.warns, this silences it.
const release = trapWarn();
await Promise.all(
pages.map(async (pathname) => {
const filepath = new URL(`file://${pathname}`);
@ -222,21 +228,27 @@ export async function build(astroConfig: AstroConfig): Promise<0 | 1> {
mergeSet(imports, await collectDynamicImports(filepath, collectImportsOptions));
})
);
info(logging, 'build', green('✔'), 'pages built.');
release();
} catch (err) {
error(logging, 'generate', err);
await runtime.shutdown();
return 1;
}
info(logging, 'build', yellow('! scanning pages...'));
for (const pathname of await allPages(componentRoot)) {
mergeSet(imports, await collectDynamicImports(new URL(`file://${pathname}`), collectImportsOptions));
}
info(logging, 'build', green('✔'), 'pages scanned.');
if (imports.size > 0) {
try {
info(logging, 'build', yellow('! bundling client-side code.'));
await bundle(imports, { dist, runtime, astroConfig });
info(logging, 'build', green('✔'), 'bundling complete.');
} catch (err) {
error(logging, 'generate', err);
error(logging, 'build', err);
await runtime.shutdown();
return 1;
}
@ -250,6 +262,7 @@ export async function build(astroConfig: AstroConfig): Promise<0 | 1> {
}
if (existsSync(astroConfig.public)) {
info(logging, 'build', yellow(`! copying public folder...`));
const pub = astroConfig.public;
const publicFiles = (await new fdir().withFullPaths().crawl(fileURLToPath(pub)).withPromise()) as string[];
for (const filepath of publicFiles) {
@ -260,16 +273,28 @@ export async function build(astroConfig: AstroConfig): Promise<0 | 1> {
const bytes = await readFile(fileUrl);
await writeFilep(outUrl, bytes, null);
}
info(logging, 'build', green('✔'), 'public folder copied.');
}
// build sitemap
if (astroConfig.buildOptions.sitemap && astroConfig.buildOptions.site) {
info(logging, 'build', yellow('! creating a sitemap...'));
const sitemap = generateSitemap(builtURLs.map((url) => ({ canonicalURL: canonicalURL(url, astroConfig.buildOptions.site) })));
await writeFile(new URL('./sitemap.xml', dist), sitemap, 'utf8');
info(logging, 'build', green('✔'), 'sitemap built.');
} else if (astroConfig.buildOptions.sitemap) {
info(logging, 'tip', `Set "buildOptions.site" in astro.config.mjs to generate a sitemap.xml`);
}
builtURLs.sort((a, b) => a.localeCompare(b, 'en', { numeric: true }));
info(logging, 'build', underline('Pages'));
const lastIndex = builtURLs.length - 1;
builtURLs.forEach((url, index) => {
const sep = index === 0 ? '┌' : index === lastIndex ? '└' : '├';
info(logging, null, ' ' + sep, url === '/' ? url : url + '/');
});
await runtime.shutdown();
info(logging, 'build', bold(green('▶ Build Complete!')));
return 0;
}

View file

@ -2,9 +2,11 @@ import type { AstroConfig } from './@types/astro';
import type { LogOptions } from './logger.js';
import { logger as snowpackLogger } from 'snowpack';
import { bold, green } from 'kleur/colors';
import http from 'http';
import { relative as pathRelative } from 'path';
import { defaultLogDestination, error, parseError } from './logger.js';
import { performance } from 'perf_hooks';
import { defaultLogDestination, error, info, parseError } from './logger.js';
import { createRuntime } from './runtime.js';
const hostname = '127.0.0.1';
@ -19,6 +21,7 @@ const logging: LogOptions = {
/** The primary dev action */
export default async function dev(astroConfig: AstroConfig) {
const startServerTime = performance.now();
const { projectRoot } = astroConfig;
const runtime = await createRuntime(astroConfig, { mode: 'development', logging });
@ -66,8 +69,9 @@ export default async function dev(astroConfig: AstroConfig) {
const port = astroConfig.devOptions.port;
server.listen(port, hostname, () => {
// eslint-disable-next-line no-console
console.log(`Server running at http://${hostname}:${port}/`);
const endServerTime = performance.now();
info(logging, 'dev server', green(`Server started in ${Math.floor(endServerTime - startServerTime)}ms.`));
info(logging, 'dev server', `${green('Local:')} http://${hostname}:${port}/`);
});
}

View file

@ -15,13 +15,16 @@ export const defaultLogDestination = new Writable({
dest = process.stdout;
}
let type = event.type;
if (event.level === 'info') {
type = bold(blue(type));
} else if (event.level === 'error') {
type = bold(red(type));
if(type !== null) {
if (event.level === 'info') {
type = bold(blue(type));
} else if (event.level === 'error') {
type = bold(red(type));
}
dest.write(`[${type}] `);
}
dest.write(`[${type}] `);
dest.write(utilFormat(...event.args));
dest.write('\n');
@ -47,7 +50,7 @@ export const defaultLogOptions: LogOptions = {
};
export interface LogMessage {
type: string;
type: string | null;
level: LoggerLevel;
message: string;
args: Array<any>;
@ -62,7 +65,7 @@ const levels: Record<LoggerLevel, number> = {
};
/** Full logging API */
export function log(opts: LogOptions = defaultLogOptions, level: LoggerLevel, type: string, ...args: Array<any>) {
export function log(opts: LogOptions = defaultLogOptions, level: LoggerLevel, type: string | null, ...args: Array<any>) {
const event: LogMessage = {
type,
level,
@ -79,22 +82,22 @@ export function log(opts: LogOptions = defaultLogOptions, level: LoggerLevel, ty
}
/** Emit a message only shown in debug mode */
export function debug(opts: LogOptions, type: string, ...messages: Array<any>) {
export function debug(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'debug', type, ...messages);
}
/** Emit a general info message (be careful using this too much!) */
export function info(opts: LogOptions, type: string, ...messages: Array<any>) {
export function info(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'info', type, ...messages);
}
/** Emit a warning a user should be aware of */
export function warn(opts: LogOptions, type: string, ...messages: Array<any>) {
export function warn(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'warn', type, ...messages);
}
/** Emit a fatal error message the user should address. */
export function error(opts: LogOptions, type: string, ...messages: Array<any>) {
export function error(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'error', type, ...messages);
}
@ -129,3 +132,12 @@ export const logger = {
warn: warn.bind(null, defaultLogOptions),
error: error.bind(null, defaultLogOptions),
};
// For silencing libraries that go directly to console.warn
export function trapWarn(cb: (...args: any[]) => void = () =>{}) {
const warn = console.warn;
console.warn = function(...args: any[]) {
cb(...args);
};
return () => console.warn = warn;
}