Skip to content

Commit 97b82d1

Browse files
authored
Merge pull request #5 from doesdev/2.0.0
2.0.0
2 parents 96b1cde + ee6a7dd commit 97b82d1

6 files changed

Lines changed: 238 additions & 154 deletions

File tree

README.md

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ $ npm install --save-dev rollup-analyzer
2929
## Usage
3030

3131
```js
32-
const rollupAnalyzer = require('rollup-analyzer')({limit: 5})
33-
rollup.rollup({/*...*/}).then((bundle) => {
32+
import { rollup } from 'rollup'
33+
const { formatted } from 'rollup-analyzer'
34+
35+
rollup({/*...*/}).then((bundle) => {
3436
// print console optimized analysis string
35-
rollupAnalyzer.formatted(bundle).then(console.log).catch(console.error)
37+
formatted(bundle, {limit: 5}).then(console.log).catch(console.error)
3638
})
3739

3840
// Results in ...
@@ -59,12 +61,27 @@ dependents: 1
5961

6062
## API
6163

62-
### rollupAnalyzer
63-
the default exported function is identical to init, and returns the same functions as export {init, formatted, analyze}. So, you can `require('rollup-analyzer')` or `require('rollup-analyzer')({limit: 5})` and use the same functions.
64-
65-
### rollupAnalyzer.init(options)
66-
set options to use in analysis (this step is optional)
67-
- **options** *(Object)*
64+
Module exports `analyze`, `formatted`, and `plugin` functions
65+
66+
### formatted(bundle, options)
67+
- arguments
68+
- **bundle** *(Rollup Bundle)*
69+
- **options** *(Object - see below for available options)*
70+
- returns
71+
- **analysisText** *(String - well formatted for console printing)*
72+
73+
### analyze(bundle, options)
74+
- arguments
75+
- **bundle** *(Rollup Bundle)*
76+
- **options** *(Object - see below for available options)*
77+
- returns
78+
- **analysis** *(Object)*
79+
- **id** *(String)* - path of module / rollup module id
80+
- **size** *(Number)* - size of module in bytes
81+
- **dependents** *(Array)* - list of dependent module ids / paths
82+
- **percent** *(Number)* - percentage of module size relative to entire bundle
83+
84+
#### options `Object`
6885
- **limit** - *optional*
6986
- type: Number
7087
- default: `null`
@@ -78,20 +95,6 @@ set options to use in analysis (this step is optional)
7895
- default: `process.cwd()`
7996
- description: Application directory, used to display file paths relatively
8097

81-
### rollupAnalyzer.formatted(bundle)
82-
returns Promise which resolves with well formatted analysis string (for CLI printing)
83-
- **bundle** *(Rollup Bundle)* - *required*
84-
85-
### rollupAnalyzer.analyze(bundle)
86-
returns Promise which resolves with array of objects describing each imported file
87-
- **bundle** *(Rollup Bundle)* - *required*
88-
89-
returned array's child analysis objects have the following properties
90-
- **id** *(String)* - path of module / rollup module id
91-
- **size** *(Number)* - size of module in bytes
92-
- **dependents** *(Array)* - list of dependent module ids / paths
93-
- **percent** *(Number)* - percentage of module size relative to entire bundle
94-
9598
## License
9699

97100
MIT © [Andrew Carpenter](https://github.com/doesdev)

index.js

Lines changed: 77 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
'use strict';
22

3-
// Setup
3+
Object.defineProperty(exports, '__esModule', { value: true });
4+
45
const buf = ' ';
56
const tab = ' ';
67
const borderX = `${Array(30).join('-')}\n`;
7-
let proc = process;
8-
let root = proc && proc.cwd ? proc.cwd() : null;
9-
let limit, filter;
10-
11-
// Helpers
128
const formatBytes = (bytes) => {
139
if (bytes === 0) return '0 Byte'
1410
let k = 1000;
@@ -18,63 +14,112 @@ const formatBytes = (bytes) => {
1814
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
1915
};
2016

21-
// Main
22-
function init (opts) {
23-
opts = opts || {};
24-
limit = opts.limit;
25-
filter = opts.filter;
26-
root = opts.root || root;
27-
}
28-
29-
function analyzer (opts) {
30-
init(opts);
31-
return {init, formatted, analyze}
32-
}
33-
analyzer.init = init;
34-
analyzer.formatted = formatted;
35-
analyzer.analyze = analyze;
36-
37-
function formatted (bndl) { return analyze(bndl, true) }
38-
39-
function analyze (bundle, format) {
17+
const analyze = (bundle, opts = {}, format = false) => {
18+
let { root, limit, filter } = opts;
4019
let deps = {};
20+
let entrySize;
4121
let bundleSize = 0;
22+
let bundleModules = bundle.modules;
23+
4224
return new Promise((resolve, reject) => {
43-
let modules = bundle.modules.map((m, i) => {
44-
let id = m.id.replace(root, '');
45-
let size = Buffer.byteLength(m.code, 'utf8') || 0;
25+
let modules = bundleModules.map((m, i) => {
26+
let { id, originalLength: origSize, renderedLength, isEntry, code } = m;
27+
id = id.replace(root, '');
28+
let size = renderedLength;
29+
if (!size && size !== 0) size = code ? Buffer.byteLength(code, 'utf8') : 0;
30+
if (isEntry) entrySize = size;
4631
bundleSize += size;
32+
4733
if (Array.isArray(filter) && !filter.some((f) => id.match(f))) return null
48-
else if (typeof filter === 'string' && !id.match(filter)) return null
34+
if (typeof filter === 'string' && !id.match(filter)) return null
35+
4936
m.dependencies.forEach((d) => {
5037
d = d.replace(root, '');
5138
deps[d] = deps[d] || [];
5239
deps[d].push(id);
5340
});
54-
return {id, size}
41+
42+
return {id, size, origSize, isEntry}
5543
}).filter((m) => m);
44+
45+
if (entrySize) bundleSize = entrySize;
46+
5647
modules.sort((a, b) => b.size - a.size);
5748
if (limit || limit === 0) modules = modules.slice(0, limit);
5849
modules.forEach((m) => {
5950
m.dependents = deps[m.id] || [];
6051
m.percent = ((m.size / bundleSize) * 100).toFixed(2);
52+
m.reduction = 100 - ((m.size / m.origSize) * 100).toFixed(2);
6153
});
54+
6255
if (!format) return resolve(modules)
56+
6357
let heading = `Rollup File Analysis\n`;
6458
let displaySize = `${borderX}bundle size: ${formatBytes(bundleSize)}\n`;
6559
let formatted = `${borderX}${heading}${displaySize}${borderX}`;
60+
6661
modules.forEach((m) => {
62+
if (m.isEntry) return
6763
formatted += `file:${buf}${m.id}\n`;
6864
formatted += `size:${buf}${formatBytes(m.size)}\n`;
6965
formatted += `percent:${buf}${m.percent}%\n`;
66+
formatted += `orig. size:${buf}${formatBytes(m.origSize || 'unknown')}\n`;
67+
formatted += `code reduction:${buf}${m.reduction}%\n`;
7068
formatted += `dependents:${buf}${m.dependents.length}\n`;
7169
m.dependents.forEach((d) => {
7270
formatted += `${tab}-${buf}${d.replace(root, '')}\n`;
7371
});
7472
formatted += `${borderX}`;
7573
});
74+
7675
return resolve(formatted)
7776
})
78-
}
77+
};
78+
79+
const formatted = (bndl, opts) => analyze(bndl, opts, true);
80+
81+
const plugin = (opts = {}) => {
82+
let cb = opts.writeTo || (opts.stdout ? console.log : console.error);
83+
if (opts.onAnalysis) cb = opts.onAnalysis;
84+
let written;
85+
let modules;
86+
87+
let runAnalysis = (out, bundle, isWrite) => new Promise((resolve, reject) => {
88+
resolve();
89+
if (written) return
90+
written = true;
91+
if (out.bundle) bundle = out.bundle;
92+
if (!Array.isArray(bundle.modules)) {
93+
modules.forEach((m) => {
94+
let bm = bundle.modules[m.id];
95+
bm.id = bm.id || m.id;
96+
bm.isEntry = bm.isEntry || m.isEntry;
97+
bm.dependencies = m.dependencies || [];
98+
});
99+
modules = Object.keys(bundle.modules).map((k) => bundle.modules[k]);
100+
} else {
101+
modules = bundle.modules;
102+
}
103+
return analyze({modules}, opts, !opts.onAnalysis).then(cb)
104+
});
105+
return {
106+
name: 'rollup-analyzer-plugin',
107+
transformChunk: (_a, _b, chunk) => new Promise((resolve, reject) => {
108+
resolve(null);
109+
if (!chunk || !chunk.orderedModules) return
110+
modules = chunk.orderedModules.map((m) => {
111+
return {
112+
id: m.id,
113+
isEntry: m.isEntryPoint,
114+
dependencies: m.dependencies.map((d) => d.id)
115+
}
116+
});
117+
}),
118+
generateBundle: runAnalysis,
119+
ongenerate: runAnalysis
120+
}
121+
};
79122

80-
module.exports = analyzer;
123+
exports.analyze = analyze;
124+
exports.formatted = formatted;
125+
exports.plugin = plugin;

module.js

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
'use strict'
22

3-
// Setup
43
const buf = ' '
54
const tab = ' '
65
const borderX = `${Array(30).join('-')}\n`
7-
let proc = process
8-
let root = proc && proc.cwd ? proc.cwd() : null
9-
let limit, filter
10-
11-
// Helpers
126
const formatBytes = (bytes) => {
137
if (bytes === 0) return '0 Byte'
148
let k = 1000
@@ -18,64 +12,108 @@ const formatBytes = (bytes) => {
1812
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
1913
}
2014

21-
// Exports
22-
export default analyzer
23-
24-
// Main
25-
function init (opts) {
26-
opts = opts || {}
27-
limit = opts.limit
28-
filter = opts.filter
29-
root = opts.root || root
30-
}
31-
32-
function analyzer (opts) {
33-
init(opts)
34-
return {init, formatted, analyze}
35-
}
36-
analyzer.init = init
37-
analyzer.formatted = formatted
38-
analyzer.analyze = analyze
39-
40-
function formatted (bndl) { return analyze(bndl, true) }
41-
42-
function analyze (bundle, format) {
15+
export const analyze = (bundle, opts = {}, format = false) => {
16+
let { root, limit, filter } = opts
4317
let deps = {}
18+
let entrySize
4419
let bundleSize = 0
20+
let bundleModules = bundle.modules
21+
4522
return new Promise((resolve, reject) => {
46-
let modules = bundle.modules.map((m, i) => {
47-
let id = m.id.replace(root, '')
48-
let size = Buffer.byteLength(m.code, 'utf8') || 0
23+
let modules = bundleModules.map((m, i) => {
24+
let { id, originalLength: origSize, renderedLength, isEntry, code } = m
25+
id = id.replace(root, '')
26+
let size = renderedLength
27+
if (!size && size !== 0) size = code ? Buffer.byteLength(code, 'utf8') : 0
28+
if (isEntry) entrySize = size
4929
bundleSize += size
30+
5031
if (Array.isArray(filter) && !filter.some((f) => id.match(f))) return null
51-
else if (typeof filter === 'string' && !id.match(filter)) return null
32+
if (typeof filter === 'string' && !id.match(filter)) return null
33+
5234
m.dependencies.forEach((d) => {
5335
d = d.replace(root, '')
5436
deps[d] = deps[d] || []
5537
deps[d].push(id)
5638
})
57-
return {id, size}
39+
40+
return {id, size, origSize, isEntry}
5841
}).filter((m) => m)
42+
43+
if (entrySize) bundleSize = entrySize
44+
5945
modules.sort((a, b) => b.size - a.size)
6046
if (limit || limit === 0) modules = modules.slice(0, limit)
6147
modules.forEach((m) => {
6248
m.dependents = deps[m.id] || []
6349
m.percent = ((m.size / bundleSize) * 100).toFixed(2)
50+
m.reduction = 100 - ((m.size / m.origSize) * 100).toFixed(2)
6451
})
52+
6553
if (!format) return resolve(modules)
54+
6655
let heading = `Rollup File Analysis\n`
6756
let displaySize = `${borderX}bundle size: ${formatBytes(bundleSize)}\n`
6857
let formatted = `${borderX}${heading}${displaySize}${borderX}`
58+
6959
modules.forEach((m) => {
60+
if (m.isEntry) return
7061
formatted += `file:${buf}${m.id}\n`
7162
formatted += `size:${buf}${formatBytes(m.size)}\n`
7263
formatted += `percent:${buf}${m.percent}%\n`
64+
formatted += `orig. size:${buf}${formatBytes(m.origSize || 'unknown')}\n`
65+
formatted += `code reduction:${buf}${m.reduction}%\n`
7366
formatted += `dependents:${buf}${m.dependents.length}\n`
7467
m.dependents.forEach((d) => {
7568
formatted += `${tab}-${buf}${d.replace(root, '')}\n`
7669
})
7770
formatted += `${borderX}`
7871
})
72+
7973
return resolve(formatted)
8074
})
8175
}
76+
77+
export const formatted = (bndl, opts) => analyze(bndl, opts, true)
78+
79+
export const plugin = (opts = {}) => {
80+
let cb = opts.writeTo || (opts.stdout ? console.log : console.error)
81+
if (opts.onAnalysis) cb = opts.onAnalysis
82+
let written
83+
let modules
84+
85+
let runAnalysis = (out, bundle, isWrite) => new Promise((resolve, reject) => {
86+
resolve()
87+
if (written) return
88+
written = true
89+
if (out.bundle) bundle = out.bundle
90+
if (!Array.isArray(bundle.modules)) {
91+
modules.forEach((m) => {
92+
let bm = bundle.modules[m.id]
93+
bm.id = bm.id || m.id
94+
bm.isEntry = bm.isEntry || m.isEntry
95+
bm.dependencies = m.dependencies || []
96+
})
97+
modules = Object.keys(bundle.modules).map((k) => bundle.modules[k])
98+
} else {
99+
modules = bundle.modules
100+
}
101+
return analyze({modules}, opts, !opts.onAnalysis).then(cb)
102+
})
103+
return {
104+
name: 'rollup-analyzer-plugin',
105+
transformChunk: (_a, _b, chunk) => new Promise((resolve, reject) => {
106+
resolve(null)
107+
if (!chunk || !chunk.orderedModules) return
108+
modules = chunk.orderedModules.map((m) => {
109+
return {
110+
id: m.id,
111+
isEntry: m.isEntryPoint,
112+
dependencies: m.dependencies.map((d) => d.id)
113+
}
114+
})
115+
}),
116+
generateBundle: runAnalysis,
117+
ongenerate: runAnalysis
118+
}
119+
}

0 commit comments

Comments
 (0)