Blog

Javascript 빌드도구, Grunt 시작하기

January 25, 2014

Javascript 빌드도구, Grunt 시작하기

Grunt

Grunt 0.4 부터는 grunt-cli 를 전역으로 설치하고, 프로젝트마다 grunt를 설치해야한다.

1. Installation

npm install -g grunt-cli
npm install -g grunt-init
npm install grunt // in project folder

grunt --version
> grunt-cli v0.1.12
> grunt v0.4.2

grunt-init --version
> grunt-init v0.2.1
> grunt v0.4.2


npm install grunt --save-dev // in project folder
npm install grunt-contrib --save-dev // in project folder

*참고 `npm install -production`  실행하면 `--save-dev`  저장된 패키지는 설치되지 않는다.

2. grunt-init

grunt-init 을 사용하기 위해선 템플릿을 다운받아야 한다. ~/.grunt-init/ 에 템플릿을 저장하면 된다. 아래는 공식적으로 유지되는 몇가지 grunt-init templates

grunt-init-commonjs : for CommonJS module
grunt-init-gruntfile : Create a basic Gruntfile
grunt-init-gruntplugin : for Grunt plugin
grunt-init-jquery : for jQuery plugin
grunt-init-node : for Node.js module

gruntfile 템플릿을 설치해 보자. 기본으로 package.jsonGruntfile.js 를 생성해준다.

git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile
grunt-init gruntfile // 모두 엔터

3. Gruntfile.js 분석


module.exports = function(grunt) {

  grunt.initConfig({
    meta: {
      version: '0.1.0'
    },
    banner: '/*! PROJECT_NAME - v<%= meta.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
      '* http://PROJECT_WEBSITE/\n' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> ' +
      'YOUR_NAME; Licensed MIT */\n',
    // Task configuration.
    concat: {
      options: {
        banner: '<%= banner %>',
        stripBanners: true,
      },
      dist: {
        src: ['test/config.js', 'test/server.js'],
        dest: 'test/result.js'
      }
    },
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        src: '<%= concat.dist.dest %>',
        // src: ['public/javascripts/**/*.js']
        dest: 'test/result.min.js'
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');

  // Default task.
  grunt.registerTask('ugly', ['uglify']);
  grunt.registerTask('con', ['concat']);
  grunt.registerTask('make', ['concat', 'uglify']);
};

grunt.initConfig 하위에 있는 Task들, uglifyconcat 등은 ‘할일’ 이다. 이것들은 npm install 을 통해 위에서 설치되었으므로, grunt.loadNpmTasks를 통해 등록 된 후에야 사용할 수 있다. option은 각 Github 페이지에 가서 Documentation 을 보면 된다. 중요한 부분은, dist 필드다. src(원본) 을 작업해서 dest (결과) 로 만들어 버린다. 파일의 이름은 [] 배열로서 여러게 지정하거나 아니면 <%= %> 등의 템플릿 기능을 이용해 다른 작업의 결과물을 뽑아 올 수도 있다. 폴더 내에 모든 파일을 대상으로 하고싶다면 uglify.dist.src 부분의 주석처럼 src: ['public/javascripts/**/*.js'] 이렇게 사용하면 된다. 그러면 public 폴더 내에 javascripts 폴더 내에 있는 모든 파일(하위폴더포함)을 대상으로 한다.

마지막으로 이런 세부 Task 들을 모아 밖에서 grunt로 실행할 사용자-실행 Task 를 등록한다. 예를들어

grunt.registerTask('make', ['concat', 'uglify']);

의 경우에는 사용자가 grunt make 를 입력했을때 세부 Task인 concatuglify를 순서대로 실행한다.

4. Grunt : Maximum call stack size exceeded

Grunt 를 실행 시켰을때 Maximum call stack size exceeded Use --force to continue 따위의 메세지가 뜰 수 있는데, 이건 registerTask 로 등록된 이름과 내부 Task 이름이 같아서 그렇다.(아마 파싱 잘못되서 For문 무한으로 돌다가 스택 풀차서 에러나는 것처럼 보임.) 해결방법은, 아래의 코드를 그 아래처럼 변경하자.

grunt.registerTask('concat', ['concat']);  // 둘 다 이름이 같으면 안된다.
grunt.registerTask('concate', ['concat']); // 다르게 만들어주자.

References

  1. Grunt Intro – Slideshare
  2. node-inspector
  3. grunt 0.4 Intro
  4. grunt-init
Array