Gulp로 구성한 퍼블리싱 개발 환경
Gulp 빌드 프로세스를 사용해서 정적인 페이지 마크업을 효율적으로 진행하는 방법
본 포스트에서 사용된 전체 소스 파일은 아래 링크에서 확인할 수 있다.
최근 만들어지는 웹사이트는 싱글 페이지 형식으로 개발하는 형태가 일반적이다. 하지만 퍼블리싱이라고도 불리는 정적인 페이지 개발 작업에 대한 수요는 여전히 많다. 작업을 할때는 Gulp를 기반으로 개발 프로세스를 구성하는데, 새로운 일을 시작할 때 편하게 clone해서 사용할 수 있도록 별도로 저장소를 만들어 보았다.
퍼블리싱을 위한 언어
개인적으로는 마크업에는 Pug를 사용하고 스타일시트 작성에는 Sass를 선호한다.
Pug를 사용하면 html보다 태그를 훨씬 간편하게 작성할 수 있어서 좋다. 무엇보다 block으로 템플릿(Template Inheritance – Pug)을 작성해두면 중복된 부분을 컴포넌트화 시킬 수 있음과 동시에 여러 페이지를 빠르게 만들 수 있어서 무척 편리하다.
Sass는 partial 파일을 사용한 컴포넌트화, nesting, mixin, 변수, CSS에서 지원하지 않는 연산자, 조건문, 반복문 등의 기능을 사용할 수 있다. Sass를 한 번이라도 사용해 본다면 CSS를 직접 작성하던 시절로는 돌아가고 싶지 않을 것이다.
Gulp
Gulp는 Node.js 기반으로 개발 프로세스를 자동화시킬 수 있는 툴이다. Node.js의 Stream 인터페이스를 이용해서 특정 소스 파일에 대한 작업을 단계적으로 진행할 수 있다. 간단히 풀어내자면
- Sass 소스 파일을 불러와서
- CSS 파일로 변환한 후
- 원하는 위치에 저장한다.
이런 식으로 순차적으로 작업을 진행할 수 있다. 그리고 이어서
- 소스 파일에 새로운 내용이 저장되면
- 앞선 1~3의 과정을 반복한다.
- 브라우저를 새로고침시켜서 변경된 사항을 확인할 수 있도록 만든다.
이런 식의 작업이 가능하다. webpack 으로도 정적인 사이트 작업의 가능하지만(rhostem/webpack-static-site), 기본 목적이 분리된 모듈을 하나로 만드는데 있기 때문에 작업 결과물로 여러 개의 마크업 파일을 만들어내기에는 다소 불편하다. 그에 비교해 Gulp는 간단하게 소스 파일을 결과 파일로 변환할 수 있기 때문에 퍼블리싱 작업에 더 적합하다고 할 수 있다.
Pug 소스파일 처리
Gulp는 task를 선언해서 사용하며, Pug 파일을 처리하기 위한 task는 아래와 같이 작성할 수 있다.
gulp.task('pug', [], function buildHTML() {
const pugErrHandler = conf.errorHandler('pug')
return gulp
.src(conf.paths.pug.src) // 소스 파일 불러오기
.pipe(pug({ pretty: true }).on('error', pugErrHandler)) // HTML로 변환
.pipe(gulp.dest(conf.paths.pug.dist)) // 원하는 위치에 저장
.pipe(browserSync.reload({ stream: true })) // 브라우저 새로고침
})
pipe 메소드 덕분에 작업 과정이 무척 직관적이다. 사용자가 신경 써야하는 부분은 pug 모듈을 실행할 때 전달해야 하는 옵션, 소스와 아웃풋 파일의 위치 정도다.
Sass 소스파일 처리
gulp.task('sass', [], function() {
const sassErrHandler = conf.errorHandler('sass')
gulp
.src(conf.paths.sass.src) // 소스 파일 불러오기
.pipe(sourcemaps.init()) // 소스맵 초기화
.pipe(sass(conf.sass.process).on('error', sassErrHandler)) // CSS로 변환
.pipe(autoprefixer(conf.sass.autoprefixer)) // 자동으로 vendor prefix 붙이기
.pipe(sourcemaps.write('./map')) // 소스맵 파일 생성
.pipe(gulp.dest(conf.paths.sass.dist))
.pipe(browserSync.reload({ stream: true }))
})
Pug와 거의 유사하다. Sass에서는 소스맵(관련 문서: Using source maps with Sass 3.3)을 생성하는 과정이 필요하다. 브라우저가 실제로 불러오는 것은 CSS 파일이기에 스타일이 Sass 소스 파일의 어느 부분에서 작성된 것인지 연결할 필요가 있기 때문이다.
아래와 같이 개발자 도구에서 특정 요소의 스타일을 검사하면 CSS 파일이 아닌 Sass 파일을 가리키는 것을 확인할 수 있다.
로컬 서버 생성
정적인 페이지는 서버를 실행하지 않고 작성해도 상관없지만 그렇게 할 경우 리소스를 불러올 때 무조건 현재 소스 파일의 위치를 기준으로 참조해야 한다는 문제가 생긴다. 웹에서 흔하게 사용하는 루트(/
) 기호를 사용할 수 없다는 의미이다. 서버에 올라가지 않은 HTML 파일에서 저 루트 기호는 운영체제 파일 시스템의 루트를 가리킬 테니 말이다. 이런 문제도 있고 뒤에서 작성할 브라우저 자동 새로 고침을 위해서도 로컬 서버를 사용하는 편이 좋다.
로컬 서버로는 Browsersync를 사용한다. Browsersync는 Gulp, Grunt 같은 빌드 도구와 호환성이 좋아서 많이 사용된다. 몇 개의 옵션만 할당해주면 간단히 서버를 생성할 수 있다.
gulp.task('serve', function() {
browserSync.instance = browserSync.init({
startPath: '/',
server: {
baseDir: `${conf.paths.dist}`, // 루트 폴더 위치
directory: true, // 디렉터리 구조를 기반으로 라우트를 구성한다
},
port: 4000, // 포트
open: true, // 서버 시작시 웹페이지를 기본 브라우저에서 자동으로 열 것인지
})
})
앞서 Pug, Sass 태스크에서 등장했듯이 browserSync 모듈은 다른 태스크에서 소스 파일 변경 시 브라우저 새로 고침에 사용된다. 그러기 위해서는 같은 서버를 사용해야 하므로 browserSync 모듈의 instance
속성에 serve 태스크 내부에서 생성한 인스턴스를 할당해서 다른 태스크의 콜백 함수 내부에서도 사용할 수 있도록 한다.
그리고 인스턴스를 생성할 때 directory 옵션을 사용하면 디렉터리 내부의 파일을 탐색할 수 있는 UI를 제공한다. 웹 브라우저에서 마치 파일 탐색기를 사용하는 것과 같으며 간단한 검색 기능도 제공하기에 작업이 진행됨에 따라 파일 개수가 늘어나면 무척 유용할 것이다.
파일 변경 탐지
Gulp에서 제공하는 watch
메소드를 사용하면 파일이 변경되었을 때 특정 태스크를 실행하도록 구성할 수 있다. 이를 통해 파일이 변경될 때마다 새로운 HTML, CSS 파일이 생성되도록 한다.
gulp.watch(소스 파일 경로, [태스크 목록])
// 파일 변경을 감지해서 pug, sass,태스크를 실행하도록 한다.
gulp.task('watch', function() {
gulp.watch(path.join(conf.paths.src, '/**/*.pug'), ['pug'])
gulp.watch(
[path.join(conf.paths.src, '/**/*.scss'), path.join(conf.paths.src, '/**/*.sass')],
['sass']
)
})
다양한 Gulp 플러그인의 활용
글에서는 Gulp로 가능한 최소한의 작업만 소개했을 뿐이다. Gulp는 수많은 개발자의 참여를 통해 만들어진 다양한 플러그인을 통해 더 많은 일이 가능하다. 글을 작성하는 시점에 3500여 개가 넘는 플러그인이 등록되어 있으니 만약 사용하고 싶은 기능이 있다면 이미 구현되어 있을 가능성이 매우 높다. 그리고 Gulp를 잘 활용하려면 Javascript는 물론 Node.js의 파일 시스템과 스트림에 대한 이해가 조금 필요하긴 하지만 학습에 투자할 가치는 충분하다고 생각한다.