Grunt

This is a beginner level post about Grunt and Yeoman. Please enjoy! Grunt is a quite popular, JavaScript based task runner which comes as a Node.js module.  At VNGRS, we use Grunt for mainly automation tasks. Some examples of where Grunt is useful are;

  • Analyzing CSS and Javascript code quality with various tools (jshint, csslint).
  • Compiling languages such as  Coffeescript, Less, Sass/SCSS etc. with pre-processors.
  • Minifying CSS, JS files, which are the outcome of this process, to a single file.
  • Compressing images in a project and adding random keys to our file names in order to avoid our files being cached by users.
  • Observing changes at our code without refreshing the browser window manually. (with the help of Livereload)
  • (In case we are not using compass) Converting our images into sprite and forming CSS codes dynamically.
  • ...

This list can go on forever, but long story in short, we ease our workload by automating with Grunt instead of doing everything manually.

Grunt Installation

For Grunt, we need Node.js installed. You can install the suitable version according to your platform from the download page. After Node.js installation is done, let's install Grunt.

If you are planning on using Grunt just once, or want to give it a try, go to the terminal and run:

npm install grunt-cli

If you are planning on using Grunt from now on, you can install Grunt for global use by:

npm install -g grunt-cli

Grunt Extensions Installation

After the default installation, there is a short way of installing the Grunt package by using the command npm install packagename .  However, for a healthier enviroment, we need to have two files named Gruntfile.js and Package.json ;

Gruntfile.js : file where we will organize the jobs of the grunt extensions that we installed

package.json : where we are holding the dependencies of the files that were installed for grunt. ( by npm install packagename --save )

We can  start creating package.json by npm init  while at the project main index on terminal. Now we will answer a couple of questions (name, version, description etc) for generating the content of package.json.

Just for the sake of exercise, we are going to create a task, which will compile a project that we created with compass previously.  Traditionally, we used to do that with compass compile or compass watch. In addition to compiling the project, we want to use Livereload in order to we see the changes at our code without refreshing the browser manually.

In order to use compass through Grunt, we will install Grunt extension by the command npm install grunt-contrib-compass --save and also we would record the dependency that we would install under package.json file. Afterwards with the help of the extension that we would install using npm install grunt-contrib-watch --save, we will be able to observe the changes at our code, instantly. Additionally, we will be able to compile our Sass files and with the same extension in order to make it work with Livereload.

Gruntfile.js

Now we are about to start; since we installed all the extensions, we need to create our Gruntfile.js in order to make them work together. Lets start with compiling our Sass files with compass by using grunt-contrib-compass.

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dist: {
        options: {
          sassDir: 'sass',
          cssDir: 'css'
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.registerTask('default',['compass']);
}

This way, we are completing the adjustments of grunt-contrib-compass under compass parameter. As in config.rb ,we declared our projects main directories for sassDir and cssDir keys. Next, with  grunt.loadNpmTasks(‘grunt-contrib-compass’) command, we will use grunt-contrib-compass in our Gruntfile.js file. For the last part, we will make sure that our compass task will run under grunt by declaring grunt.registerTask(‘default’, [‘compass’]);

Everything is working so far. But this will be not enough if we want to make sure that our changes at the saas files are automoticly compiled each time. Right now, we need to manually type grunt  each time at the terminal in order to preview every change.

It is time to watch file changes and initiate auto compile with compass. We will use the grunt-contrib-watch command to watch the file changes and automatically compile the files through compass. We had installed grunt-contrib-watch upfront. We just need to make the necessary adjustments to Gruntfile.js.

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dist: {
        options: {
          sassDir: 'sass',
          cssDir: 'css'
        }
      }
    },
    watch: {
      css: {
        files: '**/*.scss',
        tasks: ['compass']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('default',['watch']);
}

Now we included the watch function to our Gruntfile.js. The only part that requires attention is the configurations that defines grunt-contrib-watch. We declared which files will be watched at watch.css.files and we declared which tasks will be run upon those changes at the watch.css.tasks.

Since we have tasks in place, it is time to remove the compass by line 22 with grunt.registerTasks part since we have added watch task which will monitor the changes and fire the compass task automatically upon changes.

Great, now it should all be working. It's time to reflect our changes to our browsers open tab with livereload. We will use grunt-contrib-watch again with the livereload feature:

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dist: {
        options: {
          sassDir: 'sass',
          cssDir: 'css'
        }
      }
    },
    watch: {
      css: {
        files: '**/*.scss',
        tasks: ['compass'],
        options: {
          livereload: {
            port: 9000
          }
        }
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('default',['watch']);
}

As a result Grunt will serve us the .js file that will help us use livereload feature at the at the port. After the execution, you can check if you have the javascript file at http://localhost:9000/livereload.js


Since we have the javascript file, we only need to include it in our interface to run livereload feature. Right now, we should have everything set up in order to watch changes at our Saas file changes, compile them automatically with compass and refresh the browser accordingly.

You can check out the codes which are the outcome of the blog through github repo

Extra: Yeoman!

It takes time to create a new Gruntfile.js in each project, so Yeoman is there to help! Yeoman enables us to create our project infrastructure faster by using generators. Generators are basically plugins that can be run with Yeoman to scaffold project parts. For example, it can have a project infrastructure that includes AngularJS by Angular generator.

Let's walk through the basic steps.

As the first step, we install Yeoman with npm install -g yo  globally. Afterwards we find the generator that we want to use at yeoman’s discovering generators site. Let’s use an angular generator. To be able to use the angular generator, we have to install it. Lets follow the instruction at the github page of the generator;

npm install -g generator-angular

We also need to form and get into a new folder to add our files to by mkdir newproject && cd newproject. Now its time to execute our generator and it will initiate the necessary steps for the installation: yo angular [app-name].

Generator will ask us a couple of questions:

Some of them are;

  • Do you want to use Sass (with Compass)?
  • Do you want to include Bootstrap?
  • Do you want to use Sass version of Bootstrap?
  • Which modules do you want to include? (angular-animate.js, angular-cookie.js, angular-resources.js, angular-route.js, angular-sanitize.js, angular-touch.js)

By answering a few questions regarding the technologies that we want to use, we will form our project infrastructure automatically.

To have more information about Yeoman you can check Yeoman’s CodeLab site and the article at tutsplus name Building Apps With the Yeoman Workflow.

:)

Please feel free to use comments for any questions you might have.


Turkish version:

Grunt'ı duymayanımız yoktur. Grunt duyduğumuz, bildiğimiz üzere görev çalıştırıcısı olan bir nodejs modülüdür. Buradaki görevden kastımız nedir, Grunt ile neler yapabiliriz kısmına değinecek olursak;

  • Yazdığımız css ve javascript kodlarını çeşitli kod kalite araçlarıyla (bknz. jshint, csslint) analiz ettirebiliriz.
  • Coffescript, less, sass/scss vb. pre-processor'lerle işlenen kodları derlettirebiliriz.
  • Bu işlemler sonuçu ortaya çıkan css, js dosyalarımızı minified ettirebildiğimiz gibi tek dosya hâline de getirtebiliriz.
  • Projemizde bulunan resimlerimizi sıkıştırabilir ve diğer dosyalarımız dahil olmak üzere son kullanıcı tarafında cache’lenmesini önlemek adına dosya isimlerinin başına/sonuna random key'ler koyarak cache'lenmesini önleyebiliriz.
  • Livereload koyarak kodtaki değişikliklerimizi tarayıcı üzerindeki sekmeyi elle yenilemeden direkt görebiliriz.
  • Eğer compass kullanmıyorsak grunt sayesinde de imajlarımızı sprite hâline getirip dinamik şekilde css kodlarını oluşturabiliriz.
  • ...

bu liste böyle gider. Kısacası bu tarz işlemleri her seferinde el ile kendimiz yapmaktansa yükümüzü Grunt ile otomasyona bağlıyoruz.

Grunt kurulumu

Grunt için Node.js'in kurulu olması gerekmekte. Eğer sisteminizde Node.js kurulu değilse, indirme sayfasından platformunuza uygun yükleme dosyasını indirerek kurulumu yapabilirsiniz.

Node.js'in kurulumunu bitirdikten sonra sıra Grunt'ın kurulumunda. Grunt'ı bir kere kullanacağım, sadece denemek istiyorum diyorsanız terminal üzerinden npm install grunt-cli, hayır, bundan sonra işlerimde grunt'ı kullanmayı düşünüyorum diyorsanız grunt'ı npm install -g grunt-cli diyerek grunt'ı global şekilde kurabilirsiniz.

Grunt eklentilerinin kurulumu

Grunt'ın kurulumundan sonra herhangi bir ayar yapmadan npm install packagename diyerek grunt ile alakalı bir paketin kurulumunu node.js altında yapabilmekteyiz. Fakat daha sağlılı ilerleyebilmek için Gruntfile.js ve package.json adı altında iki dosyaya ihtiyaçımız var.

Gruntfile.js: kurduğumuz grunt eklentilerinin gerçekleştireceği işleri organize edip bir bütün şeklinde çalışmasını sağlayacağımız dosya.

package.json: ise grunt için npm install packagename --save diyerek kurduğumuz eklentilerin, bağımlılıkların tutulacağı dosya.

package.json'u oluşturmak için terminal üzerinde proje anadizinimizdeyken npm init diyerek package.json oluşturma işlemini başlatabiliriz. Bu komut sonrasında terminal bize package.json içeriğini oluşturmaya yönelik sorular (name, version, description vd.) sorarak dosyayı otomatik olarak oluşturacaktır.

Grunt ile örnek yapma adına compass ile yaptığımız projemizi compass compile veya compass watch komutlarıyla değilde grunt üzerinden compile edecek hâle getireceğiz. Ve bunun yanında "Livereload koyarak kodtaki değişikliklerimizi tarayıcı üzerindeki sekmeyi elle yenilemeden direkt görebiliriz."; maddesinde belirttiğim gibi grunt'ın livereload eklentisini kullanarak bu işlevi de sağlayacağız.

Öncelikle compass'ı grunt üzerinde kullanabilmek için npm install grunt-contrib-compass --save diyerek hem grunt eklentimizi yükleyelim, hem de yükleyeceğimiz bu bağımlılığı package.json dosyasında kayıt altında tutmuş olalım. Ardından npm install grunt-contrib-watch --save diyerek yükleyeceğimiz eklenti sayesinde kod taraflı değişiklikleri anlık izleyerek sass dosyalarımızı compile edip aynı eklenti sayesinde livereload yapacağız.

Gruntfile.js

Asıl iş şimdi başlıyor. Eklentileri terminal üzerinden kurduktan sonra bir bütün şeklinde çalışmalarını sağlamak için Gruntfile.js’imi oluşturmamız lazım. Öncelikle grunt-contrib-compass'ı kullanarak grunt aracılığıyla sass dosyalarımızı compass ile compile edelim.

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dist: {
        options: {
          sassDir: 'sass',
          cssDir: 'css'
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.registerTask('default',['compass']);
}

Bu şekilde grunt-contrib-compass'a compass parametresi altında ayarlarını tanımlamış olduk. config.rb'de olduğu gibi sassDir ve cssDir key'lerine projemizin anadizininde bulunan klasörlerimizi belirttik. Ardından grunt.loadNpmTasks('grunt-contrib-compass') diyerek grunt-contrib-compass'ı kullanacağımızdan ötürü Gruntfile.js'e yani grunt'a dahil etmiş olduk. Son olarak grunt.registerTask('default', ['compass']);  diyerek yazmış olduğumuz compass task'ini grunt çalıştırıldığında çalıştırılmasını sağladık.

Şu ana kadar herşey çalışıyor. Fakat güzel değil. Çünkü sass dosyalarında yaptığımız değişiklikler henüz otomatik olarak compile edilmemekte. Grunt dosyamı bu hâldeyken her değişiklik sonunda önizleme için terminal üzerinden grunt diyerek elle compile ettirmemiz gerekmekte.

Sıra grunt-contrib-watch'ı kullanarak dosya değişikliklerini izleyip compass ile otomatik olarak compile ettirmeye geldi. Zaten grunt-contrib-watch eklentisini en başta kurmuştuk. Sadece çalışması için gerekli ayarları Gruntfile.js'e yazmak kaldı.

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dist: {
        options: {
          sassDir: 'sass',
          cssDir: 'css'
        }
      }
    },
    watch: {
      css: {
        files: '**/*.scss',
        tasks: ['compass']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('default',['watch']);
}

Gruntfile.js'imize watch kısmını ekleyerek dosyamızı bu hâle getiriyoruz. Burada dikkat edilmesi gereken nokta grunt-contrib-watch'a tanımlanan ayarlar. watch.css.files'a hangi dosyaların izleneceği ve watch.css.tasks'e ise bu izlenen dosyalar üzerindeki değişiklikler sonuçu hangi task(ler)in çalışacağını belirttik. Ve 22. satırdaki grunt.registerTasks kısmında compass'ı kaldırıp watch task'ini ekledik. Çünkü zaten watch sayesinde izlediğimiz değişikliklerin ardından compass task'i otomatik olarak çalışmakta.

Evet, yine herşey iyi, güzel. Ve bu sefer işimize yaramakta da. Sıra bu değişiklikler gerçekleştikten sonra bu değişiklikleri otomatik olarak tarayıcıdaki açık olan sekmeye yansıtmaya geldi. İşimiz yine grunt-contrib-watch ile. Bu sefer bu eklentinin livereload özelliğini kullanacağız. Bunun için Gruntfile.js'imizi aşağıdaki gibi düzenlememiz gerekmekte.

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compass: {
      dist: {
        options: {
          sassDir: 'sass',
          cssDir: 'css'
        }
      }
    },
    watch: {
      css: {
        files: '**/*.scss',
        tasks: ['compass'],
        options: {
          livereload: {
            port: 9000
          }
        }
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('default',['watch']);
}

Bunun sonuçunda grunt, 9000. portta grunt-contrib-watchın livereload özelliğini çalıştırarak bize livereload özelliğini projemiz üzerine kullanmamızı sağlayacak olan .js dosyayını servis edecek. İsterseniz grunt'ı çalıştırdıktan sonra http://localhost:9000/livereload.js adresine giderek javascript dosyasının varlığını kontrol edebilirsiniz. Şimdi livereload özelliğini kullanabilmemiz için bu javascript dosyasını arayüzümüze eklememiz gerekmekte.

Bu dosyayı ekledikten sonra projemiz üzerinde sass dosyalarında herhangi bir değişiklik yaptığımızda grunt bu değişiklikleri algılayıp sass dosyalarını compass ile compile edip tarayıcıda projenin açık olan sekmesini otomatik olarak yenileyecek.

Yazı sonuçunda ortaya çıkan örneğin kodlarına yazının github reposu üzerinden ulaşabilirsiniz.

Ekstra: Yeoman!

Her proje için en baştan Gruntfile.js oluşturmak hepimiz için vakit kaybı.. Bu durumda imdadımıza Yeoman yetişiyor! Yeoman, barındırdığı generator'ler sayesinde hızlı şekilde proje altyapımızı oluşturmamızı sağlıyor. Örneğin, angular generator'ü ile hızlı bir şekilde angularjs'i barındıran bir proje altyapısına sahip olabiliyor.

Nasıl mı? Öncelikle npm install -g yo ile global şekilde yeoman'in kurulumunu yapıyoruz. Ardından kullanmak istediğimiz generator'ü yeoman'in discovering generators sayfasından buluyoruz. Biz angular generator'ünü örneklendirelim. Angular'ı generatorünü kullanabilmek için öncelikle yüklememiz gerekiyor. Bunun için github sayfasında bulunan yönergeleri izleyerek npm install -g generator-angular diyerek yüklememizi gerçekleştiriyoruz. mkdir newproject && cd newproject komutu ile projemizi bulunduracağımız yeni bir klasör oluşturup içine giriyoruz. Bu dizinde angular-generator'ünü çalıştırıp proje altyapımızı otomatik olarak sorulan sorular doğrultusunda oluşturacağız. yo angular [app-name] diyerek generator'ü çalıştırıyoruz.

Bu komutun ardından karşımıza cevaplamamız gereken birkaç soru gelecek. Bunlardan birkaçı;

  • Sass kullanmak ister misiniz (Compass ile birlikte)?
  • Bootstrap’i dahil etmek ister misiniz?
  • Bootstrap’in Sass versiyonunu kullanmak ister misiniz?
  • Hangi modülleri dahil etmek istersiniz? (angular-animate.js, angular-cookies.js, angular-resources.js, angular-route.js, angular-sanitize.js, angular-touch.js)

şeklinde birkaç soruya projemizin altyapısında kullanmak istediğimiz teknolojiler doğrultusunda cevap vererek proje altyapımızı otomatik olarak oluşturmuş oluyoruz.

Yeoman hakkında daha fazla bilgi edinmek için tutsplus'taki CodeLab sayfasına göz atabilirsiniz.

:)