Gulp 사용법 #3 (gulp-uglify, gulp-rename)
Gulp Plugin - gulp-uglify, gulp-rename
지난 포스팅에서 gulp 설치와 대략적인 gulp 문법, 그리고 gulp 플러그인을 다운받은 후 간단한 gulpfile.js 를 작성해 보는 시간을 가졌습니다.
이번 글에서는 프론트 엔드에서 많이 사용되는 다양한 플러그인을 설치하고 그에 따른 gulpfile.js 를 한 단계, 한 단계 작성해 보도록 합니다.
gulp 는 앞서 설명했듯이 node.js 스트림 기반의 task runner 입니다.
반복적으로 발생하는 노가다성의 작업들을 빌드를 함으로서 필요한 작업을 보다 쉽게 처리할 수 있도록 gulp(자동화 빌드 시스템) 란 유용한 도구를 이용해 처리할 수 있습니다.
gulp 의 작업흐름 방식은 다음과 같습니다.
위 이미지에서 보았듯이 gulp 는 stream 기반의 build system 이라고 알려져 있습니다.
node.js의 특징인 event-driven, non-blocking I/O 를 바탕으로, 요청 후 한번에 결과를 받는 것이 아니라 이벤트로 중간중간 전달받는 방식을 stream이라고 하는데, 이 stream 을 기반으로 하고 있기 때문에 실제로 작업 속도도 비교적 더 빠른 것으로 알려져 있습니다.
그리고 gulp 의 task 는 pipe 로 연결되는데(node.js stream의 그 pipe 와 같다), 작업 대상 파일들이 pipe 를 따라 흘러가며(stream) 병렬로 동시에 여러 task를 수행하게 됩니다.
전체적인 프로세스를 살펴보자면 gulp 는 위 이미지처럼 gulp.src()
를 통해 파일을 읽어오고 gulp.pipe()
에서 수행된 일련의 작업들을 통해 결과물로 파일을 쓰게 되는 과정을 거치게 됩니다.
이제 본격적으로 프론트 엔드에서 많이 사용되고 있는 유용한 gulp 의 플러그인에 대해 알아보고 gulpfile.js 를 작성해 보도록 합니다.
gulpfile.js & Gulp Tasks
프론트엔드 빌드 과정에서 성능 최적화를 위한 작업 중 하나는 JavaScript 파일을 Minify(혹은 Uglify, 난독화)하는 작업입니다.
JavaScript 파일에 포함된 주석, 공백 등을 제거하고 변수명 등을 짧게 바꾸는 등의 작업을 거쳐 용량을 줄이고 압축하여 JavaScript Engine 이 보다 빠르게 JavaScript 파일을 해석할 수 있도록 도와줍니다.
JavaScript Minify(Uglify)
바로 언급한 내용의 작업들을 수행해주는 gulp-plugin 이 다수 존재하는데 그 중에 가장 인기있는 gulp-uglify 라는 플러그인을 사용해서 해당 task 를 수행해 보도록 하겠습니다.
먼저 아래와 같이 npm 을 이용하여 gulp-uglify 플러그인을 설치하도록 합니다.
$ npm i gulp-uglify -D
i 는 install의 약어, -D 는 --save-dev 의 약어입니다.
설치가 끝났다면 이 플러그인을 사용해서 직접 파일을 다루는 빌드 작업을 해도록 하겠습니다.
참고로 이전 포스팅에서 다룬 gulp-concat 의 task 와 관계하여 빌드 수행을 하도록 하겠습니다.
이전 task 에서 수행한 gulp-concat 은 다음과 같습니다.
// gulp load (gulp modules 호출)
var gulp = require('gulp');
// Gulp 의 concat 패키지 로드
var concat = require('gulp-concat');
// Gulp.task()를 사용해 gulp-concat 업무 수행을 정의
gulp.task('concat:js', function () {
return gulp
// js 하위 디렉터리 내의 모든 자바스크립트 파일을 가져온다.
.src(['project/src/js/**/*.js'])
// 상단에서 참조한 concat 모듈을 호출하고 병합할 파일네이밍을 정의
.pipe( concat('conbined.js') )
// 위에서 수행한 task 를 배포지(dist)에 파일을 생성한다.
.pipe( gulp.dest('project/dist/js') );
});
// $ gulp 명령어만 수행하기 위해 'default' 로 정의, 의존 모듈 concat:js 정의
gulp.task('default', ['concat:js']);
gulp-uglify
를 수행하기 위해 아래와 같이 작성하도록 합니다.
// gulp load (gulp modules 호출)
var gulp = require('gulp');
// Gulp 의 concat 패키지 로드
var concat = require('gulp-concat');
// uglify 플러그인 로드(호출)
var uglify = require('gulp-uglify');
// Gulp.task()를 사용해 gulp-concat 업무 수행을 정의
gulp.task('concat:js', function () {
return gulp
// js 하위 디렉터리 내의 모든 자바스크립트 파일을 가져온다.
.src(['project/src/js/**/*.js'])
// 상단에서 참조한 concat 모듈을 호출하고 병합할 파일 네이밍을 정의
.pipe( concat('conbined.js') )
/**
* ==============================+
* 파일을 병합한 후 uglifiy를 수행한다.
* ==============================+
*/
.pipe(uglify())
// 위에서 수행한 task 를 배포지(dist)에 파일을 생성한다.
.pipe( gulp.dest('project/dist/js') );
});
// $ gulp 명령어만 수행하기 위해 'default' 로 정의
// gulp default 를 수행하기 전에 concat:js 수행할 수 있도록 의존 모듈을 정의
gulp.task('default', ['concat:js']);
위 코드를 살펴보면 자바스크립트 파일들을 병합한 후 압축할 수 있도록 그 아래에 "pipe" 를 연결한 후 내부에 uglify() 함수를 적용했습니다.
이렇게 작성하면 목적지(dist)에 파일을 생성하기 전에 압축 과정을 수행하고 목적지에 파일을 생성하게 될 것입니다.
$ gulp
위와 같이 gulp 를 수행하면 병합,압축된 결과를 확인하실 수 있습니다.
병합, 압축된 결과물은 주석이 사라지고 전달인자 값이 모두 알파벳 한 글자로 변경되어 있을 것입니다.
그리고 여기서 주의할 점이 한 가지 있습니다.
위에서 정의한 gulpfile.js 의 마지막 기본 task 부분을 눈여겨 보시기 바랍니다.
gulp.task('default', ['concat:js']);
task 를 'default' 로 정의한 후 의존 모듈인 concat:js 하나만 정의해 둔 것을 확인하실 수 있습니다.
만약에 gulp-concat task 안에서 uglify 를 작성하지 않고 따로 task를 정의했다면 아래와 같이 정의할 수 있습니다.
gulp.task('default', ['concat:js','uglify']);
하지만 gulp-concat task 안에서 같이 사용하고 있다면 기본 테스크를 정의한 후 의존 모듈로 concat task 만 정의하면 됩니다.
일반적으로 실무에서는 파일 병합을 할 경우에 압축도 하기 때문에 위 코드와 같이 작성하면 되지만 uglify 만을 단독으로 사용한다면 task 를 따로 정의해주어야만 합니다.
만약에 필자의 위 코드인 gulpfile.js 를 가지고 아래와 같이 task 를 정의하고 gulp 를 수행한다면 :
// 기본 (default) 테스크 정의
gulp.task('default', ['concat:js', 'uglify']);
Task 'uglify' is not in your gulpfile 와 같은 메시지를 보게 될 것입니다.
계속해서 uglify 에 대해 알아보도록 하겠습니다.
gulp 가 올바르게 수행됐다면 병합, 압축이 되었을 것이고 위에서 언급했듯이 주석, 전달인자 값 등에 변경이 일어났을 것입니다.
이는 uglify() 함수가 처리하면서 기본 설정된 옵션 값에 따라 발생한 결과로 변수, 매개변수 등이 알파벳 한 글자로 변경되지 않게 하려거나 주석을 보존하려면 기본 옵션이 아닌 옵션을 설정해 줄 필요가 있습니다.
다음의 예제는 uglify()
에 전달 인자로 옵션 값을 정의한 것입니다.
// gulp load (gulp modules 호출)
var gulp = require('gulp');
// gulp 플러그인 호출
var concat = require('gulp-concat'),
uglify = require('gulp-uglify');
// Gulp.task()를 사용해 gulp-concat 업무 수행을 정의
gulp.task('concat:js', function () {
return gulp.src(['project/src/js/**/*.js'])
.pipe( concat('conbined.js') )
/**
* ==============================+
* uglifiy 옵션값 정의
* ==============================+
*/
.pipe(uglify({
mangle : false, // 알파벳 한 글자 압축 과정 설정
preserveComments : 'all' // 'all', 또는 'some'
}))
.pipe( gulp.dest('project/dist/js') );
});
// gulp.task() 를 사용해 기본(default) 테스크를 정의
gulp.task('default', ['concat:js']);
mangle
옵션 값을 false
로 설정하면 알파벳 한 글자로 압축하는 과정을 수행하지 않으며, preserveComments
의 옵션 값을 all
또는 some
으로 설정하면 압축과정에서 주석이 지워지지 않고 보존(preserve)됩니다.
all 값일 경우에는 모든 주석이 보존되고 some 값일 때는 느낌표(!)가 붙은 주석만 보존되게 됩니다.
mangle, preserveComments 옵션 외에 다른 옵션도 설정할 수 있습니다.
설정 가능한 옵션은 gulp-uglify 옵션 페이지를 참고바랍니다.
gulp-rename
이번에는 gulp-rename 모듈을 이용하여 병합,압축한 파일을 먼저 출력한 후 압축 과정을 거쳐 이름을 바꿔서 출력하는 방법에 대해 알아봅니다.
다시 말해, 압축하지 않은 파일과 압축한 파일 두 가지를 출력하는 것입니다.
실무에서는 대개 압축된 파일에 min 접미사를 붙여 사용하는데 gulp-rename 모듈을 사용하여 간편하게 파일 이름을 바꿔서 출력할 수 있습니다.
먼저 NPM 명령어로 gulp-rename 모듈을 다음과 같이 설치합니다.
$ mpm install gulp-rename --save-dev
설치가 완료되었다면 gulpfile.js 파일의 코드를 수정하도록 하겠습니다.
수정된 코드의 내용은 다음과 같습니다.
var gulp = require('gulp');
// gulp 플러그인 호출
var concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
rename = require('gulp-rename'); // gulp-rename 모듈 호출
/**
* ==============================================================+
* 파일 병합,압축 그리고 문법 검사까지 수행하는 테스크를 정의히기 때문에
* task 의 이름을 concat:js -> combine-js 로 변경(가독성 차원)
* ==============================================================+
*/
gulp.task('combine-js', function () {
return gulp.src(['project/src/js/**/*.js'])
.pipe(concat('combined.js'))
/**
* ============================================+
* pipe 에 파일 병합,압축한 것을 먼저 목적지에 생성
* ============================================+
*/
.pipe(gulp.dest('project/dist/js'))
.pipe(uglify({
mangle : true, // 알파벳 한 글자 압축 과정 설정
preserveComments : 'all' // 'all', 또는 'some'
}))
/**
* ============================================+
* pipe 에 concat, uglify 을 수행한 후 rename 실행
* ============================================+
*/
.pipe(rename('combined.min.js')) // min 네이밍으로 파일 생성
.pipe( gulp.dest('project/dist/js') );
});
// gulp.task() 를 사용해 기본(default) 테스크를 정의
gulp.task('default', ['combine-js']);
먼저 첫 번째 task 부분의 name 을 combine-js 로 변경하였습니다.
concat 과 uglify 를 수행하고 rename 까지 수행하는 task 이기 때문에 가독성 차원에서 이름을 변경한 것 뿐입니다.
그리고 주석과 코드 내용을 살펴보면 gulp.dest()
호출하는 곳이 두 군데 보일 것입니다
이는 병합을 수행한 파일을 먼저 목적지(dist)에 생성하고 그 다음에 병합, 압축을 모두 한 파일을 rename 함으로써 'combined.min.js' 네이밍을 정의한 후 목적지(dis)에 또 다시 파일을 생성한 것입니다.
concat()
함수에 병합할 파일 네이밍을 문자열로 전달했듯이 rename()
함수에 변경할 파일 이름을 전달인자로 작성한 것입니다.
gulp 명령어를 실행하면 아래의 그림처럼 두 개의 파일이 생성된 것을 확인하실 수 있습니다.
Watch : 지속적인 관찰 업무 등록
지금까지 정의한 스크립트 업무는 gulp-uglify, gulp-concat, gulp-rename 플러그인을 사용해서 JavaScript 파일을 최적화하는 방법에 대해서 살펴 보았습니다.
그런데 한 두번은 괜찮지만, 개발 과정에서 빈번한 수정으로 매번 JavaScript 파일을 수정할 때마다 CLI 에서 gulp task 를 수행,실행하는 것은 매우 비효율적이고 귀찮은 일이 아닐 수 없습니다.
이러한 불편한 경우를 위해 gulp는 파일에 변경이 있을 때마다 변경을 감지해서 task 를 실행할 수 있는 기능을 gulp.watch
라는 메서드를 제공해주고 있습니다.
즉, 사용자가 파일만 변경하여 저장하면 자동으로 업무가 실행되기 때문에 지속적인 관찰 업무를 등록하게 되면 자동으로 번거로운 일들을 처리할 수 있는데 이를 자동화(Automation)라고 합니다.
관찰 업무를 정의하는 방법도 앞서 설명한 내용과 크게 다르지 않습니다.
지금까지 수행한 스크립트 최적화 업무를 다음과 같이 watch(지속적 업무 관찰 등록)해 보도록 합니다.
var gulp = require('gulp');
// gulp 플러그인 호출
var concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
rename = require('gulp-rename');
gulp.task('combine-js', function () {
return gulp.src(['project/src/js/**/*.js'])
.pipe(concat('combined.js'))
.pipe(gulp.dest('project/dist/js'))
.pipe(uglify())
.pipe(rename('combined.min.js'))
.pipe( gulp.dest('project/dist/js') );
});
/**
* =================================+
* 지속적인 업무 관찰을 위해 watch 등록
* 즉, 파일 변경을 감지한다.
* =================================+
*/
gulp.task('watch', function () {
/**
* ====================================+
* 1. 감지할 디렉터리를 정의
* 2. 변경이 감지되면 실행할 task 를 지정
* ====================================+
*/
gulp.watch('project/src/js/**/*.js', ['combine-js']);
});
// gulp 를 실행하면 default 로 combine-js task 와 watch task 를 실행하도록 한다.
gulp.task('default', ['combine-js','watch']);
위에서 살펴본 코드에서 watch
라는 task가 추가되었습니다,
이 task 의 gulp.watch 메서드에는 두 개의 전달인자 값을 전달받고 있습니다.
gulp.watch
- gulp.watch 의 첫번째 파라미터에서는 변경 감지를 해야하는 대상을 지정합니다.
- 두번째 파라미터는 변경이 감지되었을 때 실행할 task 를 지정하도록 합니다. 배열 형태로 여러개의 task 명을 넣어주면 변경이 일어날 때마다 해당 task 들을 자동으로 실행해주게 됩니다.
위 코드의 watch 를 분석해 보면 'project/src/js/' 디렉터리 내에 js 확장자를 가진 파일이 변경되면 conbine-js task 실행한다는 의미입니다.
gulp.task('default', ['combine-js','watch']);
그리고 위와 같이 default task 로 combine-js
와 watch
task 를 지정했기 때문에 아래와 같이 gulp 라고만 입력하면 combine-js와 watch task가 실행되게 됩니다.
$ gulp
이번에는 watch task 도 실행했기 때문에, gulp 가 바로 종료되지 않고 변경 감지를 위해 대기하고 있는 것을 확인하실 수 있을 것입니다.
이때 project/src/js/ 디렉터리 아래의 js 파일 하나를 수정하면 바로 변경을 감지해서 combine-js 를 수행하는 것을 확인할 수 있습니다.
마치며
지금까지 단계별로 gulp.js 의 사용방법에 대해서 살펴보았습니다.
이 글에서는 세 개 정도의 gulp-concat, gulp-uglify, gulp-rename 플러그인을 사용했지만, 지금까지 다룬 내용을 잘 이해한다면 언제든지 필요에 따라 gulp 플러그인들을 찾아서 적절하게 활용할 수 있을 것입니다.
그리고 gulp는 현재까지 약 2000여개에 플러그인을 보유하고 있으며 Grunt 보다 인기가 더 높고 사용자수도 나날이 늘어가고 있습니다.
다음 포스팅에서는 스크립트 업무만이 아닌 CSS 전처리기인 SASS 를 gulp-sass 플러그인을 사용해 보고, 그 이외에 몇 가지 유용한 플러그인을 다뤄보도록 하겠습니다.
Related Info
[발췌] 감성프로그래밍(gulp 입문)