Skip to content

Commit

Permalink
Merge pull request #357 from infinitered/perf/startup-time
Browse files Browse the repository at this point in the history
⚡️ Improves Startup Performance, Adds 'gluegun/toolbox' for on-demand loading
  • Loading branch information
jamonholmgren committed Feb 24, 2018
2 parents e05cf94 + 8ef1230 commit da04d74
Show file tree
Hide file tree
Showing 23 changed files with 227 additions and 256 deletions.
2 changes: 1 addition & 1 deletion bin/gluegun
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ if (devMode && !wantsCompiled) {
// kick off gluegun
require(`${__dirname}/../src/cli/cli`).run(process.argv)
} else {
require(`${__dirname}/../dist/cli/cli`).run(process.argv)
require(`${__dirname}/../build/cli/cli`).run(process.argv)
}
25 changes: 25 additions & 0 deletions docs/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,31 @@ const cli = build().brand('movie')

The brand is most likely to share the same name of the CLI.

## exclude

If you don't need certain core extensions, you can skip loading them (thus improving startup time) by using `.exclude()`. Just pass in an array of string names for the core extensions you don't need. Just make sure this appears before the `.src()` command (documented below).

```js
const cli = build()
.brand('movie')
.exclude(['meta', 'strings', 'print', 'filesystem', 'semver', 'system', 'prompt', 'http', 'template', 'patching'])
```

If you find you need one of these extensions for just _one_ command but don't want to load it for _all_ of your commands, you can always load it separately from the Gluegun toolbox, like this:

```js
const { prompt } = require('gluegun/toolbox')
```

For reference, the core extensions that incur the biggest startup performance penalty are (timing varies per machine, but this gives some sense of scale):

```
prompt +100ms
print +45ms
http +30ms
system +10ms
```

## src

This sets where the default commands and extensions are located, in
Expand Down
12 changes: 12 additions & 0 deletions docs/toolbox-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,15 @@ module.exports = {
```

To learn more about each tool, explore the rest of the `toolbox-*.md` files in this folder.

## Accessing Tools Directly

You can access almost all of Gluegun's toolbox tools without running a command. This is useful when you'd like to use these tools outside of a CLI context or when doing some really specialized CLI.

```js
const { print, filesystem, strings } = require('gluegun/toolbox')

print.info(`Hey, I'm Gluegun!`)
filesystem.dir('/tmp/jamon')
print.error(strings.isBlank(''))
```
25 changes: 9 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,23 @@
"bin": {
"gluegun": "bin/gluegun"
},
"main": "dist/index.js",
"types": "dist/types/index.d.ts",
"main": "build/index.js",
"types": "build/types/index.d.ts",
"scripts": {
"precommit": "lint-staged",
"format": "prettier --write \"**/*.ts\" && tslint -p . --fix",
"clean-build": "rm -rf ./dist ./build",
"clean-build": "rm -rf ./build",
"compile": "tsc -p .",
"copy-templates": "cp -a ./src/cli/templates ./build/cli/",
"rollup": "rollup -c",
"copy-cli": "cp -a ./build/cli ./dist/",
"clean-types": "find ./dist/types -type f -size 0 -delete && find ./dist/types -type d -empty -delete",
"build": "yarn format && yarn clean-build && yarn compile && yarn copy-templates && yarn rollup && yarn copy-cli && yarn clean-types",
"clean-types": "find ./build/types -type f -size 0 -delete && find ./build/types -type d -empty -delete",
"build": "yarn format && yarn clean-build && yarn compile && yarn copy-templates && yarn clean-types",
"lint": "tslint -p .",
"test": "yarn build && ava-ts",
"test": "yarn build && ava-ts --fail-fast",
"watch": "ava-ts --watch",
"snapupdate": "ava-ts --update-snapshots",
"coverage": "nyc --reporter=lcov --reporter=html --reporter=text ava-ts",
"coveralls": "nyc ava-ts && nyc report --reporter=text-lcov | coveralls",
"shipit": "yarn build && yarn rollup && yarn lint && np --yolo"
"shipit": "yarn build && yarn lint && np --yolo"
},
"author": {
"name": "Infinite Red, Inc.",
Expand All @@ -34,7 +32,7 @@
"files": [
"docs",
"bin",
"dist",
"build",
"sniff.js",
"sniff-async.js",
"LICENSE",
Expand Down Expand Up @@ -97,11 +95,6 @@
"np": "^2.19.0",
"nyc": "^11.2.1",
"prettier": "^1.10.2",
"rollup": "^0.55.3",
"rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-filesize": "^1.5.0",
"rollup-plugin-json": "^2.3.0",
"rollup-plugin-progress": "^0.4.0",
"sinon": "^4.2.2",
"strip-ansi": "^4.0.0",
"temp-write": "^3.3.0",
Expand Down Expand Up @@ -134,4 +127,4 @@
"git add"
]
}
}
}
121 changes: 0 additions & 121 deletions rollup.config.js

This file was deleted.

3 changes: 2 additions & 1 deletion src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export async function run(argv?: string[] | string): Promise<GluegunToolbox> {
// create a CLI runtime
const cli = build()
.brand('gluegun')
.src(`${__dirname}`)
.exclude(['semver', 'prompt', 'http', 'patching'])
.src(__dirname)
.help()
.version()
.create()
Expand Down
1 change: 1 addition & 0 deletions src/core-extensions/template-extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Runtime } from '../runtime/runtime'

const createRuntime = () => {
const r = new Runtime()
r.addCoreExtensions()
r.addPlugin(`${__dirname}/../fixtures/good-plugins/generate`)
return r
}
Expand Down
11 changes: 11 additions & 0 deletions src/domain/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import { GluegunLoadOptions, GluegunMultiLoadOptions } from './options'
*/
export class Builder {
public readonly runtime: Runtime
public excludes: string[]

constructor() {
this.runtime = new Runtime()
this.excludes = []
}

/**
Expand All @@ -28,6 +30,14 @@ export class Builder {
return this
}

/**
* Excludes core libraries if they're not needed, for performance reasons.
*/
public exclude(excludes: string[]) {
this.excludes = excludes
return this
}

/**
* Specifies where the default commands and extensions live.
*
Expand All @@ -36,6 +46,7 @@ export class Builder {
* @return self.
*/
public src(value: string, options: GluegunLoadOptions = {}): Builder {
this.runtime.addCoreExtensions(this.excludes)
this.runtime.addDefaultPlugin(value, options)
return this
}
Expand Down
53 changes: 0 additions & 53 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,56 +10,3 @@ test('create', t => {
.create()
t.is(runtime.brand, 'test')
})

test('print', t => {
t.is(typeof exported.print.printCommands, 'function')
t.is(typeof exported.print.info, 'function')
})

test('strings', t => {
t.is(exported.strings.lowerCase('HI'), 'hi')
})

test('filesystem', t => {
t.truthy(exported.filesystem)
t.truthy(exported.filesystem.eol)
t.truthy(exported.filesystem.separator)
t.is(exported.filesystem.cwd(), process.cwd())
})

test('system', t => {
t.truthy(exported.system)
t.truthy(exported.system.which('node'))
})

test('prompt', t => {
t.truthy(exported.prompt)
t.truthy(typeof exported.prompt.confirm, 'function')
})

test('http', t => {
t.truthy(exported.http)
t.truthy(typeof exported.http.create, 'function')
const api = exported.http.create({ baseURL: 'https://api.github.com/v3' })
t.is(typeof api.get, 'function')
t.is(typeof api.post, 'function')
})

test('generate', async t => {
t.truthy(exported.template)
const actual = await exported.template.generate({
template: './src/fixtures/good-plugins/generate/templates/simple.ejs',
directory: process.cwd(),
})
t.is(actual, 'simple file\n')
})

test('patching', t => {
t.truthy(exported.patching)
t.truthy(typeof exported.patching.exists, 'function')
t.truthy(typeof exported.patching.update, 'function')
t.truthy(typeof exported.patching.append, 'function')
t.truthy(typeof exported.patching.prepend, 'function')
t.truthy(typeof exported.patching.replace, 'function')
t.truthy(typeof exported.patching.patch, 'function')
})
36 changes: 0 additions & 36 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,6 @@ process.on('unhandledRejection', up => {
throw up
})

// bring in a few extensions to make available for stand-alone purposes
import attachStringsExtension from './core-extensions/strings-extension'
import attachPrintExtension from './core-extensions/print-extension'
import attachFilesystemExtension from './core-extensions/filesystem-extension'
import attachSemverExtension from './core-extensions/semver-extension'
import attachSystemExtension from './core-extensions/system-extension'
import attachPromptExtension from './core-extensions/prompt-extension'
import attachHttpExtension from './core-extensions/http-extension'
import attachTemplateExtension from './core-extensions/template-extension'
import attachPatchingExtension from './core-extensions/patching-extension'

// export the `build` command
export { build } from './domain/builder'

Expand Down Expand Up @@ -59,28 +48,3 @@ export {
// it's hacky, but it works well!
require('app-module-path').addPath(`${__dirname}/../node_modules`)
require('app-module-path').addPath(process.cwd())

// build a temporary toolbox to hang things on
const toolbox: any = {}

attachStringsExtension(toolbox)
attachPrintExtension(toolbox)
attachFilesystemExtension(toolbox)
attachSemverExtension(toolbox)
attachSystemExtension(toolbox)
attachPromptExtension(toolbox)
attachHttpExtension(toolbox)
attachTemplateExtension(toolbox)
attachPatchingExtension(toolbox)

// some functions are available if you just `import { <things> } from 'gluegun'` directly
export const filesystem: GluegunFilesystem = toolbox.filesystem
export const semver: GluegunSemver = toolbox.semver
export const system: GluegunSystem = toolbox.system
export const prompt: GluegunPrompt = toolbox.prompt
export const http: GluegunHttp = toolbox.http
export const template: GluegunTemplate = toolbox.template
export const patching: GluegunPatching = toolbox.patching
export const print: GluegunPrint = toolbox.print
export const generate = toolbox.generate
export const strings: GluegunStrings = toolbox.strings
Loading

0 comments on commit da04d74

Please sign in to comment.