Babel timing
Measure Babel compilation time file by file, plugin by plugin.
Profile Babel when your application or your tests take ages to build.
Note: this tool is in version 0, any minor release might introduce breaking changes.
Installation
npm i babel-timing -D
yarn add babel-timing -D
Usage
As standalone library via CLI
babel-timing path/to/file-1.js path/to/file-2.js
babel-timing path/to/file-*.js
babel-timing path/to/entrypoint.js --follow-imports
As standalone library via Node
const { babelTiming } = require('babel-timing');
const results = await babelTiming(['path/to/file.js'], options);
As Webpack integration
Profile Babel during the actual Webpack bundling process.
- Import
babel-timing/webpack/plugin
to Webpack configuration:
const BabelTimingPlugin = require('babel-timing/webpack/plugin');
- Add
customize
option to the existing babel-loader
configuration:
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: 'babel-loader',
options: {
customize: require.resolve(
'babel-timing/webpack/babel-loader-customize'
),
},
},
},
];
}
- Add
babel-timing/webpack/plugin
plugin (accepts the render options):
plugins: [new BabelTimingPlugin()];
...with options (accepts output
and outputPath
options):
plugins: [
new BabelTimingPlugin({ output: 'json', outputPath: './results.json' }),
];
-
Delete babel-loader
cache at ./node_modules/.cache/babel-loader/
-
Start Webpack bundling process and wait for results
As Jest integration
Profile Babel while running your actual Jest tests.
- Add the following
transform
and reporters
entries to the existing Jest configuration:
{
transform: {
'^.+\\.jsx?$': 'babel-timing/jest/transformer'
},
reporters: [
'default',
'babel-timing/jest/reporter'
]
}
...with reporter's options (accepts the render options):
{
reporters: [
'default',
[
'babel-timing/jest/reporter',
{ output: 'json', outputPath: './results.json' },
],
];
}
- Run tests with
--no-cache
option
Further integrations
Options
babelConfig
/ --babel-config
Type: string | false
Default: false
Path to a custom babel configuration file. By default Babel will try to load any existing valid configuration file.
followImports
/ --follow-imports
Type: bool
Default: false
Follow imported files/modules and run babel-timing
against them.
include
/ --include
Type: string[]
(cli accepts a string containing a comma-separated list)
Default: ['**']
Include paths (imported ones also) according to the provided glob patterns.
exclude
/ --exclude
Type: string[]
(cli accepts a string containing a comma-separated list)
Default: ['**/node_modules/**']
Exclude paths (imported ones also) according to the provided glob patterns.
resolveMainFields
/ --resolve-main-fields
Type: string[]
(cli accepts a string containing a comma-separated list)
Default: ['browser', 'module', 'main']
When importing from an npm package this option will determine which fields in its package.json
are checked.
resolveExtensions
/ --resolve-extensions
Type: string[]
(cli accepts a string containing a comma-separated list)
Default: ['.js', '.jsx', '.mjs', '.ts']
Attempt to resolve these extensions in order. Any other extension won't be considered.
--read-results
(CLI only, for Node use render
API)
Type: string
Default: undefined
Skip compilation and render existing results from file at specified path.
Render options
output
/ --output
Type: string
Default: "return"
("console"
when called via CLI or integrations)
Options: "return"
, "console"
, "json"
Make babel-timing
results available as:
"return"
return results' object"console"
render results in console"json"
save results as babel-timing-results.json
outputPath
/ --output-path
Type: string
Default: "./babel-timing-results.json"
Path of output file in case output
option is set to "json"
.
Type: number
Default: 10
Number of entries displayed in a page when rendering "console"
output.
aggregateBy
/ --aggregate-by
Type: string
Default: "files"
Options: "files"
, "plugins"
Output results aggregated by files
or plugins
.
expandPackages
/ --expand-packages
Type: bool
Default: false
Expand results relative to node_modules
packages file by file.
How it works
Compile files with Babel 7 and get collect compilation info through wrapPluginVisitorMethod
Babel config option.
ResultList
Compilation info are by default extracted into the following data structure:
type ResultList = {
name: string;
time: number;
plugins: {
name: string;
time: number;
timePerVisit: number;
visits: number;
}[];
}[];
Notes
This tool started as an attempt of measuring the time taken by Babel while running transpiled tests and compiling Webpack applications.
The main difficulty of monitoring Babel while running the aforementioned tools, consists of relating the wrapPluginVisitorMethod
calls to the files actually being compiled.
Any further idea/contribution to get to a better Babel profiling solution is welcome.
Manual tests :)
node cli.js __fixtures__/file-1.js
node cli.js __fixtures__/file-1.js __fixtures__/file-2.js
node cli.js __fixtures__/*.js
node cli.js __fixtures__/entry.js --follow-imports
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
, keep track of transform times and return a ResultList
entry object for a given file.
const { Timer } = require('babel-timing');
const timer = new Timer(fileName);
timer.wrapPluginVisitorMethod;
timer.getResults();
timersCollection
Utility function meant to temporarily store Timer
instances into a Node module while Babel compiles.
const { timersCollection } = require('babel-timing');
timersCollection.getFile(fileName);
timersCollection.getAll();
timersCollection.clear();
render(ResultList, options)
Accepts a ResultList
array and renders an interactive CLI visualisation or outputs a JSON file of it.
const { render } = require('babel-timing');
render(babelTimingResults, { options });
Accepts the render options.
Thanks to
Todo
- Add
csv
output option - Provide a wider set of integrations (
rollup
, babelify
, parcel
, ...) - Improve existing integrations
- Consider versioning results JSON data shape
- Consider splitting standalone feature from core and integrations