Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bundle progress bar to logs #140

Merged
merged 16 commits into from
Apr 21, 2017
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion react-native-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@
"match-require": "^2.0.0",
"minimist": "^1.2.0",
"path-exists": "^3.0.0",
"progress": "^1.1.8",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue concerns me re: windows support

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, I don't have a windows machine to test this :<

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or rather I do but I have no idea how to use windows for anything except oculus and netflix

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw we use this same ProgressBar module on exp so this could be a problem we have to address there too if it is indeed true and not user error in that issue

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok. hm maybe it's broken in exp too then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you try out installing exp and init'ing a project? should show progress bar while downloading

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wipes tear away while spinning up a VM

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so apparently the inquirer package is also irrevocably broken on git bash, so i'm just going to step away slowly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolution: don't support git bash for now if you want a pleasant crna experience. powershell recommended on windows for now. if anyone reading this is interested in fixing git bash support it would be welcome!

"qrcode-terminal": "^0.11.0",
"xdl": "^37.0.0"
"xdl": "38.0.0-beta.2"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming we'll release this as at-latest before we merge this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup!

},
"devDependencies": {
"babel-plugin-add-module-exports": "^0.2.1",
Expand Down
35 changes: 35 additions & 0 deletions react-native-scripts/src/util/log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import chalk from 'chalk';

let _bundleProgressBar;

function respectProgressBars(commitLogs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existence of this function makes me think that we also need to replace console.log's in other scripts, as there's a chance we may use, for example, the Expo login stuff inside of a script that needs to respect progress bars.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this more, we probably want to replace all of the console.log statements so that there's no confusion about when or where to use this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dikaiosune - so just:

let _oldConsoleLog = console.log;
console.log = log;

// implement log with _oldConsoleLog

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wfm

if (_bundleProgressBar) {
_bundleProgressBar.terminate();
_bundleProgressBar.lastDraw = '';
commitLogs();
_bundleProgressBar.render();
} else {
commitLogs();
}
}

log.setBundleProgressBar = function setBundleProgressBar(bar) {
_bundleProgressBar = bar;
};

function log() {
const prefix = chalk.dim(new Date().toLocaleTimeString()) + ':';
var args = [prefix].concat(Array.prototype.slice.call(arguments, 0));

respectProgressBars(() => {
console.log(...args);
});
}

log.withoutPrefix = function(...args) {
respectProgressBars(() => {
console.log(...args);
});
};

export default log;
141 changes: 93 additions & 48 deletions react-native-scripts/src/util/packager.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// @flow

import { Project, ProjectSettings, ProjectUtils } from 'xdl';
import { PackagerLogsStream, Project, ProjectSettings, ProjectUtils } from 'xdl';

import ProgressBar from 'progress';
import bunyan from 'bunyan';
import chalk from 'chalk';

import log from './log';

// TODO get babel output that's nice enough to let it take over the console
function clearConsole() {
process.stdout.write(process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H');
Expand All @@ -23,9 +26,10 @@ function installExitHooks(projectDir) {
}

process.on('SIGINT', () => {
console.log('\nStopping packager...');
log('\nStopping packager...');
cleanUpPackager(projectDir).then(() => {
console.log(chalk.green('Packager stopped.'));
// TODO: this shows up after process exits, fix it
log(chalk.green('Packager stopped.'));
process.exit();
});
});
Expand All @@ -52,66 +56,107 @@ function run(onReady: () => ?any, options: Object = {}) {
let packagerReady = false;
let needsClear = false;
let logBuffer = '';
let progressBar;
const projectDir = process.cwd();
ProjectUtils.attachLoggerStream(projectDir, {
stream: {
write: chunk => {
// don't show the initial packager setup, so that we can display a nice getting started message
// note: it's possible for the RN packager to log its setup before the express server is done
// this is a potential race condition but it'll work for now
if (chunk.msg.indexOf('Loading dependency graph, done.') >= 0) {
packagerReady = true;
// TODO clearConsole();
onReady();
return;
}

const messagePrefix = chalk.dim(new Date().toLocaleTimeString()) + ':';
const handleLogChunk = chunk => {
// we don't need to print the entire manifest when loading the app
if (chunk.msg.indexOf(' with appParams: ') >= 0) {
if (needsClear) {
// this is set when we previously encountered an error
// TODO clearConsole();
}
log(`Loading your app...\n`);
return;
}

if (
chunk.msg === 'Dependency graph loaded' ||
chunk.msg.indexOf('Loading dependency graph, done.') >= 0
) {
packagerReady = true;
onReady();
return;
}

// we don't need to print the entire manifest when loading the app
if (chunk.msg.indexOf(' with appParams: ') >= 0) {
if (needsClear) {
// this is set when we previously encountered an error
// TODO clearConsole();
}
console.log(`${messagePrefix} Loading your app...\n`);
return;
}
if (packagerReady) {
const message = `${chunk.msg.trim()}\n`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

such template literal much wow

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

if (chunk.level <= bunyan.INFO) {
log(message);
} else if (chunk.level === bunyan.WARN) {
log(chalk.yellow(message));
} else {
log(chalk.red(message));

if (packagerReady) {
const message = `${messagePrefix} ${chunk.msg}\n`;
if (chunk.level <= bunyan.INFO) {
console.log(message);
} else if (chunk.level === bunyan.WARN) {
console.log(chalk.yellow(message));
} else {
console.log(chalk.red(message));

// if you run into a syntax error then we should clear log output on reload
needsClear = message.indexOf('SyntaxError') >= 0;
}
} else {
if (chunk.level >= bunyan.ERROR) {
console.log(chalk.yellow('***ERROR STARTING PACKAGER***'));
console.log(logBuffer);
console.log(chalk.red(chunk.msg));
logBuffer = '';
} else {
logBuffer += chunk.msg + '\n';
}
// if you run into a syntax error then we should clear log output on reload
needsClear = message.indexOf('SyntaxError') >= 0;
}
} else {
if (chunk.level >= bunyan.ERROR) {
log.withoutPrefix(chalk.yellow('***ERROR STARTING PACKAGER***'));
log.withoutPrefix(logBuffer);
log.withoutPrefix(chalk.red(chunk.msg));
logBuffer = '';
} else {
logBuffer += chunk.msg + '\n';
}
}
};

// Subscribe to packager/server logs
let packagerLogsStream = new PackagerLogsStream({
projectRoot: projectDir,
onStartBuildBundle: () => {
progressBar = new ProgressBar('Building JavaScript bundle [:bar] :percent', {
total: 100,
clear: true,
complete: '=',
incomplete: ' ',
});

log.setBundleProgressBar(progressBar);
},
onProgressBuildBundle: percent => {
if (!progressBar || progressBar.complete) return;
let ticks = percent - progressBar.curr;
ticks > 0 && progressBar.tick(ticks);
},
onFinishBuildBundle: () => {
if (progressBar && !progressBar.complete) {
progressBar.tick(100 - progressBar.curr);
}

if (progressBar) {
log.setBundleProgressBar(null);
progressBar = null;
log(chalk.green('Finished building JavaScript bundle'));
}
},
updateLogs: updater => {
let newLogChunks = updater([]);
newLogChunks.map(handleLogChunk);
},
});

// Subscribe to device updates separately from packager/server updates
ProjectUtils.attachLoggerStream(projectDir, {
stream: {
write: chunk => {
if (chunk.tag === 'device') {
handleLogChunk(chunk);
}
},
},
type: 'raw',
});

installExitHooks(projectDir);
console.log('Starting packager...');
log('Starting packager...');

Project.startAsync(projectDir, options).then(
() => {},
reason => {
console.log(chalk.red(`Error starting packager: ${reason.stack}`));
log(chalk.red(`Error starting packager: ${reason.stack}`));
process.exit(1);
}
);
Expand Down
Loading