Reduce number of requests by grouping assets with Gulp

Often my main layout view posses many style sheet and javascript files included. This is escpecially visible when I use some Bootstrap themes, so beside bootstrap.min.css there are IE fixes included, custom header and footer files, some animation style sheet, Font Awesome files, my custom styles ... entire bunch of files.

Don't tell anyone :) but my view files usually used to look like this:

    
        <!-- ... some other stuff ... -->

        <!-- Web Fonts -->
        <link rel='stylesheet' type='text/css' href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600&amp;subset=cyrillic,latin'>

        <!-- CSS Global Compulsory -->
        <link rel="stylesheet" href="/assets/plugins/bootstrap/css/bootstrap.min.css">
        <link rel="stylesheet" href="/assets/css/style.css">

        <!-- CSS Header and Footer -->
        <link rel="stylesheet" href="/assets/css/headers/header-default.css">

        <!-- CSS Implementing Plugins -->
        <link rel="stylesheet" href="/assets/plugins/font-awesome/css/font-awesome.min.css">

        <link rel="stylesheet" href="/assets/plugins/sky-forms-pro/skyforms/css/sky-forms.css">
        <link rel="stylesheet" href="/assets/plugins/sky-forms-pro/skyforms/custom/custom-sky-forms.css">

        <!-- CSS Customization -->
        <link rel="stylesheet" href="/assets/css/custom.css">

        <!-- Home Page -->
        <link media="all" type="text/css" rel="stylesheet" href="/assets/css/home.css">

        <!-- Header End -->
    

I am very well aware of many tools like Gulp and Grunt, but I am always telling myself that I will come back to that part,... and that happens almost never. There is always some new project or some hotfix needed and not enough time to deal with every aspect of site optimization.

If I am having fast internet connection, that doesn't mean that my visitors are also having similar internet speeds. If my connection is 50Mbps and site loads in 1 to 1.5 seconds, how much time it will take for a visitor with 10Mbps connection, or 2Mbps or even slower. That 1 second suddenly becomes 10+ seconds. No one wants to wait that much, for 10 seconds I will do 5 new Google queries and find what I am looking for on some other site.

This site optimization issue gave me an idea for new series of tutorials. I am planning to cover common site optimization techniques, like the ones which GTmetrix.com uses for site scoring. First in the row is this tutorial related to grouping and minifying assets, after this I will show you how to use server caching to boost your Laravel site, optimize images, deliver scaled images to different screen sizes and many more techniques.

The best part with all of these small improvements is that Google positively reacts on these modifications, and over time it will give more traffic to optimized sites versus non-optimized.

Now lets return to our issue with too many css and js files included in main view. What this means is that visitors browser will need to make new requests to our server for each new asset. In this example view I have 8 files included in head section of the page, which are hosted on my server. I also have, but did not include here, about 6 js files in the footer section of this same page.

I want to mix all css files in one file and do that same for js files. So instead of 14 requests, page will only need 2 requests for these files.

From version 5.0 Laravel ships with built-in support for Gulp. This is accomplished with Laravel Elixir, which is wrapping some complex (for backend devs) Gulp stuff into fluent Laravel-way API.

Gulp installation

Gulp relies on Node.js so first you need to install it. On Ubuntu OS:

    
sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm
    

This last line installs Node Package Manger (npm), which works like Composer.

I want to use Gulp through entire system so I will do global installation.

    
npm install --global gulp
    

After this, I need to install Node dependencies for current project. So I will go into root directory of current project and run:

    
npm install
    

Node keeps project dependancy list into package.json in similar way as Composer in composer.json.

Instructing Gulp which files to group

Gulp can do a bunch of different tasks, I am interested in grouping css and js files. Also I want to version grouped files, so when I modify some stylesheet file and run Gulp again, changes propagate fast to end users. I am talking about adding some random string to each new version of grouped file like /build/css/all-da88553f03.css.

In root directory of your project you will find gulpfile.js. I will modify it according to my needs.


    var elixir = require('laravel-elixir');

    /*
    |--------------------------------------------------------------------------
    | Elixir Asset Management
    |--------------------------------------------------------------------------
    |
    | Elixir provides a clean, fluent API for defining some basic Gulp tasks
    | for your Laravel application. By default, we are compiling the Sass
    | file for our application, as well as publishing vendor resources.
    |
    */

    elixir(function(mix) {
        mix.styles([
            'assets/plugins/bootstrap/css/bootstrap.min.css',
            'assets/css/style.css',
            'assets/css/headers/header-default.css',
            'assets/plugins/font-awesome/css/font-awesome.min.css',
            'assets/plugins/sky-forms-pro/skyforms/css/sky-forms.css',
            'assets/plugins/sky-forms-pro/skyforms/custom/custom-sky-forms.css',
            'assets/css/custom.css',
            'assets/css/home.css'
        ], 'public/css/all.css','./public/');

        mix.scripts([
            'assets/plugins/jquery/jquery.min.js',
            'assets/plugins/jquery/jquery-migrate.min.js',
            'assets/plugins/bootstrap/js/bootstrap.min.js',
            'assets/plugins/back-to-top.js',
            'assets/plugins/smoothScroll.js',
            'assets/js/custom.js',
        ], 'public/js/all.js','./public/');

        mix.version([
            'css/all.css',
            'js/all.js'
        ]);
    });

Syntax is pretty clean, group method accepts 3 arguments here. First is array of assets, second is output destination and the last one is path from root directory to directory where assets are hosted.

After 2 grouping methods are completed gulp will insert 2 newly created files and version them.

Running Elixir

Elixir is built on top of Gulp, so in order to run these tasks I need to issue:


gulp

If everything is completed without errors Gulp will create new build directory in public folder.

Running gulp command each time you modify some asset is a bit boring so you can use gulp watch command. This command is same as running gulp continuously. It will block current terminal window, until you manually stop this command with CTRL+C.

Using newly grouped & versioned assets

In the head section off this view I will replace all css assets with only one file:

    
        <!-- ... some other stuff ... -->

        <!-- Web Fonts -->
        <link rel='stylesheet' type='text/css' href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600&amp;subset=cyrillic,latin'>

        <!-- CSS All -->
        <link rel="stylesheet" href="{{ elixir('css/all.css') }}">

        <!-- Header End -->
    

This elixir() method is very simple. It will use passed string as dictionary key, and it will replace it with the value from the dictionary. Elixir dictionary is located in public/build/rev-manifest.json.

So each time we run gulp these dictionary values will change, but we don't need to worry about updating the links, cause Elixir takes care of that.

Minifying files

Running gulp will only add one file on top of another. To minimize output files you need to run gulp with production flag:


gulp --production

Known issues & fixes

CSS @import & fonts not working

After gulp version files it copies them to build directory. Because of this any css import or any other hard link won't work. For @import directives it is easy, just delete them and append those files to gulpfile.js in order they were imported.

For images you may modify their links or copy related directories to build folder.

Fonts are almost always affected by Gulp, cause font files are using relative links but not from build directory. If you are using Font Awesome fonts you may use some CDN or update the links.

After minification inline JS throws errors

I often leave some parts of inline JavaScript on the page and forgot to move it to separate file and group with the rest of the files. So after I run gulp --production page throws some errors in the console usually Uncaught TypeError: function_name(...) is not a function. This is fixed by minifying all JS code together.

In next post about optimizations you can read how I accomplished 6x faster loading of Laravel site in 15 minutes.

Online computer science courses to jumpstart your future.
WP Engine Managed WordPress Hosting

Trending

Newsletter

Subscribe to our newsletter for good news, sent out every month.

Tags