Creating a production workflow

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.

Gulp useref

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.

Image Optimization

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

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

Bundle JavaScript files for production

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.

Putting it all together

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.216.75