The development workflow that we built in the previous sections is an amazing improvement for the project; however, we are not finished yet. In this section, you will see how to optimize the project that is to be run in the production environments.
In this section, you will learn how to minimize your JavaScript and CSS files to obfuscate your source code and reduce the time the browser takes to load the asset files. The images can also be minified in order to reduce its weight without altering its appearance.
The gulp-useref
plugin processes your HTML files to concatenate your JavaScript and CSS assets into a single file. Please note that the JavaScript is already processed by Browserify, therefore, it is not necessary to process the JavaScript files with useref; on the other hand, CSS can be processed here.
You will need to install the plugin with npm as a development dependency:
$ npm install --save-dev gulp-useref
Then, to use it, you will need to create a new task. Let's call it html
:
// ... gulp.task('html', function() { var assets = $.useref.assets(); return gulp.src('app/*.html') .pipe(assets) .pipe(assets.restore()) .pipe($.useref()) .pipe(gulp.dest('dist')); });
The gulp.src('app/*.html')
function grabs all the files with the.html
extension. In our case, only the index.html
file exists, therefore, it is the only file that will be processed. The useref.assets()
function concatenates all the assets that are found in the HTML files and puts them in a stream, the assets.restore()
function will restore the original stream of HTML files that are picked in the beginning.
When you call the useref()
function, the HTML file is parsed in order to replace the assets files in a single HTML tag. For example, if you have five CSS files, it replaces these five link tags in the HTML file in a single tag that points to the concatenated version.
You should indicate the useref
task how to concatenate the files with special tags in the HTML files:
<html> <head> <!-- ... --> <!-- build:css(app) css/vendor.css --> <link rel="stylesheet" href="css/bootstrap.css"> <link rel="stylesheet" href="css/main.css"> <!-- endbuild --> <!-- ... --> </head> <!-- ... --> </html>
You need add two HTML comments to the code, these comments have a special meaning for useref. Its syntax is as follows:
<!-- build:<type>(alternate search path) <path> --> ... HTML Markup, list of script / link tags. <!-- endbuild -->
As we are processing CSS files, we use css
as type, and the search path indicates where useref will look for the files. If we left this optional parameter blank, then it will use the root project path. The last path
argument indicates where the concatenated CSS files will be put.
If you run the Gulp html
task, you will get a concatenated file with all your styles under the dist/css/vendor.css
path. The output HTML file will point to this file instead of the development ones:
<html> <head> <!-- ... --> <link rel="stylesheet" href="css/vendor.css"> <!-- ... --> </head> <!-- ... --> </html>
You can optimize the output CSS files by minifying them with the gulp-minify-css
plugin. As you may have guessed, you should install the plugin with npm:
$ npm install --save-dev gulp-minify-css
Then you can use the plugin in your build process, as follows:
// ... var minifyCss = require('gulp-minify-css'); gulp.task('html', function() { var assets = $.useref.assets(); return gulp.src('app/*.html') .pipe(assets) .pipe(minifyCss()) .pipe(assets.restore()) .pipe($.useref()) .pipe(gulp.dest('dist')); });
This will minify the concatenated CSS file. However, as useref
can process CSS and JavaScript files, the code can be buggy if a JavaScript build tag is added. To prevent errors, you can use the gulp-if
plugin:
$ npm install --save-dev gulp-if gulp-uglify
This will also install uglify
in order to also process the JavaScript files:
// ... gulp.task('html', function() { var assets = $.useref.assets(); return gulp.src('app/*.html') .pipe(assets) .pipe($.if('*.js', uglify())) .pipe($.if('*.css', minifyCss())) .pipe(assets.restore()) .pipe($.useref()) .pipe(gulp.dest('dist')); });
With gulp-if
we test if the file in the stream is a CSS or a JavaScript file and then apply the right transformation.
When you are developing your project in the local machine, the assets load pretty fast as images and code live in the same computer; however, when you go to the production images, they travel through the Internet to your user machine.
With image optimization, we can compress these images in order to reduce the amount of data that your app downloads from the server. With node, you can use the imagemin
package; however, as we are using Gulp, gulp-imagemin
will do the job.
As we did earlier, you will need to install the plugin first:
$ npm install --save-dev gulp-imagemin
Now that the plugin is installed, we can use it:
gulp.task('images', function() { gulp.src('app/images/*.{jpg,gif,svg,png}') .pipe($.imagemin()) .pipe(gulp.dest('dist/images')); });
It grabs the images from the app/images
path and applies the imagemin()
process to each image.
Fonts for Bootstrap are located under the node_modules/
directory. If you install other type of fonts, such as Font Awesome, or download a specific fonts; they should be copied to the dist/
directory. You can create a fonts
task to do this, as shown in the following:
// ... gulp.task('fonts', function () { return gulp.src([ 'app/{,styles/}fonts/**/*', 'node_modules/bootstrap/dist/fonts/**/*' ]) .pipe($.flatten()) .pipe(gulp.dest('dist/fonts')); });
Note that you will need to install the gulp-flatten
plugin; this plugin will remove any prefix directory:
$ npm install --save-dev gulp-flatten
The browserify
task that we have is useful for development, it creates sourcemaps and the output is not minified. If you want to go to the production, you will need to remove the sourcemaps and minimize the output too.
For production environment, we will transform the ECMAScript 6 code into JavaScript in order to add support for these browsers that does not support for ECMAScript 6. Babel is the best transpiler at the moment to make this transformation.
The babelify plugin of Browserify will apply the transformations, as follows:
$ npm install --save-dev babelify
You will need to configure Babel before using the babelify plugin. In Babel 6, you have to install individual packages for the functions that you want to support. For this project, we support ES2015:
$ npm install --save-dev babel-preset-es2015
In the .babelrc
file, you should configure the preset:
// .babelrc { "presets": ["es2015"] }
Once you have configured Babel properly, we can create the browserify
task for production:
// Bundle files with browserify for production gulp.task('browserify:dist', function () { // set up the browserify instance on a task basis var bundler = browserify({ entries: 'app/js/main.js', // defining transforms here will avoid crashing your stream transform: [babelify, jstify] }); return bundler.bundle() .on('error', $.util.log) .pipe(source('app.js')) .pipe(buffer()) .pipe($.uglify()) .pipe(gulp.dest('dist/js')); });
This task does not generate sourcemaps and optimize the output.
You have learned how to optimize several kind of assets: CSS, JavaScript, and images. Now let's put all this together in order to build our application. The serve:dist
task wires all the processes into a pipeline:
gulp.task('serve:dist', ['browserify:dist', 'images', 'fonts', 'express'], () => { var serverProxy = httpProxy.createProxyServer(); browserSync({ port: 9000, ui: { port: 9001 }, server: { baseDir: 'dist', middleware: [ function (req, res, next) { if (req.url.match(/^/(api|avatar)/.*/)) { serverProxy.web(req, res, { target: 'http://localhost:8000' }); } else { next(); } } ] } }); });
To test our pipeline, we can run the serve:dist
task in the terminal:
$ gulp serve:dist [11:18:04] Using gulpfile ~/Projects/mastering-backbone/ch07/gulpfile.js [11:18:04] Starting 'browserify:dist'... [11:18:04] Starting 'images'... [11:18:04] Finished 'images' after 305 ms [11:18:04] Starting 'fonts'... [11:18:04] Starting 'express'... [11:18:05] Finished 'express' after 141 ms [11:18:05] gulp-imagemin: Minified 0 images [11:18:05] [nodemon] 1.8.1 [11:18:05] [nodemon] to restart at any time, enter `rs` [11:18:05] [nodemon] watching: *.* [11:18:05] [nodemon] starting `node server/index.js` Express server is running on port 8000 [11:18:08] Finished 'fonts' after 4.04 s [11:18:12] Finished 'browserify:dist' after 8.02 s [11:18:12] Starting 'serve:dist'... [11:18:12] Finished 'serve:dist' after 40 ms [11:18:12] [nodemon] restarting due to changes... [BS] Access URLs: -------------------------------------- Local: http://localhost:9000 External: http://192.168.100.4:9000 -------------------------------------- UI: http://localhost:9001 UI External: http://192.168.100.4:9001 -------------------------------------- [BS] Serving files from: dist [11:18:12] [nodemon] starting `node server/index.js` Express server is running on port 8000
Notice how the tasks are executed by Gulp. After all these processes, the browser will automatically open while pointing to the http://localhost:9000
address, running the application in the production environment.
3.135.216.75