1년 전에 자동화 툴로 사용했던 gulp 세팅값이다.
당시에 프로젝트가 끝나고 시간적 여유가 있어서,
gulp 코드의 한 줄 한 줄에 대한 역할을 찾아서 정리해 놨었다.
지금 여기서 더 업그레이드되었을 수 있다. 최신 문법이 생겼을 수도 있고.
암튼 일단 잃어버릴까 봐 블로그에 기록!
const gulp = require("gulp"); // gulp 기본 모듈. 파일을 읽고 변환.
const scss = require("gulp-sass")(require("sass")); // gulp-sass는 gulp와 함께 사용 가능한 scss 컴파일러. require("sass")를 통해 Dart Sass 컴파일러 사용 (Dart Sass는 Sass의 최신 기능과 사양을 가장 먼저 지원. 오류 메시지 지원)
const babel = require("gulp-babel"); // babel을 사용하여 JavaScript 파일을 최신 ES6+ 문법에서 호환성 있는 ES5 문법으로 변환 (구형 브라우저에서도 최신 JavaScript 코드를 사용)
const sourcemaps = require("gulp-sourcemaps"); // Sourcemaps를 생성하고 처리 컴파일된 코드와 원본 코드 간의 매핑 정보를 제공하여 디버깅을 용이하게 함 (개발자도구에서 확인)
const fileinclude = require("gulp-file-include"); // 파일 인클루드 기능을 제공 (HTML 파일에서 다른 파일을 포함할 때 사용 @include)
const htmlbeautify = require("gulp-html-beautify"); // HTML 파일을 정렬하고 예쁘게 만드는 모듈. 들여쓰기나 코드 스타일을 일관성 있게 유지
const ejs = require("gulp-ejs"); // HTML 파일을 렌더링. EJS 파일을 HTML 파일로 변환
const concat = require("gulp-concat"); // 여러 파일을 하나의 파일로 병합. 여러 JavaScript 파일이나 CSS 파일을 하나로 합칠 때 사용
const uglify = require("gulp-uglify"); // JavaScript 파일을 압축하여 파일 크기를 줄임.
const autoprefixer = require("gulp-autoprefixer"); // CSS 파일에 자동으로 브라우저 접두사를 추가. 다양한 브라우저 호환성을 확보
const rename = require("gulp-rename"); // 파일 이름을 변경하는 모듈. 파일 확장자를 변경하거나 파일 이름을 수정할 때 사용 (.ejs -> .html)
const browserSync = require("browser-sync").create(); // 로컬 서버를 실행하고 파일 변경 시 브라우저를 자동으로 새로 고. 실시간으로 변경 사항을 확인할 수 있어 개발 생산성을 높임
const del = require("del"); // 파일이나 디렉토리를 삭제하는 모듈. 주로 빌드 전에 기존의 파일을 정리하는 데 사용
const SRC_FOLDER = "./src/front";
const DIST_FOLDER = "./dist/front";
const SRC_PATH = {
ASSETS: {
FONTS: "./src/front/assets/fonts",
IMAGES: "./src/front/assets/images",
SCSS: "./src/front/assets/scss",
JS: "./src/front/assets/js",
AJAX: "./src/front/assets/ajax",
MODULES: "./src/front/assets/modules",
DOC: "./src/front/assets/doc",
GLTF: "./src/front/assets/gltf",
MOVIES: "./src/front/assets/movies",
BOOTSTRAP: "./node_modules/bootstrap/dist",
},
EJS: "./src/front/ejs",
};
const DEST_PATH = {
ASSETS: {
FONTS: "./dist/front/assets/fonts",
IMAGES: "./dist/front/assets/images",
CSS: "./dist/front/assets/css",
JS: "./dist/front/assets/js",
AJAX: "./dist/front/assets/ajax",
MODULES: "./dist/front/assets/modules",
DOC: "./dist/front/assets/doc",
GLTF: "./dist/front/assets/gltf",
MOVIES: "./dist/front/assets/movies",
},
};
const OPTIONS = { // scss 컴파일에 사용할 옵션 정의
outputStyle: "expanded", // css 여러줄로 확장 출력 (nested : 계층구조유지/들여쓰기, compact : 한줄로, compressed : 공백 줄바꿈 모두 제거 크기 최소화)
indentType: "space", // 들여쓰기에 사용할 문자
indentWidth: 4, // 들여쓰기 공백
precision: 8, // css 소수점 이하 8자리까지 정확도 유지
};
gulp.task("clean", () => del(["dist"])); // clean 테스크로 dist 디렉토리 삭제
gulp.task("html", () => // html 테스크로 html을 복사한 후 browserSync 테스크 실행하여 로컬 서버 실행
gulp
.src([`${SRC_FOLDER}/**/*.html`], { base: SRC_FOLDER, since: gulp.lastRun("html") }) // base : gulp가 파일을 읽어올 때 기준 디렉토리를 설정 파일이 복사될 때 원래 구조를 유지. since : gulp 가 마지막으로 테스크를 실행한 후 변경된 파일만 처리하도록 설정.
.pipe(gulp.dest(DIST_FOLDER)) // 읽어온 파일을 지정된 DIST_FOLDER 디렉토리에 저장하는 역할
.pipe(browserSync.stream())
);
/** html 테스크 역할 요약 **/
/*
1. SRC_FOLDER에서 .html 파일들을 읽어온다. (base 옵션을 통해 원래 디렉토리 구조를 유지하고, since 옵션을 통해 변경된 파일만 처리)
2. 읽어온 파일들을 DIST_FOLDER 로 복사한다.
3. 파일이 복사 된 후 browserSync를 통해 브라우저를 새로고침 한다.
*/
gulp.task("ejs", () =>
gulp
.src([`${SRC_FOLDER}/ejs/**/!(_)*.ejs`, `${SRC_FOLDER}/*.ejs`]) // 이 경우 지정된 2개의 경로에서 ejs파일을 읽어온다. (언더스코어(_)로 시작하지 않는 모든 ejs파일)
.pipe(ejs()) // ejs파일을 html로 변환한다.
.pipe(rename({ extname: ".html" })) // 파일 확장자를 .ejs에서 .html로 변경한다.
.pipe(fileinclude({ prefix: "@@", basepath: "@file" })) // 파일 인클루드를 수행한다. ejs 내에 다른 파일을 포함할 수 있도록 한다. (@@ 접두사를 사용하여 인클루드할 파일을 지정, basepath: "@file" 옵션은 현재 파일의 디렉토리를 기준으로 포함할 파일을 찾음)
.pipe(htmlbeautify({ indentSize: 2 })) // html파일을 정렬한다. (indentSize: 2 옵션은 들여쓰기 크기를 2칸으로 설정한다는 의미)
.pipe(gulp.dest(DIST_FOLDER)) // 변환된 html 파일들을 DIST_FOLDER 디렉토리에 저장. 최종적으로 배포될 파일들의 위치
.pipe(browserSync.stream())
);
gulp.task("scss:compile", () =>
gulp
.src(`${SRC_PATH.ASSETS.SCSS}/*.scss`) // scss 파일을 소스 경로에서 읽어옴
.pipe(sourcemaps.init()) // sourcemaps 초기화 (sourcemaps : 개발자 도구에서 원본 scss파일과 라인 번호 매핑) 파일된 CSS 파일과 원본 SCSS 파일 간의 맵핑을 생성하여 디버깅을 용이하게 한다.
.pipe(scss(OPTIONS)) // SCSS를 OPTIONS 설정 대로 컴파일 (어떤 스타일, 들여쓰기 방식, 소수점 몇 자리 등)
.pipe(autoprefixer()) // Autoprefixer를 사용하여 CSS 접두사 추가 (다양한 브라우저 호환성 확보)
.pipe(sourcemaps.write()) // Sourcemaps를 작성하여 컴파일된 css파일과 함께 저장, css 디버깅을 쉽게
.pipe(gulp.dest(DEST_PATH.ASSETS.CSS)) // 결과 CSS 파일을 이 경로에 저장
.pipe(browserSync.stream())
);
gulp.task("js", () =>
gulp
.src([ // 해당 경로에서 파일들을 읽어옴
`${SRC_PATH.ASSETS.JS}/**/*.js`,
`${SRC_PATH.ASSETS.BOOTSTRAP}/js/bootstrap.bundle.min.js`, // 부트스트랩 번들 파일
])
.pipe(babel()) // babel : 최신 JavaScript(ES6+) 코드를 구형 브라우저에서도 호환되도록 함.ES6+ 코드가 ES5 코드로 변환
.pipe(uglify()) // uglify : 코드의 공백과 주석을 제거, 변수명을 축약하여 파일 크기를 최소화. 웹 페이지 로딩 속도를 향상
.pipe(gulp.dest(DEST_PATH.ASSETS.JS)) // 변환되고 압축된 js파일을 지정된 디렉토리에 저장. 최종적으로 배포될 파일들이 위치함
.pipe(browserSync.stream())
);
const copyAssets = (src, dest) => () => // 재사용 가능한 copyAssets 함수를 정의. 2개의 인수 src, dest를 받아야 함. (src : 소스 파일의 경로. 복사할 파일들이 위치할 곳. dest : 대상 디렉토리의 경로. 파일이 복사될 위치)
gulp.src(src).pipe(gulp.dest(dest)).pipe(browserSync.stream());
gulp.task("ajax", copyAssets(`${SRC_PATH.ASSETS.AJAX}/*.js`, DEST_PATH.ASSETS.AJAX));
gulp.task("modules", copyAssets(`${SRC_PATH.ASSETS.MODULES}/*.+(js|json|xml|txt)`, DEST_PATH.ASSETS.MODULES));
gulp.task("images", copyAssets(`${SRC_PATH.ASSETS.IMAGES}/**/*.+(png|jpg|jpeg|gif|ico)`, DEST_PATH.ASSETS.IMAGES));
gulp.task("svg", copyAssets(`${SRC_PATH.ASSETS.IMAGES}/**/*.svg`, DEST_PATH.ASSETS.IMAGES));
gulp.task("fonts", copyAssets(`${SRC_PATH.ASSETS.FONTS}/**/*.+(eot|otf|svg|ttf|woff|woff2)`, DEST_PATH.ASSETS.FONTS));
gulp.task("doc", copyAssets(`${SRC_PATH.ASSETS.DOC}/**/*`, DEST_PATH.ASSETS.DOC));
gulp.task("gltf", copyAssets(`${SRC_PATH.ASSETS.GLTF}/**/*`, DEST_PATH.ASSETS.GLTF));
gulp.task("movies", copyAssets(`${SRC_PATH.ASSETS.MOVIES}/*`, DEST_PATH.ASSETS.MOVIES));
/** copyAssets 함수 역할 요약 **/
/*
1. 재사용 가능한 copyAssets 함수 : 파일을 복사하고 browserSync를 통해 변경 사항을 브라우저에 실시간으로 반영.
2. src: 소스 파일의 경로. 복사할 파일들이 위치한 곳을 지정
3. dest: 대상 디렉토리의 경로. 파일들이 복사될 위치를 지정
4. (() => ...) : 리턴된 함수. copyAssets 함수 내부에 정의된 익명 함수. gulp 테스크에서 이 함수를 호출하면 파일 복사 작업 실행
5. gulp.src(src) : src 경로에 있는 파일 읽어옴. pipe(gulp.dest(dest)) : 읽어온 파일을 dest 경로에 저장. pipe(browserSync.stream()) : browserSync를 통해 브라우저 새로 고침
즉. 여러 파일을 복사하는 gulp 테스크를 쉽게 정의. 코드의 중복을 줄임.
*/
gulp.task("watch", () => { // watch : 지정된 디렉토리 내 파일 유형을 감시하고, 파일이 변경될 때마다 관련 gulp 테스크가 자동으로 실행. 자동으로 빌드 및 브라우저 새로 고침이 이루어짐.
gulp.watch(`${SRC_PATH.EJS}/**/*.ejs`, gulp.series("ejs"));
gulp.watch(`${SRC_PATH.ASSETS.SCSS}/**/*.scss`, gulp.series("scss:compile"));
gulp.watch(`${SRC_PATH.ASSETS.JS}/**/*.js`, gulp.series("js"));
gulp.watch(`${SRC_PATH.ASSETS.BOOTSTRAP}/**/*.js`, gulp.series("js"));
gulp.watch(`${SRC_PATH.ASSETS.AJAX}/*.js`, gulp.series("ajax"));
gulp.watch(`${SRC_PATH.ASSETS.MODULES}/**/*.js`, gulp.series("modules"));
gulp.watch(`${SRC_PATH.ASSETS.IMAGES}/**/*.+(png|jpg|jpeg|gif|ico)`, gulp.series("images"));
gulp.watch(`${SRC_PATH.ASSETS.IMAGES}/**/*.svg`, gulp.series("svg"));
gulp.watch(`${SRC_PATH.ASSETS.FONTS}/**/*.+(eot|otf|svg|ttf|woff|woff2)`, gulp.series("fonts"));
gulp.watch(`${SRC_PATH.ASSETS.DOC}/**/*`, gulp.series("doc"));
gulp.watch(`${SRC_PATH.ASSETS.GLTF}/**/*`, gulp.series("gltf"));
gulp.watch(`${SRC_PATH.ASSETS.MOVIES}/*`, gulp.series("movies"));
});
gulp.task("browserSync", () => // browserSync : 파일 변경을 실시간으로 감지하고 브라우저를 자동으로 새로 고침하는 역할
browserSync.init({ // browserSync를 설정하고 초기화함. 설정 옵션 정의
notify: false, // 파일 변경 알림 메시지를 표시하지 않도록 설정 (원래 오른쪽 상단에 표시됨)
port: 5000, // 로컬 서버의 포트번호 설정
server: { baseDir: ["dist/front"], open: true }, // baseDir : 로컬 서버의 루트 디렉토리 설정 dist/front 폴더 안의 파일들이 서버를 통해 제공. open: true : browserSync가 시작될 때 자동으로 브라우저를 열도록 설정
})
);
gulp.task(
"build",
gulp.series( // series : 주어진 테스크를 순차적으로 실행 (즉 첫번째 clean테스크가 끝나면 다음 테스크가 시작)
"clean", // clean은 dist폴더를 삭제하는 역할. 시작 부분에서 한 번만 실행되어야 함
gulp.parallel( // parallel : 주어진 테스크를 동시에 실행 (즉 clean테스크가 완료된 후 이 모든 테스크가 동시에 병렬로 실행)
"html", // parallel 테스크들은 서로 독립적. 동시에 실행해야 빌드 시간 단축
"ejs",
"scss:compile",
"js",
"ajax",
"modules",
"images",
"svg",
"fonts",
"doc",
"gltf",
"movies"
),
gulp.parallel( // 첫 parallel 블록에 있는 모든 테스크 완료 후 두번째 parallel 테스크 동시 실행
"browserSync", // browserSync, watch 테스크는 개발 중 실시간으로 변경 사항 반영, 파일 감시 역할. 빌드가 완료된 후 실행되어야 하므로 마지막에 병렬로 실행
"watch"
)
)
);
gulp.task("default", gulp.series("build")); // 이 한 줄의 역할은 걸프에서 기본 테스크를 정의하는 것. 걸프 명령어를 실행했을 때 기본적으로 실행되는 테스크. build 테스크는 순차적으로 실행하도록 지정. 즉 default 테스크를 실행하면 build 테스크 실행됨.
/*** GULP 전체 흐름 ***/
/*
1. gulp 명령어를 터미널에서 실행하면 gulp는 default 테스크를 자동으로 찾는다.
2. deafult 테스크가 gulp.series("build")로 정의되어 있으므로 build 테스크가 실행된다.
3. build 테스크는 앞서 정의한 대로 clean 테스크가 먼저 실행되고, 그 다음에 병렬로 여러 빌드 테스크를 실행하며 마지막으로 browserSync와 watch 테스크를 병렬로 실행한다.
4. 사용자가 gulp만 입력해도 build 프로세스 전체가 실행된다. 즉 편리하게 전체 빌드 과정을 단일 명령어로 실행할 수 있다.
*/
/*** GULP는 스트림 기반 빌드 시스템 ***/
/*
1. 스트림 : gulp에서 스트림은 파일을 1개씩 읽고 여러 플러그인으로 데이터를 변환 후 결과를 파일 시스템에 다시 쓰는 과정을 거친다.
2. 파일을 조각으로 처리 : 파일 전체를 메모리에 올리지 않는다. 이를 통해 메모리 사용량을 줄이고, 대용량 파일도 효율적으로 처리가능하다.
3. pipe : 스트림을 연결하는 방식. 여러 작업을 순차적으로 처리하는데 사용된다.
각 단계별 스트림
1. 입력 스트림 : 지정된 디렉토리 내의 파일을 읽어온다 (ex : gulp.src("src/scss/*.scss"))
2. 스트림 변환 : 스트림 초기화, 자동으로 컴파일하는 작업을 스트림에 추가한다.
3. 출력 스트림 : 최종적으로 변환된 파일을 지정 디렉토리에 저장한다.
*/
/*** GULP의 효율성 ***/
/*
1. 파일을 한 번에 처리하지 않고, 조각으로 처리하므로 메모리 사용량이 적다.
2. 여러 작업을 순차적으로 진행한다.
3. pipe라인을 쉽게 구성할 수 있어 다양한 파일 변환 작업을 유연하게 처리할 수 있다.
4. 플러그인을 쉽게 추가하거나 제거 가능하다.
5. 각 작업이 독립적으로 실행되므로, 코드를 모듈화하고 유지보수하기 쉽다.
6. 여러 작업을 조합하여 복잡한 빌드 과정을 단순화할 수 있다.
*/