Gulp Run Task Again After File Change

Many of us have to handle web-based projects that are used in production, which provide various services to the public. When dealing with such projects, it is important to be able to build and deploy our code quickly. Doing something speedily often leads to errors, especially if a process is repetitive, therefore it's a good do to automate such a procedure as much as possible.

Gulp: A Web Developer's Secret Weapon for Maximizing Site Speed

My fellow developers: There is no excuse for serving junk to your browser.

In this mail service, we volition be looking at a tool that tin can be a office of what will allow united states to reach such automation. This tool is an npm packet chosen Gulp.js. In gild to become familiar with the basic Gulp.js terminology used in this post, please refer to "An Introduction to JavaScript Automation with Gulp" that was previously published on the web log past Antonios Minas, one of our fellow Toptal developers. We will presume bones familiarity with the npm surroundings, as it is used extensively throughout this post to install packages.

Serving Front-Finish Assets

Before nosotros continue, let'south take a few steps back to go an overview of the problem that Gulp.js can solve for us. Many spider web-based projects feature front-terminate JavaScript files that are served to the client in guild to provide various functionalities to the spider web page. Usually in that location's likewise a fix of CSS stylesheets that are served to the client likewise. Sometimes when looking at the source code of a website or a spider web application, we tin see code like this:

          <link href="css/main.css" rel="stylesheet"> <link href="css/custom.css" rel="stylesheet"> <script src="js/jquery.min.js"></script> <script src="js/site.js"></script> <script src="js/module1.js"></script> <script src="js/module2.js"></script>                  

There are a few problems with this code. It has references to two separate CSS stylesheets and four separate JavaScript files. This means that the server has to make a total of six requests to the server, and each request has to separately load a resource earlier the page will be ready. This is less of an event with HTTP/ii because HTTP/2 introduces parallelism and header compression, but it'due south all the same an upshot. It increases the total volume of traffic that is required to load this page and reduces the quality of user feel because it takes longer to load the files. In case of HTTP 1.1, it also hogs the network and reduces the number of request channels that are available. It would accept been much improve to combine the CSS and JavaScript files into a single bundle for each. That way, there would be but a total of two requests. It would as well have been nice to serve minified versions of these files, which are normally much smaller than the originals. Our web application might also break if any of the assets are cached, and the client would receive an outdated version.

Overload

One primitive approach to solving some of these problems is to manually combine each type of nugget into a bundle using a text editor, and then run the effect through a minifier service, such as http://jscompress.com/. This proves to be very tedious to do continuously during the development procedure. A slight just questionable comeback would be to host our ain minifier server, using one of the packages available on GitHub. Then we could do things that would look somewhat similar to the post-obit:

          <script src="min/f=js/site.js,js/module1.js"></script>                  

This would serve minified files to our client, but it would not solve the problem of caching. It would also cause additional load on the server since our server would substantially have to concatenate and minify all the source files repetitively on every request.

Automating with Gulp.js

Surely we can do amend than either of these ii approaches. What we really desire is to automate bundling and include it in the build phase of our project. Nosotros want to end up with pre-congenital nugget bundles that are already minified and are set up to serve. We also want to force the client to receive the most up to date versions of our bundled assets on every asking, but we notwithstanding want to leverage caching if possible. Luckily for us, Gulp.js can handle that. In the remainder of the article, we will be building a solution that will leverage the power of Gulp.js to concatenate and minify the files. We will likewise be using a plugin to bosom the cache when at that place are updates.

Nosotros will be creating the following directory and file structure in our example:

          public/ |- build/    |- js/       |- bundle-{hash}.js    |- css/       |- stylesheet-{hash}.css avails/ |- js/    |- vendor/    |- jquery.js    |- site.js    |- module1.js    |- module2.js |- css/    |- main.css    |- custom.css gulpfile.js package.json                  

npm makes package management in Node.js projects a bliss. Gulp provides tremendous extensibility past taking advantage of npm'south uncomplicated packaging arroyo to deliver modular and powerful plugins.

The gulpfile.js file is where we will define the tasks that Gulp volition perform for us. The parcel.json is used past npm to define our application's package and track the dependencies that nosotros will be installing. The public directory is what should exist configured to face up the web. The assets directory is where nosotros will store our source files. To use Gulp in the projection, nosotros will need to install it via npm and save it as a developer dependency for the project. We volition also desire to showtime with the concat plugin for Gulp, which volition allow us to concatenate multiple files into one.

To install these two items, we will run the following control:

          npm install --save-dev gulp gulp-concat                  

Next, we will want to begin writing the content of gulpfile.js.

          var gulp = require('gulp'); var concat = require('gulp-concat');   gulp.task('pack-js', function () {         return gulp.src(['assets/js/vendor/*.js', 'avails/js/main.js', 'assets/js/module*.js'])         .pipage(concat('bundle.js'))         .pipe(gulp.dest('public/build/js')); });   gulp.task('pack-css', function () {         return gulp.src(['avails/css/main.css', 'avails/css/custom.css'])         .pipage(concat('stylesheet.css'))         .pipe(gulp.dest('public/build/css')); });   gulp.task('default', ['pack-js', 'pack-css']);                  

Hither, nosotros are loading the gulp library and its concat plugin. We and so define three tasks.

Loading the gulp library and its concat plugin

The starting time task (pack-js) defines a procedure to compress multiple JavaScript source files into one bundle. We list the source files, which volition be globbed, read, and concatenated in the society specified. We pipe that into the concat plugin to get i last file called packet.js. Finally, we tell gulp to write the file to public/build/js.

The second chore (pack-css) does the same thing as above, merely for the CSS stylesheets. It tells Gulp to store the concatenated output as stylesheet.css in public/build/css.

The third task (default) is the one Gulp runs when we invoke information technology with no arguments. In the 2d parameter, we laissez passer the list of other tasks to execute when the default task is run.

Let's paste this lawmaking into gulpfile.js using whatever source code editor that nosotros ordinarily utilise, and then salve the file to the application root.

Adjacent, we will open the command line and run:

          gulp                  

If we await at our files afterwards running this command, we volition find 2 new files: public/build/js/bundle.js and public/build/css/stylesheet.css. They are concatenations of our source files, which solves role of the original problem. However, they are not minified, and there is no cache busting all the same. Let's add together automated minification.

Optimizing Congenital Assets

We will need two new plugins. To add them, nosotros will run the post-obit command:

          npm install --save-dev gulp-clean-css gulp-minify                  

The offset plugin is for minifying CSS, and the second 1 is for minifying JavaScript. The first ane uses the make clean-css package, and the second one uses the UglifyJS2 package. We volition load these two packages in our gulpfile.js first:

          var minify = require('gulp-minify'); var cleanCss = require('gulp-clean-css');                  

We will then need to utilise them in our tasks simply before nosotros write the output to disk:

          .piping(minify()) .pipe(cleanCss())                  

The gulpfile.js should now look like this:

          var gulp = require('gulp'); var concat = require('gulp-concat'); var minify = require('gulp-minify'); var cleanCss = require('gulp-clean-css');   gulp.task('pack-js', office () {         return gulp.src(['assets/js/vendor/*.js', 'assets/js/primary.js', 'assets/js/module*.js'])         .pipe(concat('bundle.js'))         .pipe(minify())         .pipe(gulp.dest('public/build/js')); });   gulp.chore('pack-css', function () {         return gulp.src(['avails/css/master.css', 'assets/css/custom.css'])         .piping(concat('stylesheet.css'))         .pipe(cleanCss())    .pipe(gulp.dest('public/build/css')); });   gulp.job('default', ['pack-js', 'pack-css']);                  

Permit's run gulp again. Nosotros volition see that the file stylesheet.css is saved in minified format, and the file bundle.js is still saved as is. We will find that we now besides accept package-min.js, which is minified. We want only the minified file, and nosotros want it saved as packet.js, and so nosotros volition modify our code with additional parameters:

          .pipe(minify({     ext:{         min:'.js'     },     noSource: true }))                  

As per gulp-minify plugin documentation (https://www.npmjs.com/bundle/gulp-minify), this volition fix the desired name for the minified version, and tell the plugin not to create the version containing the original source. If we delete the content of the build directory and run gulp from the command line again, we will terminate upwards with just two minified files. We take but finished implementing the minification phase of our build process.

Enshroud Busting

Next, we will want to add enshroud busting, and nosotros will need to install a plugin for that:

          npm install --relieve-dev gulp-rev                  

And require it in our gulp file:

          var rev = crave('gulp-rev');                  

Using the plugin is a bit catchy. We accept to pipe the minified output through the plugin first. Then, we have to call the plugin again afterward we write the results to disk. The plugin renames the files and then that they are tagged with a unique hash, and it likewise creates a manifest file. The manifest file is a map that can exist used by our application to determine the latest filenames that we should refer to in our HTML code. Later we alter the gulp file, it should end up looking like this:

          var gulp = require('gulp'); var concat = crave('gulp-concat'); var minify = require('gulp-minify'); var cleanCss = require('gulp-clean-css'); var rev = require('gulp-rev');   gulp.task('pack-js', function () {         return gulp.src(['assets/js/vendor/*.js', 'avails/js/main.js', 'assets/js/module*.js'])         .pipage(concat('bundle.js'))         .pipe(minify({             ext:{                 min:'.js'             },             noSource: true         }))         .pipe(rev())         .pipe(gulp.dest('public/build/js'))         .pipe(rev.manifest())         .pipe(gulp.dest('public/build')); });   gulp.task('pack-css', part () {     return gulp.src(['assets/css/main.css', 'avails/css/custom.css'])         .pipe(concat('stylesheet.css'))         .pipe(cleanCss())         .pipe(rev())             .pipe(gulp.dest('public/build/css'))         .pipage(rev.manifest())         .pipe(gulp.dest('public/build')); });   gulp.task('default', ['pack-js', 'pack-css']);                  

With proper cache busting in place, y'all tin can go nuts with long decease time for your JS and CSS files and reliably supersede them all the same with newer versions whenever necessary.

Permit's delete the contents of our build directory and run gulp again. We volition observe that we now have two files with hashtags affixed to each of the filenames, and a manifest.json saved to public/build. If we open the manifest file, we will come across that it only has a reference to ane of our minified and tagged files. What is happening is that each task writes a separate manifest file, and one of them ends up overwriting the other. We will demand to modify the tasks with boosted parameters that volition tell them to look for the existing manifest file and to merge the new data into it if it exists. The syntax for that is a bit complicated, and then permit'due south look at what the code should wait similar and then go over it:

          var gulp = crave('gulp'); var concat = crave('gulp-concat'); var minify = require('gulp-minify'); var cleanCss = crave('gulp-clean-css'); var rev = require('gulp-rev');   gulp.task('pack-js', function () {     return gulp.src(['assets/js/vendor/*.js', 'avails/js/primary.js', 'assets/js/module*.js'])         .pipe(concat('bundle.js'))         .pipe(minify({             ext:{                 min:'.js'             },             noSource: true         }))         .pipage(rev())         .pipe(gulp.dest('public/build/js'))         .pipe(rev.manifest('public/build/rev-manifest.json', {             merge: true         }))         .pipe(gulp.dest(''));     });   gulp.job('pack-css', office () {         return gulp.src(['assets/css/chief.css', 'avails/css/custom.css'])         .pipe(concat('stylesheet.css'))         .piping(cleanCss())         .pipe(rev())         .pipe(gulp.dest('public/build/css'))         .piping(rev.manifest('public/build/rev-manifest.json', {             merge: true         }))         .pipage(gulp.dest('')); });   gulp.task('default', ['pack-js', 'pack-css']);                  

We are piping the output to rev.manifest() first. This creates tagged files instead of the files that we had before. We are providing the desired path of our rev-manifest.json, and telling rev.manifest() to merge into the existing file, if information technology exists. Then we are telling gulp to write the manifest to the current directory, which at that bespeak will be public/build. The path issue is due to a bug that is discussed in more item on GitHub.

Nosotros now have automated minification, tagged files, and a manifest file. All of this will allow us to evangelize the files more than apace to the user, and bust their enshroud whenever nosotros make our modifications. In that location are just ii remaining problems though.

The first problem is that if nosotros make whatever modifications to our source files, nosotros will get newly tagged files, but the onetime ones will remain at that place likewise. We demand some fashion to automatically delete old minified files. Let'due south solve this problem using a plugin that will let united states of america to delete files:

          npm install --save-dev del                  

We volition require it in our code and define two new tasks, one for each type of source file:

          var del = require('del');   gulp.task('clean-js', part () {     return del([         'public/build/js/*.js'     ]); });   gulp.job('clean-css', function () {     render del([         'public/build/css/*.css'     ]); });                  

Nosotros will then brand sure that the new chore finishes running before our two main tasks:

          gulp.task('pack-js', ['clean-js'], office () { gulp.task('pack-css', ['clean-css'], function () {                  

If we run gulp again after this modification, we will take just the latest minified files.

The 2d problem is that we don't desire to keep running gulp every time nosotros make a change. To solve this, we volition need to define a watcher task:

          gulp.task('lookout', function() {  gulp.lookout man('assets/js/**/*.js', ['pack-js']);  gulp.watch('assets/css/**/*.css', ['pack-css']); });                  

We will also alter the definition of our default job:

          gulp.task('default', ['watch']);                  

If we now run gulp from the command line, we volition find that it no longer builds anything upon invocation. This is because information technology now calls the watcher task that will watch our source files for any changes, and build simply when it detects a modify. If we endeavor irresolute any of our source files and and then expect at our panel once again, we will run into that the pack-js and pack-css tasks run automatically along with their dependencies.

Now, all nosotros have to exercise is load the manifest.json file in our application and go the tagged filenames from that. How we practise that depends on our detail dorsum-cease language and applied science stack, and would be quite trivial to implement, so nosotros will not go over it in particular. However, the general idea is that we can load the manifest into an assortment or an object, and then define a helper office that will allow us to call versioned assets from our templates in a manner similar to the following:

          gulp('bundle.js')                  

Once we exercise that, we will not have to worry well-nigh inverse tags in our filenames ever again, and we will exist able to focus on writing high-quality code.

The final source lawmaking for this commodity, along with a few sample assets, can be found in this GitHub repository.

Determination

In this article, nosotros went over how to implement Gulp based automation for our build process. I promise that this proves helpful to you and allows you lot to develop more sophisticated build processes in your own applications.

Please keep in mind that Gulp is just one of the tools that can be used for this purpose, and at that place are many others such as Grunt, Browserify, and Webpack. They vary in their purposes and in the scope of problems that they tin can solve. Some tin solve bug that Gulp cannot, such as bundling JavaScript modules with dependencies that can exist loaded on need. This is referred to as "code splitting", and information technology is an comeback over the idea of serving one big file with all parts of our program on every page. These tools are quite sophisticated but might be covered in the future. In a following mail service, we will become over how to automate the deployment of our awarding.

wilkersonhisquam.blogspot.com

Source: https://www.toptal.com/javascript/optimize-js-and-css-with-gulp

0 Response to "Gulp Run Task Again After File Change"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel