├── demo.png ├── package.json ├── README.md └── index.js /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ondras/rollup-plugin-graph/HEAD/demo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-plugin-graph", 3 | "version": "2.0.0", 4 | "description": "Generate module dependencies graph, using the DOT language", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/ondras/rollup-plugin-graph.git" 9 | }, 10 | "keywords": [ 11 | "rollup-plugin" 12 | ], 13 | "author": "Ondřej Žára", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/ondras/rollup-plugin-graph/issues" 17 | }, 18 | "homepage": "https://github.com/ondras/rollup-plugin-graph" 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rollup-plugin-graph 2 | 3 | Generates module dependencies graph, using the DOT language. To actually draw images, you will need the `graphviz` toolbox. 4 | 5 | In your `rollup.config.js`: 6 | ```js 7 | let graph = require("rollup-plugin-graph"); 8 | let graphOptions = {prune: true}; 9 | 10 | module.exports = { 11 | /* ... */ 12 | plugins: [ graph(graphOptions) ] 13 | }; 14 | ``` 15 | 16 | In your terminal: 17 | ```sh 18 | rollup -c | dot -Tpng > graph.png 19 | ``` 20 | 21 | ## Options 22 | 23 | * `prune` (bool) Whether to prune the resulting graph, leaving only cyclic dependencies. This makes the graph [strongly connected](https://en.wikipedia.org/wiki/Strongly_connected_component). 24 | Examples: [pruned](https://raw.githubusercontent.com/ondras/sleeping-beauty/master/graphs/pruned.png), [not pruned](https://raw.githubusercontent.com/ondras/sleeping-beauty/master/graphs/complete.png) 25 | * `exclude` (string or regexp) Specified the module ID pattern to be excluded from the graph. 26 | 27 | ## Sample output 28 | 29 | ![](demo.png) 30 | 31 | Please note that this plugin is not directly responsible for image rendering. It generates output in the [DOT language](https://en.wikipedia.org/wiki/DOT_(graph_description_language)), so you need to use a proper tool (such as [Graphviz](https://www.graphviz.org/)) to create the image. 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function toDot(modules) { 4 | console.log("digraph G {"); 5 | console.log("edge [dir=back]") 6 | modules.forEach(m => { 7 | m.deps.forEach(dep => { 8 | console.log(`"${dep}" -> "${m.id}"`); 9 | }); 10 | }); 11 | console.log("}"); 12 | } 13 | 14 | function prune(modules) { 15 | let avail = modules.filter(m => m.deps.length == 0); 16 | if (!avail.length) { return; } 17 | 18 | let id = avail[0].id; 19 | // console.log("pruning", id); 20 | let index = modules.indexOf(avail[0]); 21 | modules.splice(index, 1); 22 | modules.forEach(m => { 23 | m.deps = m.deps.filter(dep => dep != id); 24 | }); 25 | prune(modules); 26 | } 27 | 28 | function getPrefix(ids) { 29 | if (ids.length < 2) { return ""; } 30 | return ids.reduce((prefix, val) => { 31 | while (val.indexOf(prefix) != 0) { prefix = prefix.substring(0, prefix.length-1); } 32 | return prefix; 33 | }); 34 | } 35 | 36 | module.exports = function plugin(options = {}) { 37 | let exclude = str => options.exclude && str.match(options.exclude); 38 | 39 | return { 40 | generateBundle(bundleOptions, bundle, isWrite) { 41 | let ids = []; 42 | for (const moduleId of this.getModuleIds()) { 43 | if (!exclude(moduleId)) { ids.push(moduleId); } 44 | } 45 | 46 | let prefix = getPrefix(ids); 47 | let strip = str => str.substring(prefix.length); 48 | 49 | let modules = []; 50 | ids.forEach(id => { 51 | let m = { 52 | id: strip(id), 53 | deps: this.getModuleInfo(id).importedIds.filter(x => !exclude(x)).map(strip) 54 | } 55 | if (exclude(m.id)) { return; } 56 | modules.push(m); 57 | }); 58 | if (options.prune) { prune(modules); } 59 | toDot(modules); 60 | } 61 | } 62 | } 63 | --------------------------------------------------------------------------------