블로그 이미지
윤영식
Frontend Application Architecter, Full Stacker, KnowHow Dispenser and Bike Rider

Publication

Statistics Graph

Category

Recent Comment

'Build Automation/Grunt, Gulp'에 해당되는 글 3

  1. 2013.01.31 [Grunt.js] Grunt API 활용 - Task 만들기
  2. 2013.01.28 [Build Automation] Javascript code using Grunt.js
  3. 2013.01.28 [Build Automation] Javascript code using Ant
2013.01.31 10:08 Build Automation/Grunt, Gulp

Grunt의 API를 사용하여 Task를 만들어 보자. Grunt의 Task가 핵심으로 한개를 수행하거나 여러개를 동시에 수행할 수도  있다. 


1) Task 별칭 등록하기 

  - grunt.registerTask 로 Task의 별칭을 지정한다

    + api : grunt.registerTask(taskName, taskList)

    + 예 : task.registerTask('default', 'lint qunit concat min'); 

    + grunt 수행시 특정 task를 지정하지 않으면 자동으로 default 별칭의 task가 수행된다 


2) Function Task 만들기

  - grunt.regiterTask 로 Task를 신규로 만들 수 있다

    + api : grunt.registerTask(taskName, description, taskFunction)

    + description, taskFunction을 파라미터로 넘기면 새로운 task 등록됨 

    + fail이 나면 return false 를 해야 한다 

//////////////////////////////////////////////
// grunt.js 환경파일에 등록한다 
  grunt.registerTask('dowon', 'A sample task that logs stuff.', function(arg1, arg2) {
    if (arguments.length === 0) {
      grunt.log.writeln(this.name + ", no args");
    } else {
      grunt.log.writeln(this.name + ", " + arg1 + " " + arg2);
    }
  });

//////////////////////////////////////////////
// 결과
// 아규먼트 없을 때
D:\Development\testing_grunt>grunt.cmd dowon
Running "dowon" task
dowon, no args
Done, without errors.

// 아규먼트 전달 : 이용 
D:\Development\testing_grunt>grunt.cmd dowon:hello:youngsik
Running "dowon:hello:youngsik" (dowon) task
dowon, hello youngsik
Done, without errors.


3) Multi Task 만들기 

  - grunt.registerMultiTask 를 이용하여 만든다

    + api : grunt.registerMultiTask(taskName, description, taskFunction)

    + lint, concat, min task등이 multi task이다 

    + sub-properties (별칭 targets) 이 내부적으로 task가 된다

    + multi task에서는 function에서 특별히 this 키워드를 사용하여 접근한다 

  - grunt.initConfig 안에 target을 만든다 객체명칭 = multi task의 대표 명칭이다 

    + 하기 예제에서 logstuff 가 multi task의 대표명칭이다 

    + grunt.registerMultiTask의 첫번째 아규먼트인 multi task 명칭을 logstuff 로 일치시킨다 

    + 등록한 function에서 this 함에 주의*

//////////////////////////////////////////////
/*global config:true, task:true*/
grunt.initConfig({
  logstuff: {
    foo: [1, 2, 3],
    bar: 'hello world',
    baz: false
  }
});

grunt.registerMultiTask('logstuff', 'This task logs stuff.', function() {
  // this.target === the name of the target
  // this.data === the target's value in the config object
  // this.name === the task name
  // this.args === an array of args specified after the target on the command-line
  // this.flags === a map of flags specified after the target on the command-line
  // this.file === file-specific .src and .dest properties

  // Log some stuff.
  grunt.log.writeln(this.target + ': ' + this.data);

  // If data was falsy, abort!!
  if (!this.data) { return false; }
  grunt.log.writeln('Logging stuff succeeded.');
});

//////////////////////////////////////////////
// 결과
// target을 지정하지 않았을 때는 전체 target이 수행
D:\Development\testing_grunt>grunt.cmd logstuff
Running "logstuff:foo" (logstuff) task
foo: 1,2,3
Logging stuff succeeded.

Running "logstuff:bar" (logstuff) task
bar: hello world
Logging stuff succeeded.

Running "logstuff:baz" (logstuff) task
baz: false
 Task "logstuff:baz" failed. Use --force to continue. 

Aborted due to warnings.

// foo target을 지정
D:\Development\testing_grunt>grunt.cmd logstuff:foo
Running "logstuff:foo" (logstuff) task
foo: 1,2,3
Logging stuff succeeded.

Done, without errors.

// bar target을 지정 
D:\Development\testing_grunt>grunt.cmd logstuff:bar
Running "logstuff:bar" (logstuff) task
bar: hello world
Logging stuff succeeded.

Done, without errors.

// baz target에서 false return하면서 warning 발생함 
D:\Development\testing_grunt>grunt.cmd logstuff:baz
Running "logstuff:baz" (logstuff) task
baz: false
 Task "logstuff:baz" failed. Use --force to continue. 

Aborted due to warnings.


4) Init Task 만들기 

  - api : grunt.registerInitTask(taskName, description, taskFunction)

    +최초에 수행되는 init task를 수행하고 별도의 환경 설정 데이터도 필요없다 


5) Task명칭 바꾸기 

  - api : grunt.renameTask(oldname, newname)



6) Inside Tasks 알아보기 

  - grunt의 this 에는 여러 유용한 properties 와 method를 가지고 있다. grunt.task.current 로 expose 한다 

  - Task에서 구현하는 function에서 사용한다 

  - this.async / grunt.task.current.async

    + task를 비동직적으로 수행시켜 준다 

//////////////////////////////////////////////
// Tell grunt this task is asynchronous.
var done = this.async();
// Your async code.
setTimeout(function() {
  // Let's simulate an error, sometimes.
  var success = Math.random() > 0.5;
  // All done!
  done(success);
}, 1000);


  - this.requires / grunt.task.current.requires : 의존관계있는 task를 열거

  - this.requiresConfig / grunt.task.current.requiresConfig : config properties 열거 

  - this.name / grunt.task.current.name : 등록된 task 명칭 

  - this.nameArgs / grunt.task.current.nameArgs : grunt뒤의 아규먼트들 예) grunt.cmd task1:foo  -> task1:foo 

  - this.args / grunt.task.current.args : task명칭을 뺀 실제 아규먼트값을 배열로 리턴

  - this.flags / grunt.task.current.flags : 아규먼트를 만들어준다 

  - this.errorCount / grunt.task.current.errorCount : task에서 발생한 에러건수 


7) Indside Multi Tasks 알아보기 

  - this.target / grunt.task.current.target : multi task에서만 사용. config data로 등록된 key (name) 값 

  - this.data / grunt.task.current.data : multi task에서만 사용. config data로 등록된 value 값

  - this.file / grunt.task.current.file : compact format 사용시 this.file.src , this.file.dest 가 만들어진다 (template api 참조)



8) 외부에서 정의된 Task 로딩하기 

  - 큰 프로젝트에서 sub 프로젝트끼리 공유하기 위하여 task와 helper 들을 만든다 

  - 여러 디렉토리에서 task를 로딩하거나 또는 Npm-installed grunt plugin 을 로딩한다 

  - task 관련 파일들 로딩하기 

    + api : grunt.loadTasks(tasksPath)

  - task와 helper 로딩하기 

    + api : grunt.loadNpmTasks(pluginName)

  - npm module 호출 

    + api : grunt.npmTasks(npmModuleName)



9) Helper 정의하고 실행하기 

  - 이미 만들어지 helper들 존재 (참조)

  - helper 만들기 

    + api : grunt.registerHelper(helperName, helperFunction)

//////////////////////////////////////////////
grunt.registerHelper('add_two_nums', function(a, b) {
  return a + b;
});

  - helper 이름 바꾸기 

    + api : grunt.renameHelper(oldname, newname)


  - helper 호출하기 

    + api : grunt .helper(helperName, [, agruments...])



10) Warning 과 Fatal Error

  - api 호출하여 화면에 출력 한다 

  - grunt.warn(error [, errorCode])

  - grunt.fatal(error [, errorCode])



<참조>

  - Grunt API

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
TAG Grunt.js
2013.01.28 17:48 Build Automation/Grunt, Gulp

이전에 Ant를 이용하여 Javascript project를 build하는 것을 알아 보았다. 요즘은 Grunt.js라는 빌드도구가 나와서 많이 사용되고 있고, Javascript 에 최적화 되어 있기때문에 앞으로는 Grunt.js를 사용한다. Grunt.js에 대해서 알아보자 


1) 준비하기

  - node.js 와 npm 설치되어 있어야 한다 

  - 기본 설치 : npm uninstall -g grunt  ==> npm install -g grunt-cli

  - 부가 설치 : npm install grunt-contrib

  - grunt.js (gruntfile)이 핵심 구성내역

    + 프로젝트 환경

    + grunt plugins 또는 tasks 폴더 로딩

    + Tasks 와 Helpers



2) Task 만들기 

  - 환경파일 만들기 (node.js 모듈로 생성) :  grunt init:gruntfile  명령 수행하면 Gruntfile.js 파일 생성됨(grunt 환경파일)

    + 윈도우 : grunt.cmd init:gruntfile 수행

  - grunt.js 파일안에 task 열거 lint, qunit, concat, min, watch, jshint, testuglify

    + lint : 자바스크립트 문법오류 가능성 있는 것 체크

    + qunit : Unit test를 위하여 QUnit을 사용 (PhantomJS이용)

    + concat : 지정된 디렉토리/파일을 1개의 파일로 합침

    + min : 파일사이즈 minify 최소화

    + mincss : css 최소화 

    + watch : node.js::fs 모듈의 watch 메소드 사용하여 파일 변경사항 발생시 task를 수행한다 

    + 사용가능 task 목록 보기 : grunt -h 


// grunt.js 파일 내역 
/*global module:false*/
module.exports = function(grunt) {
  // Project configuration.
  grunt.initConfig({
    pkg: '',
    meta: {
      banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
        '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
        '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' +
        '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
        ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
    },
    lint: {
      files: ['grunt.js', 'lib/**/*.js', 'test/**/*.js']
    },
    qunit: {
      files: ['test/**/*.html']
    },
    concat: {
      dist: {
        src: ['', '.js>'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    min: {
      dist: {
        src: ['', ''],
        dest: 'dist/<%= pkg.name %>.min.js'
      }
    },
    watch: {
      files: '',
      tasks: 'lint qunit'
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        browser: true
      },
      globals: {}
    },
    uglify: {}
  });

  // Default task.
  grunt.registerTask('default', 'lint qunit concat min');
};

  - module.exports = function(grunt){...}; 를 딱 한번만 grunt.js 에 표기한다 (module.exports 참조)

    + 가급적 module.exports를 사용한다 (exports 사용안함)

  - grunt.initConfig({...}); 에 환경설정 한다 

  - 환경 설정 참조 파일 : javascript-hooker/grunt.js

  - 일반 설정 사항

// Project configuration.
grunt.initConfig({
  // Project metadata, used by some directives, helpers and tasks.
  meta: {},
  // Lists of files to be concatenated, used by the "concat" task.
  concat: {},
  // Lists of files to be linted with JSHint, used by the "lint" task.
  lint: {},
  // Lists of files to be minified with UglifyJS, used by the "min" task.
  min: {},
  // Lists of files or URLs to be unit tested with QUnit, used by the "qunit" task.
  qunit: {},
  // Configuration options for the "server" task.
  server: {},
  // Lists of files to be unit tested with Nodeunit, used by the "test" task.
  test: {},
  // Configuration options for the "watch" task.
  watch: {},
  // Global configuration options for JSHint.
  jshint: {},
  // Global configuration options for UglifyJS.
  uglify: {}
});

  - plugins 또는 task를 로딩한다

// TASK
// Load tasks and helpers from the "tasks" directory, relative to grunt.js.
grunt.loadTasks('tasks');

// PLUGIN
// Load tasks and helpers from the "grunt-sample" Npm-installed grunt plugin.
grunt.loadNpmTasks('grunt-sample');


3) 사용하기 : grunt <task>

  - lint 수행 : grunt lint 

  - min 수행 : grunt min 

  - grunt 명령으로 default 수행 만들기 : grunt.registerTask('default', 'lint test concat min mincss'); 



4) Grunt.js & Yeoman 이해하기 


<참조>

  - Grunt.js Getting Started

  - Grunt.js 소개

  - 사용하기 : Outsider님 블로깅

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
TAG Grunt.js
2013.01.28 09:05 Build Automation/Grunt, Gulp

참조의 원문에 대해서 테스트 해하고 글을 정리해 본다. JavaScript에 대한 빌드 자동화를 ant로 하는 방법을 알아보자.


Javascript코드에 대해 Ant를 이용하여 Java의 Maven처럼 compile -> test -> build를 자동으로 수행할 수 있는 방법을 소개하고 있다. 하지만 현재는 gruntjs를 통하여 본 글에서 수행하였던 것을 보다 더 쉽게 할 수 있다. gruntjs에서 하나 단점은 shell command 호출인데 grunt-jasmine-task를 통해  극복하였다. 


1) JavaScript 대응 테스트 & 빌드자동화 도구들

  - 구문오류 체크 : JSLint / JSHint 

  - 유닛 또는 행휘 테스트 : Jasmine 또는 QUnit

  - API 문서 생성 : JSDoc

  - JS 파일압축 : YUI compressor 또는 Uglify.js 

  - 위의 내역들 빌드 통합 수행 : Ant


각 내역들에 대해서 순차적으로 수행하는 것을 Ant로 만들어 보도록 한다 


2) Ant로 구현한 Build Automation 구조

  - GitHub 소스 : git clone https://github.com/creynders/Build-JS-example.git  수행하여 로컬에 내려 받는다 

  - Ant로 하다 보니 1)에서 필요로 하는 모든 프레임워크 라이브러리를 다운로드 받아 놓아야 한다   

   

  

  - 디렉토리 구조 

    + bin : ant의 destination 디렉토리, 배포되는 최종 .js 파일이 위치함 

    + docs : API 문서 생성 디렉토리 

    + lib : 3-rd party 도구들 

    + specs : unit test 파일 존재 (test 파일이 specification 즉, 명세라는 표현이 맘에 든다)

    + src : 원본 소스 


3) 도구 설명

  - Apache Ant : 의존관계를 만들어서 타겟소스에 대하여 빌드를 수행케 하는 command-line 도구 (다운로드)

  - JSHint : JSLint 기반의 자바스크립트를 위한 code 품질 측정 도구. 에러나 문제가능성 있는 것을 찾아줌 (다운로드)

  - JSDoc Toolkit : HTML (XML, JSON, TEXT) 포멧으로 자바스크립트 애플리케이션에 대한 자동 문서 생성 도구 (다운로드)

  - YUI compressor : 압축을 통하여 네트워크 전송 성능을 높여준다. (다운로드)

  - Jasmine : 자바스크립트 코드 테스트를 위한 행위지향 개발 프레임워크(behavior-driven) (다운로드)

  - PhantomJS : 자바스크립트에 대해서 브라우져 없이(without GUI client) 없이 브라우징이 가능토록 해준다 (다운로드)

    + 즉, HTML 파일의 parse & rendering을 해준 다음 수행하고 결과값 읽고 ant에게 전달한다 (Headless WebKit)

    + OS 버전에 맞는 것을 다운로드 받은후 path를 잡아준다

    + 좀 더 쉽게 사용할 수 있도록 casperjs 도 있다. (요걸 사용하는게 좋을듯)


4) 소스 빌드 프로세스 (순서)

  - 원본 소스는 3개 존재 : buildexample.js, Baz.js, Foo.js

    + buildexample.js에서 namespace를 정의한다 

  - 모든 .js 파일에 대해 JSHint를 통해서 QA tool을 수행한다 

  - unit test를 수행한다

  - 3개의 개별 .js 파일을 1개의 .js 파일로 통합한다

  - 한개의 파일을 축소된(minified) .js 파일로 나눈다 

  - API 문서를 생성한다 

  - 통합하고 축소화한 파일명칭과 API 문서에 version number를 사용한다 


5) build.xml 작성하기 

  * properties : 상수 속성값을 설정. build.properties

  * tasks : ant 수행전 전처리 환경 내역들 

  * targets : 각 단계에 대하여 ant에 task로 구분하여 설정. build.xml


  - 버젼 (Version Number)

    + version.txt 파일을 읽는다 

    + 테스트 : ant version

<target name="version">
    <loadfile property="version.old" srcFile="version.txt" />
    <input message="Current version number is ${version.old}. Please enter the new version number:"
        defaultValue="${version.old}" addproperty="version"/>
    <echo file="version.txt" message="${version}" />
</target>


  - 속성 선언(Properties Declaration)

    + build.properties 파일을 사용한다 

    + build.uer.properties에 속성 재정의 한다 

<target name="properties">
    <tstamp>
        <format property="timestamp" pattern="yyyyMMddHHmmss"/>
    </tstamp>
    <!-- allow user-specific overrides -->
    <property file="build.user.properties"/>
    <property file="build.properties"/>
</target>


  - 빌드 디렉토리 생성 

   + build 디렉토리 생성한다 : 생성 temporary 파일이 위치한다. 빌드과정이 성공하면 bin에 파일이 위치한다.

<target name="create_build" depends="properties">
    <echo>Creating build...</echo>
    <delete dir="${dir.build}" />
    <mkdir dir="${dir.build.current}" />
    <echo>Finished.</echo>
</target>


  - 파일 하나로 합치기 (Consolidation)

   + src 디렉토리의 buildexample.js를 복사해서 build 디렉토리에 buildexample-.js 로 넣는다

   + 다른 파일들을 buildexample-.js 에 포함시키고 version과 timestamp를 넣는다 

<target name="consolidate" depends="properties, create_build">
    <echo>Consolidating...</echo>
    <copy file="${dir.src}/${name.base.js}" tofile="${file.consolidated.js}"/>
    <replace file="${file.consolidated.js}" token="%VERSION%" value="${version}"/>
    <replace file="${file.consolidated.js}" token="%TIMESTAMP%" value="${timestamp}"/>
    <concat id="srcfiles" destfile="${file.consolidated.js}" append="true>
        <fileset dir="${dir.src}" includes="**/*.js" excludes="${name.base.js}"/>
    </conca>
    <pathconvert pathsep=";" property="files" refid="srcfiles"/>
    <echo>${files}</echo>
    <echo>Finished.</echo>
</target>


  - JSHint 구문 검사 (코드 품질 측정)

    + PhantomJS를 통하여 수행한다 (PhantomJS API)

    + phantom-jshint-runner.js 파일로 jshint.js를 수행토록 한다 (lib 디렉토리에 존재)

<target name="jshint" depends="properties, consolidate">
    <echo>Checking syntax...</echo>
      <exec executable="phantomjs" dir="${basedir}" failonerror="true" resultproperty="specs.results">
          <arg line="'${file.jshint-runner.js}'" />
          <arg line="'${file.jshint.js}'" />
          <arg line="'${file.consolidated.js}'" />
          <arg line="${timeout.phantom}" />
      </exec>
    <echo>Finished</echo>
</target>


  - Jasmine 테스트에서 .html 파일 수행 (specs/index.html 존재)

    + PhantomJS를 통해 html을 읽어와 파싱하고 결과값을 ant로 반환한다

    + phantom-jasmine-runner.js 파일을 작성한다 (web 애플리케이션 headless test 방법)

<target name="specs" depends="properties">
    <echo>Running specs...</echo>
    <exec executable="phantomjs" dir="${basedir}" failonerror="true" resultproperty="specs.results">
        <arg line="'${file.jasmine-runner.js}'" />
        <arg line="'${file.specs-runner.html}'" />
        <arg line="${timeout.phantom}" />
    </exec>
    <echo>Finished.</echo>
</target>


  - 압축 (Minifying)

    + YUI compressor를 사용한다 (사용법)

    + command line 사용 :  java -jar yuicompressor-x.y.z.jar [options] [input files]

<target name="minify" depends="properties,create_build, consolidate">
    <echo>Minifying...</echo>
    <exec executable="java" dir="${basedir}" failonerror="true">
        <arg line="-jar '${file.yui_compressor.jar}'" />
        <arg line="--type js" />
        <arg line="-o '${file.minified.js}'" />
        <arg line="'${file.consolidated.js}'" />
    </exec>
    <echo>Finished</echo>
</target>


  - JSDoc 파일 생성 

    + command line 사용 : java -jar jsrun.jar app/run.js myscript.js -t=templates/jsdoc

<target name="jsdocs" depends="properties, consolidate">
    <echo>recreating docs folder...</echo>
    <delete dir="${dir.docs}"/>
    <mkdir dir="${dir.docs}" />
    <echo>Generating...</echo>
    <exec executable="java" dir="${basedir}">
        <arg line="-jar '${file.jsdoc_toolkit.jar}' '${dir.jsdoc_toolkit}/app/run.js'" />
        <!-- -d tells JSDoc toolkit where to output the documentation -->
        <arg line="-d='${dir.docs}'" />
        <!-- use the default template -->
        <arg line="-t='${dir.jsdoc_toolkit}/templates/jsdoc'" />
        <!-- Create an arg element for each file you want to include in the documentation -->
        <arg line="'${file.consolidated.js}'" />
    </exec>
    <echo>Finished</echo>
</target>


  - Clean up

    + build 디렉토리 파일이 빌드가 성공하면 bin 디렉토리로 옮긴다 

<target name="finish" depends="properties">
    <echo>Finishing...</echo>
    <delete dir="${dir.bin}" />
    <mkdir dir="${dir.bin}" />
    <move file="${dir.build.current}" tofile="${dir.bin}"/>
    <echo>Finished.</echo>
</target>


  - 각 target을 한꺼번에 수행하기 

<target name="build" depends="version, properties, create_build, consolidate, jshint, specs, minify, jsdocs, finish">
</target>


  - 수행 : ant build

$ ant build

Buildfile: d:\git-repositories\build-automation-javascript\build.xml


version:

    [input] Current version number is 1.0.0. Please enter the new version number: [1.0.0]

1.0.1   <== 직접 입력


properties:


create_build:

     [echo] Creating build...

   [delete] Deleting directory d:\git-repositories\build-automation-javascript\build

    [mkdir] Created dir: d:\git-repositories\build-automation-javascript\build\20130128154436

     [echo] Finished.


consolidate:

     [echo] Consolidating...

     [copy] Copying 1 file to d:\git-repositories\build-automation-javascript\build\20130128154436

     [echo] concat (d:\git-repositories\build-automation-javascript\src\Baz.js;d:\git-repositories\build-automation-javascript\src\Foo.js)

     [echo] Finished.


jshint:

     [echo] Checking syntax...

     [exec] read: d:\git-repositories\build-automation-javascript/build/20130128154436/buildexample-1.0.1.js

     [echo] Finished


specs:

     [echo] Running specs...

     [exec] open: file:///D:/git-repositories/build-automation-javascript/specs/index.html

     [exec] success

     [exec] finished in 218ms.

     [exec] 2 specs, 0 failures in 0.196s

     [echo] Finished.


minify:

     [echo] Minifying...

     [echo] Finished


jsdocs:

     [echo] recreating docs folder...

   [delete] Deleting directory d:\git-repositories\build-automation-javascript\docs

    [mkdir] Created dir: d:\git-repositories\build-automation-javascript\docs

     [echo] Generating...

     [echo] Finished


finish:

     [echo] Finishing...

   [delete] Deleting directory d:\git-repositories\build-automation-javascript\bin

    [mkdir] Created dir: d:\git-repositories\build-automation-javascript\bin

     [move] Moving 2 files to d:\git-repositories\build-automation-javascript

     [echo] Finished.


build:


BUILD SUCCESSFUL

Total time: 16 seconds


* 현재는 Grunt를 많이 사용하고 있다. (참조)


<참조>

원문 : Automating JavaScript builds

저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
prev 1 next

티스토리 툴바