4P by GN⁺ | ★ favorite | 댓글 1개
  • Jampack은 Static Site Generator 출력물을 받아 사용자 경험과 Core Web Vitals 점수를 최적화하는 사후 처리 도구이며, 번들러나 프레임워크가 아님
  • HTML의 <img><picture>를 반응형 이미지로 바꾸고, WebP·AVIF 같은 형식, srcset, sizes, width, height, loading="lazy", decoding="async" 등을 자동으로 추가함
  • CDN 이미지는 URL 파라미터 기반 srcset으로 반응형 처리할 수 있고, 외부 이미지는 _jampack 아래로 다운로드해 최적화된 로컬 이미지로 바꿀 수 있음
  • Above-the-fold 자산은 높은 우선순위로 처리하고 작은 이미지는 HTML에 인라인하며, below-the-fold 이미지와 iframe은 지연 로딩함
  • 정적 사이트 빌드 결과 폴더에 npx @divriots/jampack./dist를 실행하는 방식으로 적용하며, CSS·JS·HTML·SVG·이미지 압축까지 2차 패스에서 수행함

Jampack의 역할

  • Jampack은 Static Site Generator, 즉 SSG가 만든 결과물을 입력으로 받아 정적 웹사이트를 최적화함
  • 목표는 사용자 경험과 Core Web Vitals 점수를 개선하는 것임
  • README는 Jampack을 “번들러도 아니고 프레임워크도 아님”이라고 구분함
  • 소개 글은 Read the introduction blog post에서 제공됨

이미지 최적화

  • 일반 <img>는 반응형 이미지로 변환됨
    • 원본 src에 대해 WebP 파일을 만들고 srcset을 추가함
    • sizes="100vw", loading="lazy", decoding="async", width, height 같은 속성이 추가됨
  • <picture> 요소는 여러 이미지 형식을 포함하는 반응형 구조로 바뀜
    • AVIF용 <source type="image/avif">가 추가됨
    • WebP용 <source type="image/webp">가 추가됨
    • 원본 <img>에도 srcset, sizes, loading, decoding, width, height가 들어감
  • 이미지 최적화 기능은 optimize-images 문서로 이어지지만, README의 해당 링크는 상대 경로임

CDN 및 외부 이미지 처리

  • CDN 이미지는 원격 URL을 유지하면서 반응형 srcset을 추가할 수 있음
    • 예시는 Unsplash 이미지 URL에 w, fit=min, auto=format 파라미터를 붙여 여러 폭의 후보를 만듦
    • 원본 이미지에도 loading="lazy", decoding="async", sizes="100vw"가 추가됨
  • 외부 이미지는 다운로드한 뒤 최적화된 로컬 파일로 바뀔 수 있음
    • 예시는 외부 Unsplash 이미지를 _jampack/ab99b9d280ce4cf7cfc810b59f3a7739.jpg.webp 같은 경로로 바꿈
    • 변환된 이미지에는 width, height, srcset, sizes, loading, decoding이 포함됨

Above-the-fold와 CSS·링크 최적화

  • Jampack은 above-the-fold 자산을 별도로 최적화함
    • 이미지는 더 높은 우선순위로 로드됨
    • 작은 이미지는 HTML에 임베드됨
  • below-the-fold 자산은 지연 로딩됨
    • 이미지와 iframe이 lazy load 대상임
  • Critical CSS는 HTML에 인라인됨
    • 목적은 스타일시트 다운로드와 파싱 중 발생할 수 있는 FOUC를 피하는 것임
    • 나머지 CSS는 지연 로딩됨
  • 링크 프리페치는 향후 페이지 이동을 빠르게 하기 위한 기능임
    • quicklink를 사용해 링크가 viewport에 들어올 때 동적으로 처리할 수 있음

자산 압축과 실행 방법

  • Jampack은 2차 패스에서 건드리지 않은 모든 자산을 압축하며, 같은 이름과 같은 형식을 유지함
  • 확장자별 압축 도구는 다음과 같음
  • 정적 웹사이트가 dist 폴더에 있을 때 다음 명령으로 실행함
npx @divriots/jampack ./dist
  • 추가 옵션은 CLI options에서 확인할 수 있음

사용 사례와 이름의 의미

댓글과 토론

Hacker News 의견들
  • 딱 찾고 있던 도구임. 이런 이미지 최적화를 하려고 Sharp 기반 스크립트를 직접 써왔는데, Jampack이 그걸 완전히 대체해주고 훨씬 잘 동작함
    Quarto 정적 사이트를 빌드한 뒤 Jampack을 돌렸더니 폴더 크기가 32% 감소했고, 아직 눈에 띄는 단점은 없음
    PageSpeed Insights 기준으로 Jampack 전에는 모바일 성능 52, 접근성 73, 권장사항 100, SEO 85였고 데스크톱은 성능 90, 접근성 75, 권장사항 100, SEO 82였음
    적용 후에는 모바일 성능 49, 접근성 80, 권장사항 100, SEO 92, 데스크톱 성능 85, 접근성 82, 권장사항 100, SEO 91로 나옴

    • Lighthouse와 PageSpeed Insights 점수는 흔들릴 수 있음. 이런 성능 비교를 할 때는 여러 번 실행해서 중앙값을 보는 편이 좋음
      “5회 실행한 Lighthouse 점수의 중앙값은 1회 실행보다 두 배 안정적”이라는 자료도 있음: https://developers.google.com/web/tools/lighthouse/variabili...
    • 마음에 들었다니 기쁨. 다만 성능 지표는 더 좋아질 줄 알았음. 괜찮다면 Jampack 적용 전 정적 사이트 결과물을 공유해주면 살펴보고 싶음
      georges [at] divriots [dot] com
  • Apache와 Nginx용 PageSpeed 모듈이 떠오름: https://developers.google.com/speed/pagespeed/module

  • 와, 이거 꽤 마음에 듦. 써볼 예정임
    별로라고 느낀 사람이 있다면 결함을 짚어줬으면 좋겠음. 내 눈에는 C를 초고도 최적화 어셈블리로 컴파일하는 것과 비슷해 보이고, 직접 하고 싶지 않은 일을 확실히 대신해주는 도구처럼 보임

    • HTML과 CSS에 초고도 최적화 어셈블리 같은 걸 배포해야 한다면 우리가 올바른 방향으로 가고 있는지 모르겠음
      가장 단순하고 직관적인 HTML과 CSS를 작성하면 모든 기기의 브라우저가 그냥 잘 렌더링해야 한다고 봄
      정말 그런 수준의 최적화 산물을 배포해야 한다면 HTML과 CSS를 아예 건너뛰고, 고도로 최적화된 WebAssembly를 배포하게 한 뒤 개발자가 원하는 언어를 쓰게 하는 편이 낫겠음
  • SSG 출력의 유니코드 범위를 기준으로 글꼴을 부분집합화하고, CSS에 정의된 font-feature-settings를 바탕으로 OpenType 축을 고정하는 방법이 있으면 좋겠음

    • 맞음, 글꼴 쪽으로 할 수 있는 멋진 일이 많음. TODO에는 올바른 메트릭을 가진 시스템 글꼴 대체를 자동으로 추가해서 CLS를 자동 개선하는 작업이 있음
      이게 말한 “font-feature-settings 기반 OpenType 축 고정”인지, 아니면 다른 의미인지 궁금함
      글꼴 부분집합 최적화도 하고 싶지만 개선 폭이 얼마나 될지는 아직 잘 모르겠음. 수동으로 해본 적이 있는지 궁금함
    • 브라우저/시스템 글꼴을 쓰면 글꼴 크기 0으로 최적화할 수 있는데 굳이 할 필요가 있나 싶음
  • 별도 스타일시트에 두지 않고 인라인해야 하는 중요 CSS를 식별한다는 개념이 흥미로움
    중요 CSS와 비중요 CSS를 원칙적으로 구분하는 방법이 있길 기대했음. 예를 들어 :hover 같은 사용자 상호작용 효과는 항상 비중요로 본다든지
    그런데 사용하는 라이브러리는 페이지를 렌더링해보고 어떤 규칙이 중요하다고 볼 수 있는지 최선 추정하는 방식이라 조금 아쉬움: https://github.com/GoogleChromeLabs/critters

    • CSS가 50KB 미만이면 그냥 인라인하면 됨. 50KB가 넘는 CSS가 있다면 아마 뭔가 잘못하고 있는 것임
      물론 글꼴까지 인라인한다면 이해할 수 있지만, 그 외 스타일만 50KB를 넘는다면 대체로 잘못된 방향임
      진지하게 말하면, 인라인은 따뜻한 캐시와 비교해도 성능에 엄청나게 좋고, 외부 스타일시트나 스크립트가 더 나아지는 임계점은 생각보다 높아서 흔한 시장 기준으로는 수백 KB까지 올라가기도 함
      중요 CSS라는 개념은 근본 문제를 고치기보다 낭비한 성능을 조금 되찾으려는 패배주의적 접근처럼 느껴짐
      다만 이건 체계적 기법이 아니라 가벼운 경험과 관찰에 기반한 판단임. 누군가 이 개념을 더 제대로 측정해주면 좋겠지만, 내가 하게 될 것 같지는 않음
  • 이건 사람들이 애초에 SSG와 플러그인을 고르는 여러 용도를 커버하는 것처럼 보임. 특히 Astro나 Eleventy를 선택하는 경우라면 더 그렇겠음
    별도의 빌드 후 단계로 두는 편을 선호할 이유가 있을까? 개발 중 재빌드는 빨라지지만, 이미지 width 선언 같은 걸 추가하면서 생기는 미묘한 버그를 놓칠 가능성과의 절충처럼 보임

  • 웹페이지 레이아웃 작업을 싫어하고 배우기도 거부하지만 가끔은 해야 하는 입장에서는 이 도구가 아주 좋아 보임

  • 좋아 보임. 다만 개인적으로는 페이지를 첫 화면 아래로 스크롤했을 때 이미지를 기다려야 하는 걸 싫어함
    기본 동작으로는 첫 화면 콘텐츠가 끝난 뒤 나머지 아래쪽 콘텐츠를 백그라운드에서 로드하나?

    • 그렇지 않음. 브라우저의 네이티브 지연 로딩을 활용함. 주요 브라우저는 loading="lazy" 속성을 “이 이미지/iframe이 거의 보일 때까지 로드하지 말라”는 의미로 처리함: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/im...
      다만 종횡비는 인라인으로 넣어주기 때문에 로딩이 끝난 뒤 레이아웃이 바뀌지는 않음. 지연 로딩의 가장 큰 죄악을 피하는 셈임
    • @lelandfe가 짚은 것처럼 Jampack은 브라우저 네이티브 loading="lazy"를 사용함
      현재는 이 동작을 바꾸는 방법이 없지만, 페이지 전체가 로드된 뒤 첫 화면 아래 이미지를 백그라운드에서 미리 로드하는 옵션을 추가할 수는 있음. 꽤 좋은 아이디어임
      다만 페이지 하단의 불필요한 이미지까지 로드할까 봐 걱정됨. 옵션이라면 각자 켜거나 끌 수 있으니 괜찮을 듯함
  • 운영 환경에서 쓰는 정적 사이트 생성기로는 어떤 것들이 있나? 이 도구로 결과물을 더 최적화할 수 있을 것 같음
    예를 들어 어제 Divjoy React 웹사이트를 단순 HTML로 바꿔 S3 버킷에서 제공하려고 예제를 따라 하느라 하루를 다 썼음. 이렇게 어려울 줄은 몰랐고 아직도 헤매는 중임
    이상적으로는 S3 버킷에 자동 배포하고 도메인까지 연결해주는 무언가가 있으면 좋겠음. 돈까지 냈는데 개발자는 사라지고 Discord도 방치된 게 아픔. 그래서 항상 FOSS를 더 선호함

    • Hugo, Zola, Jekyll 정도가 있음
      어느 정도는 이런 기능의 일부를 갖고 있음
  • 내 프로젝트 하나에서는 큰 변화가 없었음. 예를 들어 전체 번들 크기는 줄었지만 gzip 크기는 늘어서 실제로는 내게 순손해였음
    그래도 CSS 개선은 실제로 도움이 된 것 같음
    아이디어는 훌륭해 보이고, 프로젝트에 이미지가 있었다면 아마 도움이 됐을 것임

    • 이미지가 없다면 이점이 제한적인 건 맞음. 또 브라우저 호환성을 자동으로 개선하기 때문에 최종 CSS 크기가 더 커질 수도 있음
      browserlist를 빈 문자열로 설정하면 이 기능을 끌 수 있음: https://jampack.divriots.com/features/browser-compatibility/