📜 ⬆️ ⬇️

Creating a gulp-plugin on the example of building a dependency graph for Angular JS modules

Foreword


In this article I will share with you the experience of how to create simple plugins for gulp quickly and painlessly. The article is focused on the same teapots as me. For those who have so far only used the ready-made fruits of the gulp, tearing them off from the great Tree of Knowledge NPM, and have not had much experience with Node JS and its streams.

I will not answer questions like "Why create your own plugins if everything is already written that is possible?". The time will come, and in half an hour you will need to write something very specific to your project. Break all npm, you will find one abandoned plugin with poor functionality, the author of which is not available, the code is terrible, and so on. Or maybe it will be such a specific task that you will find absolutely nothing.

Such a task for me was the visualization of a large project using Angular JS. There was a huge amount of angular modules, the connections between which were no longer so obvious to me. Plus, I wanted to see “saboteurs” - modules that somehow violated the overall concept of the project (for example, we climbed into another module not directly through the provider, but directly).
')
Searching, I found this solution to my problem. In principle, running grunt plugins in gulp is quite simple, but the implementation in this plugin didn’t impress me too much. I did not want to use third-party programs, namely graphviz, as a graph visualization tool. Plus, who knows what I need more, and dependence on third-party libraries always imposes restrictions.

If the reader is only interested in this plugin, and not the article itself, then here is a link to the project on github and on npm . Everyone else - welcome under cat.

Where to begin?


Gulp developers kindly help us in our endeavors by creating wiki documentation for novice plugin developers here . For successful development it is enough to read the title and guideline . You can do without the latter, but if in the future you plan to lay out your module in a public npm, then in order not to collect bricks on your head, I advise you not to go past the guidelines.

A brief synopsis of gulp-plugins philosophy:

Plus, developers are advised to familiarize themselves with well-written simple plugins. I would advise you to look at the gulp-replace code .

We implement our ideas


I will provide the most well-established gulp plugin template that is used in most good plugins. A detailed description of the implementation of my task is not the goal of this article. The main goal is that everyone can quickly "enter" with an example and go to create their own plugin.

So, let's begin. It is assumed that node js is already in the system globally.
npm init 

Main project file let it be index.js. After filling out the basic information, set the following
 npm install --save through2 gulp-util vinyl 

The first plugin will greatly simplify the processing of vinyl-streams. The second is useful for generating errors by the plugin. The third one is useful if you create new vinyl files based on input files. In my task, it is useful.

Let's design. So, I want to get two files. The first is a description of a graph in dot format to support graphviz, if that happens. The second is the html file, having opened which I will see a beautiful graph drawn with the help of d3. Total in my task there are 3 main actions:
  1. get an array of all the angular modules declared in the files that the plugin will take
  2. create a .dot graph file based on an array of modules
  3. create a visual representation of the graph (html file with d3-script)

Create index.js, clean as a canvas, and throw more colors onto it:
 var through = require('through2'), gutil = require('gulp-util'), //    - ModulesReader = require('./lib/modules-reader'), //    GraphBuilder = require('./lib/graph-builder'), //    GraphVisualizer = require('./lib/graph-visualizer'); // ,     gulp,     module.exports = function(options) { //#section  var modulesReader; var graphBuilder; var graphVisualizer; options = options || {}; if (!modulesReader) { modulesReader = new ModulesReader(); } if (!graphBuilder) { graphBuilder = new GraphBuilder(); } if (!graphVisualizer) { graphVisualizer = new GraphVisualizer(); } //#endsection  //,    through    function bufferContents(file, enc, callback) { if (file.isStream()) { //    gulp-util this.emit('error', new gutil.PluginError('gulp-ng-graph', 'Streams are not supported!')); return callback(); } if (file.isBuffer()) { //        modulesReader.read(file.contents, enc); } callback(); } //     function endStream(callback) { var modules = modulesReader.getModules(); if (!modules || !modules.length) { return; } // dot     var builderData = graphBuilder.build({ modules: modules, dot: options.dot || 'ng-graph.dot', }); // html      var htmlFile = graphVisualizer.render({ graph: builderData.graph, html: options.html || 'ng-graph.html', }); //    this.push(builderData.dotFile); this.push(htmlFile); callback(); } return through.obj(bufferContents, endStream); }; 


It is important to remember that if you plan to return processed input files, you need to call this.push (file) in the bufferContents function after manipulating the contents of the file. But if you plan (as in my task) to generate new files based on input files, then you definitely need the endStream function, where the stream is not yet closed and you can add your files to an empty stream.

Since the main purpose of the article is to learn how to write gulp plugins with a specific example, I will not give here the implementation of ModulesReader , GraphBuilder and GraphVisualizaer , which are specific to my specific task. If someone is interested in their implementation, then welcome to the github

The result of the plug-in is such a nice graph of the project on d3 with the possibility of zooming.


Source: https://habr.com/ru/post/257275/


All Articles