개요
- Jekyll 기반 블로그에서 CSS/JS 자동 최적화 시스템을 구축하여 웹 성능을 개선한 과정을 소개함
문제 상황 분석
초기 성능 문제
- 기술 블로그에서 측정된 현황
- SCSS 원본
- 332KB (19개 파일, 11,785 라인)
- 빌드된 CSS
- 454KB (13 라인으로 압축)
- JavaScript
- 7개 minified 파일 (각 3.2KB)
- SCSS 원본
CSS/JS 현황 파악
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# SCSS 파일 용량 및 개수 확인
du -sh _sass && find _sass -name "*.scss" -type f | wc -l
# 결과: 332K _sass
# 19
# SCSS 총 라인 수 확인
find _sass -name "*.scss" -type f -exec wc -l {} + | tail -1
# 결과: 11785 total
# 빌드된 CSS 확인
ls -lh _site/assets/css/style.css
# 결과: -rw-r--r-- 1 user staff 454K Dec 20 22:03 _site/assets/css/style.css
# 빌드된 CSS 라인 수 (압축 효과 확인)
wc -l _site/assets/css/style.css
# 결과: 13 _site/assets/css/style.css
# Minified JS 파일 확인
find assets/js/dist -name "*.min.js" -type f -exec ls -lh {} \;
# 결과: 7개 파일, 각 3.2KB
- 측정된 파일 특성
- SCSS 원본
- 19개 파일, 332KB, 11,785 라인
- 빌드된 CSS
- 1개 파일, 454KB, 13 라인 (압축)
- JavaScript
- 7개 minified 파일, 각 3.2KB
- defer/async 스크립트
- 5개 defer, 2개 async
- SCSS 원본
적용된 기술
- CSS 최적화
- Sass compressed 모드
- 자동 minification
- JavaScript 최적화
- Gulp + Uglify
- defer/async 로딩
- 빌드 자동화
- Jekyll 빌드 파이프라인
- GitHub Actions
- 이미지 최적화
- Git pre-commit 훅
- pngquant, jpegoptim
자동화 시스템 구성
Jekyll SCSS 압축 설정
- _config.yml 설정
_config.yml파일에 아래 내용을 추가하여 Sass 자동 압축 활성화
1 2 3
# _config.yml sass: style: compressed # CSS 자동 압축 활성화
-
압축 옵션
옵션 설명 특징 nested들여쓰기 유지 기본값, 디버깅 용이 expanded완전 확장 가독성 높음 compact한 줄로 압축 선택자별 한 줄 compressed최대 압축 공백 제거, 가장 작음
압축 효과
-
압축 전 (개발 중)
1 2 3 4 5 6 7 8 9 10
/* _sass/layout/categories.scss */ .card { background: transparent !important; background-color: transparent !important; border: 1px solid rgba(255, 255, 255, 0.1) !important; backdrop-filter: blur(10px) saturate(1.2) !important; -webkit-backdrop-filter: blur(10px) saturate(1.2) !important; box-shadow: none !important; border-radius: 20px !important; }
-
압축 후 (빌드된 CSS)
1 2
/* _site/assets/css/style.css */ .card{background:transparent!important;background-color:transparent!important;border:1px solid rgba(255,255,255,.1)!important;backdrop-filter:blur(10px) saturate(1.2)!important;-webkit-backdrop-filter:blur(10px) saturate(1.2)!important;box-shadow:none!important;border-radius:20px!important}
- CSS 압축 효과
- 라인 수
- 11,785 라인 → 13 라인 (99.9% 감소)
- 가독성
- 개발 중 유지 → 배포 시 최적화
- 파일 크기
- 454KB (압축됨)
- 라인 수
- 자동화의 이점
- 개발 시
- SCSS로 편하게 작성
- 빌드 시
- 자동으로 압축
- 배포 시
- 최적화된 파일 제공
- 개발 시
JavaScript 최적화 설정
- Gulp 기반 자동화 설정
- 프로젝트 루트에
gulpfile.js폴더 생성 및index.js작성
1 2 3 4 5 6 7 8 9 10 11
// gulpfile.js/index.js #!/usr/bin/env node "use strict"; const js = require('./tasks/js'); exports.default = js.build; /* keep-alive develop mode, without uglify */ exports.dev = js.liveRebuild;
- 프로젝트 루트에
- package.json 스크립트 설정
package.json에 다음 스크립트와 의존성 추가- 터미널에서
npm install을 실행하여 패키지 설치 필요
1 2 3 4 5 6 7 8 9 10 11
{ "scripts": { "build": "gulp build", "dev": "gulp dev" }, "devDependencies": { "gulp": "^4.0.2", "gulp-uglify": "^3.0.2", "uglify-js": "^3.14.3" } }
JavaScript 지연 로딩 설정
- defer 속성 활용
_includes폴더 내 스크립트 로드 부분에defer속성 추가- HTML 파싱 차단 없이 스크립트 로드 가능
1 2 3 4
<!-- _includes/js-selector.html --> <script defer src="/assets/js/dist/pvreport.min.js"></script> <script defer src="/assets/js/apple-liquid-glass.js"></script> <script defer src="/assets/js/code-header.js"></script>
- async 속성 활용
- 독립적인 스크립트에 사용
1 2 3
<!-- _includes/js-selector.html --> <script async src=""></script> <script id="MathJax-script" async src=""></script>
전체 빌드 프로세스

사용 방법
로컬 개발 모드
1
2
3
4
5
# Jekyll 서버 실행 (CSS 자동 압축)
bundle exec jekyll serve
# JS 개발 모드 (압축 안 함, 빠른 빌드)
npm run dev
프로덕션 빌드
1
2
3
4
5
# Jekyll 프로덕션 빌드
JEKYLL_ENV=production bundle exec jekyll build
# JavaScript 압축
npm run build
배포 워크플로우
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. SCSS 파일 수정
vim _sass/layout/categories.scss
# 2. 로컬에서 확인 (자동 CSS 압축)
bundle exec jekyll serve
# 3. JS 파일 수정 (필요시)
vim assets/js/custom-script.js
# 4. JS 빌드 (필요시)
npm run build
# 5. 변경사항 커밋
git add .
git commit -m "Update styles and scripts"
# 6. 배포
git push origin main
# → GitHub Pages 자동 빌드
# → CSS/JS 자동 압축
# → 사이트 배포 완료
최적화 결과
측정된 현황
| 구분 | 파일 크기 | 파일 개수 | 라인 수 | 비고 |
|---|---|---|---|---|
| SCSS 원본 | 332KB | 19개 | 11,785줄 | 개발용 소스 |
| 최종 CSS | 454KB | 1개 | 13줄 | 99.9% 압축됨 |
- JavaScript 최적화
- 7개 파일 모두
.min.js형태로 제공 (각 3.2KB) - 5개 스크립트에
defer적용 - 2개 스크립트에
async적용
- 7개 파일 모두
- 자동화 시스템
- Jekyll 빌드 시 CSS 자동 압축
- Gulp를 통한 JS minification
- defer/async 속성으로 비차단 로딩
최종 결과
| 항목 | 상태 | 측정 결과 |
|---|---|---|
| CSS 압축 | 자동화 완료 | 11,785 → 13 라인 |
| JS Minification | 자동화 완료 | 7개 파일 (각 3.2KB) |
| 렌더링 최적화 | 적용 완료 | defer 5개, async 2개 |
| 이미지 최적화 | 자동화 완료 | 88MB → 52MB (41%) |
| 전체 파일 | 최적화 완료 | SCSS 332KB, CSS 454KB |
전체 동작 과정

측정 방법
- CSS 압축 측정
1 2 3 4 5
# SCSS 원본 라인 수 find _sass -name "*.scss" -exec wc -l {} + | tail -1 # 빌드된 CSS 라인 수 wc -l _site/assets/css/style.css
- JS Minification 측정
1 2
# Minified JS 파일 확인 find assets/js/dist -name "*.min.js" -type f -exec ls -lh {} \;
- JS 지연 로딩 측정
1 2 3 4 5
# defer 속성 개수 grep -c "defer" _includes/js-selector.html # async 속성 개수 grep -c "async" _includes/js-selector.html
- 이미지 최적화 측정
1 2
# 이미지 디렉토리 용량 확인 du -sh assets/img
CSS 압축 관련 문제
- 문제
- CSS가 압축되지 않음
- 원인
_config.yml설정 누락 또는 잘못된 값
- 해결 방법
1 2 3
# _config.yml 확인 sass: style: compressed # 이 값이 정확한지 확인
- 문제
- 로컬과 배포된 CSS가 다름
- 원인
- 로컬에서는 개발 모드로 빌드됨
- 해결 방법
1 2 3 4 5
# 프로덕션 모드로 로컬 빌드 JEKYLL_ENV=production bundle exec jekyll build # 생성된 파일 확인 cat _site/assets/css/style.css | head -10
JavaScript 최적화 문제
- 문제
- JS 파일이 minify되지 않음
- 원인
- Gulp 빌드를 실행하지 않음
- 해결 방법
1 2 3 4 5 6 7 8
# Node.js 패키지 설치 npm install # Gulp 빌드 실행 npm run build # 결과 확인 ls -lh assets/js/dist/*.min.js
- 문제
- defer/async 스크립트 오류
- 원인
- 스크립트 간 의존성 문제
- 해결 방법
1 2 3 4 5 6
<!-- 의존성이 있는 스크립트는 defer 순서 지정 --> <script defer src="jquery.js"></script> <script defer src="custom.js"></script> <!-- jQuery 이후 로드 --> <!-- 독립적인 스크립트는 async --> <script async src="analytics.js"></script>
빌드 성능 문제
- 문제
- Jekyll 빌드가 너무 느림
- 원인
- incremental build 비활성화
- 해결 방법
1 2 3 4 5
# _config.yml (개발 환경) incremental: true # 증분 빌드 활성화 # 또는 명령어 옵션 bundle exec jekyll serve --incremental
- 문제
- 불필요한 파일 빌드
- 원인
- exclude 설정 누락
- 해결 방법
1 2 3 4 5 6 7
# _config.yml exclude: - node_modules - gulpfile.js - package*.json - '*.gem' - '*.gemspec'
캐싱 문제
- 문제
- CSS/JS 변경이 반영되지 않음
- 원인
- 브라우저 캐시 또는 CDN 캐시
- 해결 방법
1 2 3 4 5 6
# 브라우저 캐시 강제 새로고침 # Chrome/Firefox: Ctrl + Shift + R (Mac: Cmd + Shift + R) # 파일명에 버전 추가 (cache busting) # _includes/head.html <link rel="stylesheet" href="/assets/css/style.css?v=1.0.1">
성능 모니터링
Lighthouse 점수 확인
1
2
3
4
5
6
7
8
# Lighthouse CLI 설치
npm install -g lighthouse
# 로컬 사이트 테스트
lighthouse http://localhost:4000 --output=json --output-path=./lighthouse-report.json
# 배포된 사이트 테스트
lighthouse https://mxxikr.github.io --output=html --output-path=./lighthouse-report.html
주요 지표 모니터링
| 지표 | 목표 점수 | 설명 |
|---|---|---|
| Performance | 85점 이상 | 전체 성능 점수 |
| FCP (First Contentful Paint) | 1.8초 이하 | 첫 콘텐츠 렌더링 시간 |
| LCP (Largest Contentful Paint) | 2.5초 이하 | 최대 콘텐츠 렌더링 시간 |
| TBT (Total Blocking Time) | 200ms 이하 | 총 차단 시간 |
운영 및 관리 팁
개발 워크플로우
- 개발 시
- 로컬에서
bundle exec jekyll serve사용 - CSS는 자동 압축 확인
- JS는
npm run dev로 빠른 빌드
- 로컬에서
- 테스트 시
- 프로덕션 모드로 로컬 빌드
JEKYLL_ENV=production bundle exec jekyll build- Lighthouse로 성능 측정
- 배포 시
- JS 최종 빌드
npm run build - 커밋 및 푸시
- GitHub Pages 자동 배포 확인
- JS 최종 빌드
최적화 유지 팁
- SCSS 작성 규칙
- 개발 시 가독성 우선
- 빌드가 자동 압축 처리
- 주석 자유롭게 사용
- JavaScript 관리
- 의존성 있는 스크립트
defer사용 - 독립적인 스크립트
async사용 - Gulp 빌드로 minify
- 의존성 있는 스크립트
- 자동화 검증
- 빌드 후 파일 크기 확인
- 라인 수 감소 확인
- defer/async 적용 확인