Skip to content

Commit

Permalink
feat: significantly improve CLI startup times (#42)
Browse files Browse the repository at this point in the history
Move a few heavier modules from static imports to lazy `require()`s.
Also remove support for globally installed addons via yarn *and* npm.
If Yarn is detected, Denali will search Yarn for global addons, otherwise
it wills search npm, but not both. This lets Yarn users avoid the
delays that npm forces (because we need to shell out for `npm root`, which
eats 500ms).

We could make this behavior configurable in the future, once we have
a ~/.denali config file
  • Loading branch information
davewasmer committed Jan 31, 2018
1 parent 54f2573 commit a511d66
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 15 deletions.
23 changes: 12 additions & 11 deletions lib/find-addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,7 @@ export default function findAddons(isLocal: boolean): AddonSummary[] {
return finalizeAddons(addons);
}

let npmRoot = execSync('npm root -g').toString().trim();
debug(`searching for addons globally in npm root: ${ npmRoot }`);
let addons = findPlugins(merge({
dir: npmRoot,
scanAllDirs: true
}, findOptions));
let addons;

// Because yarn stores it's global modules separately, and doesn't yet support the `root` command,
// we have to double check yarn's global installs for any denali addons. The easiest way of
Expand All @@ -52,13 +47,12 @@ export default function findAddons(isLocal: boolean): AddonSummary[] {
// development of global addons (like denali itself)
// TODO shell out to `yarn root` once yarnpkg/yarn#2388 is fixed
if (commandExists('yarn')) {
let yarnGlobalInstalls = path.join(YarnConstants.GLOBAL_MODULE_DIRECTORY, 'node_modules');
let yarnGlobalInstalls = YarnConstants.GLOBAL_MODULE_DIRECTORY;
debug(`searching for addons globally in yarn global installs: ${ yarnGlobalInstalls }`);
if (fs.existsSync(yarnGlobalInstalls)) {
addons = addons.concat(findPlugins(merge({
dir: yarnGlobalInstalls,
scanAllDirs: true
}, findOptions)));
addons = findPlugins(merge({
dir: yarnGlobalInstalls
}, findOptions));
} else {
debug(`Tried to load globally installed addons from yarn, but ${ yarnGlobalInstalls } doesn't exist, skipping ...`);
}
Expand All @@ -72,6 +66,13 @@ export default function findAddons(isLocal: boolean): AddonSummary[] {
} else {
debug(`Tried to load globally linked addons from yarn, but ${ yarnGlobalLinks } doesn't exist, skipping ...`);
}
} else {
let npmRoot = execSync('npm root -g').toString().trim();
debug(`searching for addons globally in npm root: ${ npmRoot }`);
addons = findPlugins(merge({
dir: npmRoot,
scanAllDirs: true
}, findOptions));
}

return finalizeAddons(addons);
Expand Down
10 changes: 6 additions & 4 deletions lib/project.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as path from 'path';
import { Tree, Builder as Broccoli, BuildResults } from 'broccoli';
// import { Tree, Builder as Broccoli, BuildResults } from 'broccoli';
import * as rimraf from 'rimraf';
import printSlowNodes from 'broccoli-slow-trees';
import { sync as copyDereferenceSync } from 'copy-dereference';
Expand Down Expand Up @@ -81,11 +81,12 @@ export default class Project {
}

// TODO build descriptions
async _build(tree: Tree, destDir: string): Promise<void> {
async _build(tree: any, destDir: string): Promise<void> {
try {
debug('building project');
let timer = startTimer();
spinner.start(`Building ...`);
const Broccoli = require('broccoli').Builder;
let broccoli = new Broccoli(tree);
let results = await broccoli.build();
await this.finishBuild(results, destDir);
Expand Down Expand Up @@ -116,9 +117,10 @@ export default class Project {
/**
* Build the project and start watching the source files for changes, rebuilding when they occur
*/
async _watch(tree: Tree, options: WatchOptions = {}) {
async _watch(tree: any, options: WatchOptions = {}) {
spinner.start(`Watching ...`);
let timer = startTimer();
const Broccoli = require('broccoli').Builder;
let broccoli = new Broccoli(tree);
let watcher = new Watcher(broccoli, { beforeRebuild: options.beforeRebuild, interval: 100 });
let destDir = options.destDir || path.join(this.dir, 'dist');
Expand Down Expand Up @@ -192,7 +194,7 @@ export default class Project {
* After a build completes, this method cleans up the result. It copies the results out of tmp and
* into the output directory, and kicks off any optional behaviors post-build.
*/
finishBuild(results: BuildResults, destDir: string) {
finishBuild(results: { directory: string, graph: any }, destDir: string) {
debug(`copying broccoli build output to dist`);
rimraf.sync(destDir);
copyDereferenceSync(path.resolve(results.directory), destDir);
Expand Down

0 comments on commit a511d66

Please sign in to comment.