Case Study: LunApps.com Landing Page Build System Using Grunt

grunt-logo

How would you describe a perfect website? Well, an ideal website in a perfect world should pull off all of the following:

  • Be simple in maintenance and easily updatable
  • Work fast
  • Take as little resources as possible

Considering the fact that most of the website content is dynamic these days, taking care of all those three tasks at the same time gets hard as hell! That’s exactly why people tend to use CMS systems like WordPress – they are easy-to-use and practically all-purpose.

Granted, aforementioned CMS software is highly optimized by cool programmers. Plus, there are lots of plugins like WP Super Cache to speed it all up. Nevertheless:

  1. Pretty often CMS software works quite slowly. After all, no matter how super-optimized a server-side app is, straight static HTML files kick asses when it comes to speed.
  2. Even half of the features of the system are often not used for simpler websites, for example – user-generated content is not present on smaller sites.
  3. These CMS systems take a lot of resources.
  4. If not maintained and configured properly, CMS Software can be vulnerable to external security threats.

How do I build my perfect site then?!

But what if we want to take the best of two worlds and have a templating system for a website that has dynamic content which is not user-generated (e.g., a landing page), but save resources on a CMS? And how could we make it work for mobile clients as well?

Of course, we could use WordPress with WP Super Cache or an alternative combo, but it would still require us to run a database and do a lot of configuration.

As a result, we will have a big system running, but we will ever use only a tiny part of the available features. Also, this system will still sometimes be quite slow.

P.S. Don’t tell anyone … but Lunapps use WordPress with WP Super Cache! But hey, relax! We only make use of it for our blog, not for the main site 🙂

Now let’s talk about a solution that would help us juggle with all three perfect website traits at the same time!

-Everybody, it’s Grunt! -Grunt, it’s everybody!

Grunt-JavaScript

Now that you met Grunt let us tell you about the chap a bit more. Here’s a question: “What is Grunt?”. And here’s the answer: “Grant is a Task Runner”.
Its main goal is automation and to tell you the truth – it’s goddamn good at it!

Why use Grunt?

With Grunt all you need to do is define a configuration and the compilation of static files from templates becomes a matter of one single click. After that you simply upload the files to your web server. Here’s what you’ll get if you use Grunt:

  1. A landing page that uses template system. This allows you to define all the styles and markup once and then reuse it many times after. In addition, it lets you focus on simply adding and editing new content, as opposite to working with a raw HTML files.
  2. Well optimized assets (all the scripts and HTML are reduced in size, all images are optimized etc.). This is crucial when it comes to displaying your website on mobile platforms.
  3. Simpler system. The thing is – Grunt doesn’t use any sort of databases to store content, which eliminates a big layer from the system – everything is defined in the config files or templates (depends on how you implement it).

Of course, you can add stuff like email subscription with small scripts that need to be run on the server and may need a database, but it would be taking gazillion times less resources than a full-blown website with a database which stores everything.

So why would I use Grunt?

To sum it up – if your landing page or website doesn’t require any user-generated content you can go with a Task Runner like Grunt. This way you’ll easily build a website from templates to HTML with CSS and JS, and then simply upload them to your server.

Besides, this system can be used for regular sites as well. You can have a part of your site compiled with Grunt and at the same time another part can stay dynamic. We often use this trick for admin panels for our mobile apps’ BackEnds.

site-screen-2

Integrating Grunt

Let us share our experience of setting up Grunt and using it for your needs. Follow our step by step on how to use Grunt for improving site loading speed.

Part #1 – Installing parts of the system

Step #1 – Install NodeJS and Grunt

First thing you need to install is NodeJS. Then, using npm, init your project, install grunt and grunt-cli both locally and globally:

npm init
cd [your project folder]
npm install –g grunt grunt-cli
npm install grunt --save-dev

Step #2 – Install an HTML template engine

Once the basic setup described above is complete you should decide which template engine for HTML to use. Performance isn’t important here (building a website is basically one-off task). That’s why we decided to go with Jade.

The reason for picking out Jade is simple – its syntax is easy to grasp even on-the-fly as long as you know a bit of HTML. This means we will need Jade compiler for Grunt:

npm install grunt-contrib-jade --save-dev

Step #3 – Set up a stylesheet language

This step is optional. Our team decided to use a different stylesheet language as an alternative to CSS called Less. In this case, you will need a Grunt package for Less as well.

npm install grunt-contrib-less --save-dev

Step #4 – Install additional modules

On top of all that we also used the following modules:

  1. grunt-contrib-clean – to remove files from the previous build
  2. grunt-contrib-cssmin – to reduce the resulting CSS files in size (after Less to CSS compilation)
  3. grunt-contrib-compress – to gzip-compress the files after the build is complete – this works well in pair with gzip_static module of nginx
  4. grunt-contrib-copy – to copy JS and CSS libraries over to the build folder
  5. grunt-contrib-uglify – to both combine all our JS files into one and reduce the size of the resulting file
  6. grunt-sitemap-xml – to build a sitemap of the landing page for better search indexing

As you can see, we used an extensive list of packages here. You can find a lot of other good packages for Grunt that you might want to use (for example, this markdown compiler). Do not hesitate to use other packages if they can make your life easier!

Part #2 – Design your project’s folder structure

In order to turn your future relationship with Grunt into one big honeymoon you should think of a reasonable folder structure for your project. No doubt, defining all kinds of paths for Grunt tasks will make the work with it easy as pie.

You can check out the folder structure we designed for our project:

  • A bunch of static folders that were copied over as-is to the build folder
  • A build folder (containing the result of running Grunt)
  • A folder with the views (jade templates should go here)
  • A folder for JS files
  • A folder for Less files

folder-structure

Part #3 – Create the Gruntfile

Your last step for Website performance optimization with Grunt would be Gruntfile creation.
In this file you will need to define all your tasks and their options.

We’re not going to provide a full explanation because the most of it is actually just a list of paths to different places that Grunt should know about! We’ll give you description of its structure instead.

Once you’re done creating your Gruntfile you only have to open a terminal window, go to the project’s folder, and type in “grunt”. If the build gives out no errors – your site is ready for deployment!

Now, let’s give a description of the Gruntfile!

The structure of a Gruntfile

The first thing you write in your Gruntfile is this code for export:

module.exports = function (grunt) {

};

Gruntfile exports just one function that takes Grunt instance as an argument. Everything described here goes inside this function.

Then you need to load all the tasks you’re going to use:

grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-jade');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-sitemap-xml');

After that you’ll need to configure each and every task you just loaded. You can do that with the help of grunt.initConfig method, like in the following code snippet (we gave an example of uglifyjs, it has one of the longest possible configurations though):

grunt.initConfig({
    uglify: {
        options: {
            mangle: true,
            compress: {
                drop_console: true,
                dead_code: true,
                properties: true,
                drop_debugger: true,
                conditionals: true,
                comparisons: true,
                booleans: true,
                loops: true,
                unused: true,
                if_return: true,
                join_vars: true,
                keep_fargs: true,
                keep_fnames: true
            }
        },
        'compile-prod': {
            files: [{
                expand: true,
                cwd: 'js',
                src: ['**/*.js', '!*/*.min.js'],
                dest: 'build/js',
                ext: '.js',
                extDot: 'last'
            }]
        }
    }
});

Here, uglify is the task name. Options object is an object that goes to uglifyjs as a parameter, i.e. unchanged. What we do next is define ‘compile-prod’ subtask of uglify, then inside of it we determine the files uglifyjs should take and where it should output the result of its work.

Working with uglifyjs was tough at first, especially because we had to handle with *.min.js files in an unusual way. Plus, we needed to output one file, not many.

On top of that, the amount of different options is pretty huge, so it took a while to grasp all of them, but it was worthwhile – it is awesome at what it does!

A simpler task definition might look like this:

grunt.initConfig({
    clean: {
        'compile-prod': ['build/']
    }
});

It simply tells Grunt that this task should clean the build directory.
Every task in the Gruntfile is defined as easy as that! You just tell it where to grab files and where to put the result.

Finally, the last part of a Gruntfile is definition of the tasks you can run from the command prompt.

console

For example, we had these (all the subtasks run in order that’s specified in the task definition):

grunt.registerTask('default', [
    'clean:compile-prod',
    'less:compile-prod',
    'less:compile-blog',
    'jade:compile-prod',
    'copy:compile-prod',
    'copy:script-develop',
    'connect:server',
    'watch']);

grunt.registerTask('compile-prod', [
    'clean:compile-prod',
    'less:compile-prod',
    'jade:compile-prod',
    'copy:compile-prod',
    'cssmin:compile-prod',
    'uglify:compile-prod',
    'sitemap_xml',
    'compress:compile-prod']);

default is the task that runs on grunt command. Other tasks can be run with the help of grunt [task-name] command.

In this case we had a development task (a default one) that would track files for changes and then update them, and run a local copy of the website. We also had a production task that would compile the actual version for deployment.

And that’s about it! Once you’re done with all above you’ll only have to configure your web server (which is also simple, you just have to set the path to the right folder – no PHP, or any other scripting language at that, needed here!).

You can improve website speed with Grunt Grunt with our Nginx SSL Setup. Also, using a NodeJS backend for simple features (like email subscription that we paired with this system) might be just the right choice for you!

Conclusion

To sum it all up – Grunt is a good way to create a high-speed landing page that’s easy to manage. With Grunt you can also develop a website that handles small set of functions (like email subscription) and at the same time needs to be dynamic.

It can help you save resources (money you spend on the server) and time. We suggest you to improve website loading speed using Grunt if:

  1. Your site has almost no user-generated content (landing pages, small company sites etc.)
  2. Your site has no need to be updated by multiple users at the same time
  3. You want to automate building a part of or your full website

If you have any questions regarding your future project, feel free to contact us. We kick asses when it comes to developing apps with smart custom design!

P.S. Here’s our complete Gruntfile 😉

Comments