babel-timing
Advanced tools
Comparing version 0.4.0 to 0.5.0
# Changelog | ||
## 0.5.0 | ||
### New Features | ||
- Expose and document library's internals: `Timer`, `timersCollection` and `render` | ||
- Paginate both interactive CLI pages and review output style | ||
## 0.4.0 | ||
@@ -36,3 +43,3 @@ | ||
## Minor changes | ||
### Minor changes | ||
@@ -39,0 +46,0 @@ - Follow imports with Rollup.js |
#!/usr/bin/env node | ||
const program = require('commander'); | ||
const babelTiming = require('./src').babelTiming; | ||
const {babelTiming} = require('./src'); | ||
const pkg = require('./package.json'); | ||
@@ -38,2 +38,6 @@ | ||
.option('--output-path <path>', 'path of output file') | ||
.option( | ||
'--pagination-size <number-of-entries>', | ||
'number of entries displayed per page' | ||
) | ||
.option('--verbose', 'log warnings') | ||
@@ -53,4 +57,5 @@ .parse(process.argv); | ||
outputPath, | ||
paginationSize, | ||
verbose, | ||
} = program) | ||
); |
@@ -1,13 +0,12 @@ | ||
const {getAllTimers, clearAllTimers} = require('./babelTimers'); | ||
const render = require('../src/render'); | ||
const {render, timersCollection} = require('../src'); | ||
// https://jestjs.io/docs/en/configuration#reporters-array-modulename-modulename-options | ||
class MyCustomReporter { | ||
constructor(globalConfig, {output = 'console', outputPath} = {}) { | ||
this._options = {output, outputPath}; | ||
constructor(globalConfig, {output = 'console', ...otherOptions} = {}) { | ||
this._options = {output, ...otherOptions}; | ||
} | ||
onRunComplete() { | ||
const results = getAllTimers().map(entry => entry[1].getResults()); | ||
clearAllTimers(); | ||
const results = timersCollection.getAll().map(timer => timer.getResults()); | ||
timersCollection.clear(); | ||
@@ -14,0 +13,0 @@ // Render output after Jest's pending async operations check |
const babelJest = require('babel-jest'); | ||
const {getFileTimer} = require('./babelTimers'); | ||
const {timersCollection} = require('../src'); | ||
@@ -11,3 +11,4 @@ // Keep track of the file currently being traspiled in current module scope :-( | ||
wrapPluginVisitorMethod: (...args) => { | ||
const visitorWrapper = getFileTimer(currentFile).wrapPluginVisitorMethod; | ||
const visitorWrapper = timersCollection.getTimer(currentFile) | ||
.wrapPluginVisitorMethod; | ||
return visitorWrapper(...args); | ||
@@ -14,0 +15,0 @@ }, |
{ | ||
"name": "babel-timing", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Measure Babel compilation time", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -31,3 +31,3 @@ # Babel timing | ||
```js | ||
const babelTiming = require('babel-timing').babelTiming; | ||
const {babelTiming} = require('babel-timing'); | ||
const results = await babelTiming(['path/to/file.js'], options); | ||
@@ -64,3 +64,3 @@ ``` | ||
3. Add `babel-timing/webpack/plugin` plugin _(accepts `output` and `outputPath` options)_: | ||
3. Add `babel-timing/webpack/plugin` plugin _(accepts the [render options][render-options])_: | ||
@@ -81,2 +81,4 @@ ```js | ||
4. Consider deleting `babel-loader` cache at `./node_modules/.cache/babel-loader/` | ||
### As Jest integration | ||
@@ -100,3 +102,3 @@ | ||
...with **reporter's options** _(accepts `output` and `outputPath` options)_: | ||
...with **reporter's options** _(accepts the [render options][render-options])_: | ||
@@ -117,2 +119,6 @@ ```js | ||
### Further integrations | ||
- [Hops](./FURTHER-INTEGRATIONS.md#hops) | ||
## Options | ||
@@ -155,2 +161,11 @@ | ||
#### `verbose` / `--verbose` | ||
Type: `bool`<br /> | ||
Default: `false` | ||
Log warnings. | ||
### Render options | ||
#### `expandPackages` / `--expand-packages` | ||
@@ -182,14 +197,13 @@ | ||
#### `verbose` / `--verbose` | ||
#### `paginationSize` / `--pagination-size` | ||
Type: `number`<br /> | ||
Default: `10` | ||
Type: `bool`<br /> | ||
Default: `false` | ||
Number of entries displayed in a page when rendering `"console"` output. | ||
Log warnings. | ||
## How it works | ||
Compile files with **Babel 7** and get **collect compilation info** through [`wrapPluginVisitorMethod`](https://babeljs.io/docs/en/options#wrappluginvisitormethod) Babel config option. | ||
Compile files with **Babel 7** and get **collect compilation info** through [`wrapPluginVisitorMethod`][wrappluginvisitormethod-docs] Babel config option. | ||
### Results | ||
### ResultList | ||
@@ -199,3 +213,3 @@ **Compilation info** are extracted into the following data **structure**: | ||
```typescript | ||
type Results = { | ||
type ResultList = { | ||
name: string; | ||
@@ -229,2 +243,48 @@ totalTime: number; | ||
## API's | ||
These API's are meant to integrate `babel-timing` with any bundler/tool using Babel. | ||
### new Timer(filename) | ||
`Timer` class returns timer instances used to hook Babel's [`wrapPluginVisitorMethod`][wrappluginvisitormethod-docs], keep track of transform times and return a [`ResultList`][resultlist] entry object for a given file. | ||
```js | ||
const {Timer} = require('babel-timing'); | ||
const timer = new Timer(fileName); | ||
// This is the function to be provided to Babel's "wrapPluginVisitorMethod" option | ||
timer.wrapPluginVisitorMethod; | ||
// Called after Babel transformations, returns "Results" object for given file | ||
timer.getResults(); | ||
``` | ||
### timersCollection | ||
Utility function meant to temporarily store `Timer` instances into a Node module while Babel compiles. | ||
```js | ||
const {timersCollection} = require('babel-timing'); | ||
// Returns Timer instance for given file. Creates a new `Timer` instance if no timer for given file is found | ||
timersCollection.getFile(fileName); | ||
// Returns an array containing all the stored Timer instances | ||
timersCollection.getAll(); | ||
timersCollection.clear(); | ||
``` | ||
### render(ResultList, options) | ||
Accepts a `ResultList` array and renders an interactive CLI visualisation or outputs a JSON file of it. | ||
```js | ||
const {render} = require('babel-timing'); | ||
render(babelTimingResults, {options}); | ||
``` | ||
Accepts the [render options][render-options]. | ||
## Thanks to | ||
@@ -240,9 +300,10 @@ | ||
- Add `csv` output option | ||
- Expose `wrapPluginVisitorMethod` | ||
- Provide a wider set of integrations (`rollup`, `parcel`, ...) | ||
- Provide a wider set of integrations (`rollup`, `babelify`, `parcel`, ...) | ||
- Improve existing integrations | ||
- Make `followImports` more reliable | ||
- Consider paginating `PluginList` output | ||
[ci-badge]: https://travis-ci.org/toomuchdesign/babel-timing.svg?branch=master | ||
[ci]: https://travis-ci.org/toomuchdesign/babel-timing | ||
[wrappluginvisitormethod-docs]: https://babeljs.io/docs/en/options#wrappluginvisitormethod | ||
[render-options]: #render-options | ||
[resultlist]: #resultList |
module.exports = { | ||
babelTiming: require('./babelTiming'), | ||
babelTiming: require('./standalone'), | ||
Timer: require('./Timer'), | ||
timersCollection: require('./timersCollection'), | ||
render: require('./render'), | ||
}; |
const Table = require('cli-table3'); | ||
var colors = require('colors/safe'); | ||
var chunkArray = require('lodash.chunk'); | ||
const Pagination = require('./Pagination'); | ||
const {valueInRange} = require('../../utils'); | ||
@@ -9,2 +9,3 @@ | ||
results = [], | ||
selected = 0, | ||
paginationSize = 10, | ||
@@ -17,9 +18,8 @@ onSelected = () => {}, | ||
this.diff = diff; | ||
this.selected = selected % paginationSize; | ||
this.paginationSize = paginationSize; | ||
this.selected = 0; | ||
this.page = 0; | ||
this.onKeyPress = this.onKeyPress.bind(this); | ||
// Prepare data for rendering | ||
this.pagedResults = this.results.map((result, index) => [ | ||
const pagedResults = this.results.map((result, index) => [ | ||
index + 1, | ||
@@ -29,4 +29,9 @@ result.name, | ||
]); | ||
this.pagedResults = chunkArray(this.pagedResults, paginationSize); | ||
this.pagination = new Pagination({ | ||
items: pagedResults, | ||
itemsPerPage: paginationSize, | ||
}); | ||
this.pagination.goToItemPage(selected); | ||
process.stdin.on('keypress', this.onKeyPress); | ||
@@ -36,12 +41,5 @@ this.render(); | ||
getTotalPages() { | ||
return this.pagedResults.length; | ||
} | ||
getTotalEntriesInPage(pageNumber) { | ||
return this.pagedResults[pageNumber].length; | ||
} | ||
getSelectedEntryIndex() { | ||
return this.paginationSize * this.page + this.selected; | ||
const currentPage = this.pagination.getCurrentPage(); | ||
return this.paginationSize * currentPage + this.selected; | ||
} | ||
@@ -91,3 +89,3 @@ | ||
this.selected = valueInRange(this.selected + 1, { | ||
max: this.getTotalEntriesInPage(this.page) - 1, | ||
max: this.pagination.countItemsInCurrentPage() - 1, | ||
}); | ||
@@ -98,15 +96,15 @@ this.render(); | ||
previousPage() { | ||
this.page = valueInRange(this.page - 1, { | ||
min: 0, | ||
}); | ||
this.selected = 0; | ||
this.render(); | ||
if (this.pagination.hasPreviousPage()) { | ||
this.pagination.previousPage(); | ||
this.selected = 0; | ||
this.render(); | ||
} | ||
} | ||
nextPage() { | ||
this.page = valueInRange(this.page + 1, { | ||
max: this.getTotalPages() - 1, | ||
}); | ||
this.selected = 0; | ||
this.render(); | ||
if (this.pagination.hasNextPage()) { | ||
this.pagination.nextPage(); | ||
this.selected = 0; | ||
this.render(); | ||
} | ||
} | ||
@@ -123,8 +121,10 @@ | ||
render() { | ||
const table = new Table({head: ['', 'File', 'Total time(ms)']}); | ||
const resultPage = this.pagedResults[this.page]; | ||
const table = new Table({ | ||
head: ['', 'File', 'Total time(ms)'].map(entry => colors.yellow(entry)), | ||
}); | ||
const items = this.pagination.getCurrentItems(); | ||
table.push( | ||
...resultPage.map((row, index) => { | ||
...items.map((row, index) => { | ||
if (index === this.selected) { | ||
return row.map(entry => colors.green(entry)); | ||
return row.map(entry => colors.yellow.underline(entry)); | ||
} | ||
@@ -136,8 +136,10 @@ return row; | ||
const output = | ||
`${this.results.length} results | page ${this.page + | ||
1}/${this.getTotalPages()}` + | ||
'\n' + | ||
colors.yellow('Babel timing - trasformed files') + | ||
'\n' + | ||
this.pagination.getInfo() + | ||
'\n' + | ||
table.toString() + | ||
'\n' + | ||
'← prev page | → next page | ↑↓ select file | ↩ show entry details'; | ||
'← prev page | → next page | ↑↓ select file | ↩ show file details'; | ||
@@ -144,0 +146,0 @@ this.diff.write(output); |
const Table = require('cli-table3'); | ||
var colors = require('colors/safe'); | ||
const Pagination = require('./Pagination'); | ||
class PluginList { | ||
constructor({results = {}, onBack = () => {}, diff} = {}) { | ||
constructor({results = {}, paginationSize, onBack = () => {}, diff} = {}) { | ||
this.results = results; | ||
@@ -11,3 +13,4 @@ this.onBack = onBack; | ||
// Make data suitable for rendering | ||
this.pagedPlugins = this.results.plugins.map(result => [ | ||
const pagedPlugins = results.plugins.map((result, index) => [ | ||
index + 1, | ||
result.plugin, | ||
@@ -19,2 +22,7 @@ result.time.toFixed(3), | ||
this.pagination = new Pagination({ | ||
items: pagedPlugins, | ||
itemsPerPage: paginationSize, | ||
}); | ||
process.stdin.on('keypress', this.onKeyPress); | ||
@@ -31,5 +39,10 @@ this.render(); | ||
case 'escape': | ||
case 'left': | ||
return this.onBack(); | ||
case 'left': | ||
return this.previousPage(); | ||
case 'right': | ||
return this.nextPage(); | ||
case 'c': { | ||
@@ -45,2 +58,12 @@ if (key.ctrl) { | ||
previousPage() { | ||
this.pagination.previousPage(); | ||
this.render(); | ||
} | ||
nextPage() { | ||
this.pagination.nextPage(); | ||
this.render(); | ||
} | ||
clear() { | ||
@@ -56,12 +79,20 @@ this.diff.clear(); | ||
const table = new Table({ | ||
head: ['pluginAlias', 'time(ms)', 'visits', 'time/visit(ms)'], | ||
head: ['', 'pluginAlias', 'time(ms)', 'visits', 'time/visit(ms)'].map( | ||
entry => colors.yellow(entry) | ||
), | ||
}); | ||
table.push(...this.pagedPlugins); | ||
const items = this.pagination.getCurrentItems(); | ||
table.push(...items); | ||
const output = | ||
`File: ${this.results.name}` + | ||
'\n' + | ||
colors.yellow('Babel timing - info for file:') + | ||
'\n' + | ||
colors.yellow(this.results.name) + | ||
'\n' + | ||
this.pagination.getInfo() + | ||
'\n' + | ||
table.toString() + | ||
'\n' + | ||
'← ESC back to result list'; | ||
'← prev page | → next page | ESC back to results list'; | ||
@@ -68,0 +99,0 @@ this.diff.write(output); |
@@ -6,3 +6,3 @@ var differ = require('ansi-diff-stream'); | ||
function renderFileList(results, selected = 0, diff) { | ||
function renderFileList({results, selected = 0, diff, paginationSize} = {}) { | ||
const output = new FileList({ | ||
@@ -14,9 +14,10 @@ results, | ||
output.stop(); | ||
renderPluginList(results, selected, diff); | ||
renderPluginList({results, resultIndex: selected, diff, paginationSize}); | ||
}, | ||
diff, | ||
paginationSize, | ||
}); | ||
} | ||
function renderPluginList(results, resultIndex, diff) { | ||
function renderPluginList({results, resultIndex, diff, paginationSize} = {}) { | ||
const output = new PluginList({ | ||
@@ -27,9 +28,10 @@ results: results[resultIndex], | ||
output.stop(); | ||
renderFileList(results, resultIndex, diff); | ||
renderFileList({results, selected: resultIndex, diff, paginationSize}); | ||
}, | ||
diff, | ||
paginationSize, | ||
}); | ||
} | ||
function renderer(results = []) { | ||
function renderer(results = [], {paginationSize} = {}) { | ||
enableKeyPressEvent(); | ||
@@ -41,5 +43,9 @@ | ||
renderFileList(results, undefined, diff); | ||
renderFileList({ | ||
results, | ||
diff, | ||
paginationSize, | ||
}); | ||
} | ||
module.exports = renderer; |
@@ -13,2 +13,3 @@ const path = require('path'); | ||
outputPath = './babel-timing-results.json', | ||
paginationSize, | ||
} = {} | ||
@@ -26,3 +27,3 @@ ) { | ||
case 'console': { | ||
cliRenderer(results); | ||
cliRenderer(results, {paginationSize}); | ||
return; | ||
@@ -29,0 +30,0 @@ } |
const mergeWith = require('lodash.mergewith'); | ||
const PluginsTimer = require('../../PluginsTimer'); | ||
const Timer = require('../../Timer'); | ||
const {onlyUnique} = require('../../utils'); | ||
@@ -18,3 +18,3 @@ | ||
if (key === 'plugins') { | ||
return PluginsTimer.mergeResults(objValue, srcValue); | ||
return Timer.mergeResults(objValue, srcValue); | ||
} | ||
@@ -21,0 +21,0 @@ if (typeof objValue === 'string') { |
@@ -1,3 +0,2 @@ | ||
const PluginsTimer = require('../src/PluginsTimer'); | ||
let timers = []; | ||
const {timersCollection} = require('../src'); | ||
@@ -9,4 +8,3 @@ // https://github.com/babel/babel-loader#example | ||
config(cfg) { | ||
const timer = new PluginsTimer(cfg.options.filename); | ||
timers.push(timer); | ||
const timer = timersCollection.getTimer(cfg.options.filename); | ||
return { | ||
@@ -20,15 +18,2 @@ ...cfg.options, | ||
function getTimers() { | ||
return [...timers]; | ||
} | ||
function clearTimers() { | ||
timers = []; | ||
} | ||
module.exports = { | ||
default: babelLoaderCustomize, | ||
getTimers: getTimers, | ||
clearTimers: clearTimers, | ||
__esModule: true, | ||
}; | ||
module.exports = babelLoaderCustomize; |
@@ -1,10 +0,9 @@ | ||
const render = require('../src/render'); | ||
const {getTimers, clearTimers} = require('./babel-loader-customize'); | ||
const {render, timersCollection} = require('../src'); | ||
// https://webpack.js.org/api/plugins/ | ||
class BabelTimingPlugin { | ||
constructor({output = 'console', outputPath} = {}) { | ||
constructor({output = 'console', ...otherOptions} = {}) { | ||
this._options = { | ||
output, | ||
outputPath, | ||
...otherOptions, | ||
}; | ||
@@ -15,4 +14,7 @@ } | ||
compiler.hooks.done.tap('Babel timing Plugin', stats => { | ||
const results = getTimers().map(timer => timer.getResults()); | ||
clearTimers(); | ||
const results = timersCollection | ||
.getAll() | ||
.map(timer => timer.getResults()); | ||
timersCollection.clear(); | ||
if (this._options.output === 'console') { | ||
@@ -19,0 +21,0 @@ setImmediate(() => { |
63433
5720
27
805
300