Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

vastly better logging #158

Merged
merged 2 commits into from
Mar 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"mkdirp": "^0.5.1",
"mri": "^1.1.0",
"node-fetch": "^1.7.3",
"pretty-ms": "^3.1.0",
"relative": "^3.0.2",
"require-relative": "^0.8.7",
"rimraf": "^2.6.2",
Expand All @@ -39,7 +40,8 @@
"source-map-support": "^0.5.3",
"tslib": "^1.8.1",
"url-parse": "^1.2.0",
"walk-sync": "^0.3.2"
"walk-sync": "^0.3.2",
"webpack-format-messages": "^1.0.1"
},
"devDependencies": {
"@std/esm": "^0.19.7",
Expand All @@ -55,6 +57,7 @@
"nightmare": "^2.10.0",
"npm-run-all": "^4.1.2",
"rollup": "^0.53.0",
"rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-json": "^2.3.0",
"rollup-plugin-string": "^2.0.2",
"rollup-plugin-typescript": "^0.8.1",
Expand Down
2 changes: 2 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import typescript from 'rollup-plugin-typescript';
import string from 'rollup-plugin-string';
import json from 'rollup-plugin-json';
import commonjs from 'rollup-plugin-commonjs';
import pkg from './package.json';

const external = [].concat(
Expand All @@ -18,6 +19,7 @@ const plugins = [
include: '**/*.md'
}),
json(),
commonjs(),
typescript({
typescript: require('typescript')
})
Expand Down
206 changes: 130 additions & 76 deletions src/cli/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as child_process from 'child_process';
import * as http from 'http';
import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
import format_messages from 'webpack-format-messages';
import prettyMs from 'pretty-ms';
import { wait_for_port } from './utils';
import { dest } from '../config';
import { create_compilers, create_app, create_routes, create_serviceworker } from 'sapper/core.js';
Expand Down Expand Up @@ -69,13 +71,12 @@ function create_hot_update_server(port: number, interval = 10000) {
}

export default async function dev() {
const dir = dest();
process.env.NODE_ENV = 'development';

const dir = dest();
rimraf.sync(dir);
mkdirp.sync(dir);

const chokidar = require('chokidar');

// initial build
const dev_port = await require('get-port')(10000);

Expand All @@ -84,20 +85,6 @@ export default async function dev() {

const hot_update_server = create_hot_update_server(dev_port);

// TODO watch the configs themselves?
const compilers = create_compilers();

function watch_files(pattern: string, events: string[], callback: () => void) {
const watcher = chokidar.watch(pattern, {
persistent: true,
ignoreInitial: true
});

events.forEach(event => {
watcher.on(event, callback);
});
}

watch_files('routes/**/*', ['add', 'unlink'], () => {
const routes = create_routes();
create_app({ routes, dev_port });
Expand All @@ -116,31 +103,106 @@ export default async function dev() {
client: deferred()
};

const times = {
client_start: Date.now(),
server_start: Date.now(),
serviceworker_start: Date.now()
let restarting = false;
let build = {
unique_warnings: new Set(),
unique_errors: new Set()
};

compilers.server.plugin('invalid', () => {
times.server_start = Date.now();
// TODO print message
deferreds.server = deferred();
});
function restart_build(filename) {
if (restarting) return;

compilers.server.watch({}, (err: Error, stats: any) => {
if (err) {
console.error(chalk.red(err.message));
} else if (stats.hasErrors()) {
// print errors. TODO notify client
stats.toJson().errors.forEach((error: Error) => {
console.error(error); // TODO make this look nice
});
} else {
console.log(`built server in ${Date.now() - times.server_start}ms`); // TODO prettify
restarting = true;
build = {
unique_warnings: new Set(),
unique_errors: new Set()
};

process.nextTick(() => {
restarting = false;
});

console.log(`\n${chalk.bold.cyan(path.relative(process.cwd(), filename))} changed. rebuilding...`);
}

// TODO watch the configs themselves?
const compilers = create_compilers();

function watch(compiler: any, { name, invalid = noop, error = noop, result }: {
name: string,
invalid?: (filename: string) => void;
error?: (error: Error) => void;
result: (stats: any) => void;
}) {
compiler.plugin('invalid', (filename: string) => {
invalid(filename);
});

compiler.watch({}, (err: Error, stats: any) => {
if (err) {
console.error(chalk.red(`✗ ${name}`));
console.error(chalk.red(err.message));
error(err);
} else {
const messages = format_messages(stats);
const info = stats.toJson();

if (messages.errors.length > 0) {
console.log(chalk.bold.red(`✗ ${name}`));

const server_info = stats.toJson();
fs.writeFileSync(path.join(dir, 'server_info.json'), JSON.stringify(server_info, null, ' '));
const filtered = messages.errors.filter((message: string) => {
return !build.unique_errors.has(message);
});

filtered.forEach((message: string) => {
build.unique_errors.add(message);
console.log(message);
});

const hidden = messages.errors.length - filtered.length;
if (hidden > 0) {
console.log(`${hidden} duplicate ${hidden === 1 ? 'error' : 'errors'} hidden\n`);
}
} else {
if (messages.warnings.length > 0) {
console.log(chalk.bold.yellow(`• ${name}`));

const filtered = messages.warnings.filter((message: string) => {
return !build.unique_warnings.has(message);
});

filtered.forEach((message: string) => {
build.unique_warnings.add(message);
console.log(`${message}\n`);
});

const hidden = messages.warnings.length - filtered.length;
if (hidden > 0) {
console.log(`${hidden} duplicate ${hidden === 1 ? 'warning' : 'warnings'} hidden\n`);
}
} else {
console.log(`${chalk.bold.green(`✔ ${name}`)} ${chalk.grey(`(${prettyMs(info.time)})`)}`);
}

result(info);
}
}
});
}

watch(compilers.server, {
name: 'server',

invalid: filename => {
restart_build(filename);
// TODO print message
deferreds.server = deferred();
},

result: info => {
// TODO log compile errors/warnings

fs.writeFileSync(path.join(dir, 'server_info.json'), JSON.stringify(info, null, ' '));

deferreds.client.promise.then(() => {
function restart() {
Expand All @@ -162,32 +224,23 @@ export default async function dev() {
}
});

compilers.client.plugin('invalid', (filename: string) => {
times.client_start = Date.now();
watch(compilers.client, {
name: 'client',

deferreds.client = deferred();
invalid: filename => {
restart_build(filename);
deferreds.client = deferred();

// TODO we should delete old assets. due to a webpack bug
// i don't even begin to comprehend, this is apparently
// quite difficult
});
// TODO we should delete old assets. due to a webpack bug
// i don't even begin to comprehend, this is apparently
// quite difficult
},

compilers.client.watch({}, (err: Error, stats: any) => {
if (err) {
console.error(chalk.red(err.message));
} else if (stats.hasErrors()) {
// print errors. TODO notify client
stats.toJson().errors.forEach((error: Error) => {
console.error(error); // TODO make this look nice
});
} else {
console.log(`built client in ${Date.now() - times.client_start}ms`); // TODO prettify

const client_info = stats.toJson();
fs.writeFileSync(path.join(dir, 'client_info.json'), JSON.stringify(client_info, null, ' '));
result: info => {
fs.writeFileSync(path.join(dir, 'client_info.json'), JSON.stringify(info, null, ' '));
deferreds.client.fulfil();

const client_files = client_info.assets.map((chunk: { name: string }) => `/client/${chunk.name}`);
const client_files = info.assets.map((chunk: { name: string }) => `/client/${chunk.name}`);

deferreds.server.promise.then(() => {
hot_update_server.send({
Expand All @@ -208,27 +261,28 @@ export default async function dev() {
? function() {
watch_serviceworker = noop;

compilers.serviceworker.plugin('invalid', (filename: string) => {
times.serviceworker_start = Date.now();
});

compilers.serviceworker.watch({}, (err: Error, stats: any) => {
if (err) {
// TODO notify client
} else if (stats.hasErrors()) {
// print errors. TODO notify client
stats.toJson().errors.forEach((error: Error) => {
console.error(error); // TODO make this look nice
});
} else {
console.log(`built service worker in ${Date.now() - times.serviceworker_start}ms`); // TODO prettify
watch(compilers.serviceworker, {
name: 'service worker',

const serviceworker_info = stats.toJson();
fs.writeFileSync(path.join(dir, 'serviceworker_info.json'), JSON.stringify(serviceworker_info, null, ' '));
result: info => {
fs.writeFileSync(path.join(dir, 'serviceworker_info.json'), JSON.stringify(info, null, ' '));
}
});
}
: noop;
}

function noop() {}
function noop() {}

function watch_files(pattern: string, events: string[], callback: () => void) {
const chokidar = require('chokidar');

const watcher = chokidar.watch(pattern, {
persistent: true,
ignoreInitial: true
});

events.forEach(event => {
watcher.on(event, callback);
});
}
2 changes: 1 addition & 1 deletion test/common/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Nightmare.action('init', function(done) {

function run(env) {
describe(`env=${env}`, function () {
this.timeout(20000);
this.timeout(30000);

let PORT;
let proc;
Expand Down