이미지 로딩 중...

Vite 플러그인 시스템 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 24. · 4 Views

Vite 플러그인 시스템 완벽 가이드

Vite의 강력한 플러그인 시스템을 처음부터 끝까지 배워봅니다. Rollup 호환성부터 실행 순서, 공식/커뮤니티 플러그인 활용까지 실무에 바로 적용할 수 있는 내용을 담았습니다.


목차

  1. Rollup 플러그인 호환성
  2. 플러그인 실행 순서 및 훅
  3. 공식 플러그인 소개 (@vitejs/plugin-react)
  4. 커뮤니티 플러그인 추천 목록
  5. vite-plugin-pwa 실습
  6. vite-plugin-svg-icons 활용

1. Rollup 플러그인 호환성

시작하며

여러분이 Vite 프로젝트에서 특별한 기능을 추가하려고 할 때, "이 기능을 처음부터 만들어야 하나?" 하고 고민한 적 있나요? 예를 들어 이미지 최적화, 환경변수 처리, 특정 파일 형식 변환 같은 작업들을 직접 구현하려면 시간이 오래 걸립니다.

이런 문제는 실제 개발 현장에서 자주 발생합니다. 빌드 도구마다 플러그인 시스템이 다르면 매번 새로 배워야 하고, 기존에 사용하던 플러그인을 재사용할 수 없어서 개발 생산성이 떨어지게 됩니다.

바로 이럴 때 필요한 것이 Vite의 Rollup 플러그인 호환성입니다. Vite는 이미 검증된 수많은 Rollup 플러그인들을 그대로 사용할 수 있게 해주어, 개발 시간을 크게 단축시켜줍니다.

개요

간단히 말해서, Vite는 Rollup의 플러그인 시스템을 기반으로 만들어졌기 때문에 대부분의 Rollup 플러그인을 그대로 사용할 수 있습니다. 왜 이 호환성이 필요한지 실무 관점에서 설명하자면, Rollup 생태계에는 이미 수천 개의 검증된 플러그인이 존재합니다.

이미지 최적화, 코드 압축, 환경변수 관리, CSS 전처리 등 거의 모든 기능이 플러그인으로 제공되고 있습니다. 예를 들어, 프로젝트에서 CommonJS 모듈을 사용해야 하는 경우 @rollup/plugin-commonjs를 바로 설치해서 사용할 수 있습니다.

기존에는 Webpack에서 Vite로 마이그레이션할 때 모든 플러그인을 새로 찾아야 했다면, 이제는 Rollup 플러그인을 그대로 활용할 수 있습니다. Vite의 핵심 특징은 개발 모드에서는 ESM을 사용하고, 프로덕션 빌드에서는 Rollup을 사용한다는 점입니다.

이러한 특징 덕분에 Rollup의 강력한 플러그인 생태계를 그대로 활용할 수 있고, 빌드 최적화와 트리 쉐이킹 같은 고급 기능도 자동으로 적용됩니다.

코드 예제

// vite.config.js
import { defineConfig } from 'vite'
import commonjs from '@rollup/plugin-commonjs' // Rollup 플러그인 직접 사용
import json from '@rollup/plugin-json' // JSON 파일 import 지원

export default defineConfig({
  plugins: [
    commonjs(), // CommonJS 모듈을 ESM으로 변환
    json() // JSON 파일을 모듈처럼 import 가능
  ],
  build: {
    rollupOptions: {
      // Rollup 전용 옵션도 함께 설정 가능
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom']
        }
      }
    }
  }
})

설명

이것이 하는 일: 위 설정은 Vite 프로젝트에서 Rollup의 공식 플러그인들을 직접 사용하는 방법을 보여줍니다. Rollup 플러그인을 npm에서 설치하고 Vite 설정 파일에 추가하기만 하면 바로 작동합니다.

첫 번째로, @rollup/plugin-commonjs는 Node.js 스타일의 CommonJS 모듈(require/module.exports)을 브라우저에서 사용 가능한 ESM 형식으로 변환합니다. 왜 이렇게 하는지 설명하자면, 많은 npm 패키지들이 아직 CommonJS 형식으로 배포되기 때문에 이 변환 과정이 필요합니다.

이 플러그인 없이는 에러가 발생할 수 있습니다. 그 다음으로, @rollup/plugin-json이 실행되면서 JSON 파일을 JavaScript 모듈처럼 import할 수 있게 만듭니다.

내부에서는 JSON 파일을 파싱하여 JavaScript 객체로 변환하고, 이를 모듈로 export합니다. 예를 들어 import config from './config.json' 같은 코드가 정상적으로 작동하게 됩니다.

마지막으로, build.rollupOptions 섹션에서는 Rollup에만 적용되는 세부 설정을 추가합니다. 여기서는 코드 스플리팅 전략을 지정하여, React 관련 라이브러리를 별도의 vendor 청크로 분리합니다.

최종적으로 이렇게 하면 캐싱 효율이 높아져 사용자가 앱을 재방문할 때 로딩 속도가 빨라집니다. 여러분이 이 설정을 사용하면 Rollup 생태계의 검증된 플러그인들을 자유롭게 활용할 수 있고, 별도의 학습 비용 없이 바로 프로젝트에 적용할 수 있습니다.

또한 Vite 전용 플러그인과 Rollup 플러그인을 함께 사용할 수 있어 최고의 유연성을 제공합니다.

실전 팁

💡 모든 Rollup 플러그인이 완벽하게 호환되는 것은 아닙니다. 개발 서버(HMR)에서만 작동하는 Vite 전용 훅이 필요한 경우 Rollup 플러그인은 빌드 시에만 적용됩니다.

💡 플러그인 순서가 중요합니다. 일반적으로 파일 변환 플러그인(예: TypeScript, Vue)을 먼저 배치하고, 최적화 플러그인(예: 압축, 난독화)은 나중에 배치해야 합니다.

💡 @rollup/ 네임스페이스로 시작하는 플러그인들은 Rollup 공식 플러그인으로 안정성이 검증되었습니다. 커뮤니티 플러그인보다 우선적으로 고려하세요.

💡 플러그인이 제대로 작동하지 않는다면 vite build --debug 명령어로 상세한 로그를 확인할 수 있습니다. 플러그인 실행 순서와 각 단계의 결과를 볼 수 있습니다.

💡 성능이 중요한 프로젝트라면 rollup-plugin-visualizer를 사용해서 번들 크기를 시각화하고, 어떤 플러그인이 빌드 시간에 영향을 주는지 분석하세요.


2. 플러그인 실행 순서 및 훅

시작하며

여러분이 여러 개의 플러그인을 함께 사용할 때, "왜 이 플러그인이 먼저 실행되고 저 플러그인은 나중에 실행될까?" 하고 궁금해한 적 있나요? 예를 들어 TypeScript를 JavaScript로 변환하는 플러그인과 코드를 압축하는 플러그인이 있다면, 당연히 변환을 먼저 하고 압축을 나중에 해야 합니다.

이런 문제는 실제 개발 현장에서 자주 발생합니다. 플러그인 순서가 잘못되면 빌드가 실패하거나, 최적화가 제대로 적용되지 않거나, 심지어 예상치 못한 버그가 발생할 수 있습니다.

특히 여러 플러그인이 같은 파일을 수정할 때 순서가 매우 중요합니다. 바로 이럴 때 필요한 것이 Vite의 플러그인 실행 순서와 훅 시스템입니다.

이 시스템을 이해하면 플러그인들이 정확히 원하는 순서대로 실행되도록 제어할 수 있습니다.

개요

간단히 말해서, Vite 플러그인은 특정 시점에 실행되는 "훅(hook)"이라는 함수들로 구성되어 있고, 이 훅들은 미리 정해진 순서대로 실행됩니다. 왜 이 개념이 필요한지 실무 관점에서 설명하자면, 빌드 프로세스는 여러 단계로 나뉘어 있습니다.

파일을 읽고, 변환하고, 번들링하고, 최적화하고, 출력하는 각 단계마다 플러그인이 개입할 수 있어야 합니다. 예를 들어, SVG 파일을 컴포넌트로 변환하는 플러그인은 파일을 읽는 단계에서 실행되어야 하고, 코드 난독화 플러그인은 모든 변환이 끝난 후 실행되어야 합니다.

기존에는 플러그인 순서를 수동으로 조정해야 했다면, 이제는 enforce 옵션을 통해 명시적으로 실행 순서를 지정할 수 있습니다. Vite의 핵심 특징은 플러그인을 'pre', 기본, 'post' 세 그룹으로 나눈다는 점입니다.

또한 각 플러그인은 config, configResolved, configureServer, transform, buildStart, buildEnd 같은 다양한 훅을 제공합니다. 이러한 특징들이 중요한 이유는 복잡한 빌드 파이프라인을 정확하게 제어할 수 있기 때문입니다.

코드 예제

// vite.config.js
import { defineConfig } from 'vite'

// 커스텀 플러그인 예시
function myPlugin() {
  return {
    name: 'my-plugin',
    enforce: 'pre', // 'pre' | 'post' | undefined(기본)

    // 설정이 확정된 후 실행
    configResolved(config) {
      console.log('설정 확정:', config.mode)
    },

    // 파일 변환 시 실행 (가장 많이 사용)
    transform(code, id) {
      if (id.endsWith('.custom')) {
        return code.replace(/OLD/g, 'NEW')
      }
    },

    // 빌드 시작/종료 시 실행
    buildStart() {
      console.log('빌드 시작')
    }
  }
}

export default defineConfig({
  plugins: [myPlugin()]
})

설명

이것이 하는 일: 위 코드는 Vite 플러그인의 기본 구조와 실행 순서 제어 방법을 보여줍니다. 플러그인은 name과 여러 훅 함수들로 구성된 객체를 반환하는 함수입니다.

첫 번째로, enforce: 'pre' 옵션은 이 플러그인을 다른 일반 플러그인보다 먼저 실행하도록 지정합니다. 왜 이렇게 하는지 설명하자면, 파일을 가장 먼저 처리해야 하는 플러그인(예: alias 해석, 환경변수 주입)은 'pre'로 설정하고, 최종 정리 작업을 하는 플러그인(예: 압축, 분석)은 'post'로 설정해야 순서 문제가 발생하지 않습니다.

그 다음으로, configResolved 훅이 실행되면서 최종 확정된 Vite 설정을 받아옵니다. 내부에서는 개발 모드인지 프로덕션 모드인지 확인하고, 그에 따라 플러그인 동작을 다르게 설정할 수 있습니다.

이 훅은 설정이 모두 병합되고 확정된 후 한 번만 실행됩니다. 세 번째로, transform 훅은 각 모듈이 로드될 때마다 실행되며, 코드를 변환할 수 있는 가장 강력한 훅입니다.

이 예시에서는 .custom 확장자를 가진 파일의 모든 'OLD' 문자열을 'NEW'로 치환합니다. id 매개변수는 파일의 절대 경로이고, code는 파일 내용입니다.

마지막으로, buildStartbuildEnd 훅은 전체 빌드 프로세스의 시작과 끝에 실행됩니다. 최종적으로 이들을 활용하면 빌드 시간 측정, 임시 파일 생성/정리, 빌드 통계 수집 같은 작업을 수행할 수 있습니다.

여러분이 이 훅 시스템을 이해하면 원하는 시점에 정확히 코드를 실행할 수 있고, 여러 플러그인이 충돌하지 않도록 조정할 수 있습니다. 또한 복잡한 빌드 요구사항도 단계별로 나누어 처리할 수 있어 유지보수가 쉬워집니다.

실전 팁

💡 transform 훅은 모든 파일마다 실행되므로 성능에 민감합니다. 불필요한 파일은 id를 체크해서 빠르게 필터링하세요. 예: if (!id.endsWith('.vue')) return

💡 플러그인 실행 순서는 [Alias 해석 → 사용자 플러그인(pre) → Vite 코어 플러그인 → 사용자 플러그인(기본) → Vite 빌드 플러그인 → 사용자 플러그인(post) → 최소화] 순서입니다.

💡 개발 모드와 빌드 모드에서 다르게 동작해야 한다면 apply: 'serve' 또는 apply: 'build' 옵션으로 플러그인을 조건부로 적용할 수 있습니다.

💡 훅에서 에러가 발생하면 전체 빌드가 중단됩니다. try-catch로 에러를 처리하고, 개발자에게 명확한 에러 메시지를 제공하세요.

💡 handleHotUpdate 훅을 사용하면 HMR(Hot Module Replacement) 동작을 커스터마이징할 수 있습니다. 특정 파일이 변경되었을 때 전체 페이지를 새로고침할지, 모듈만 교체할지 제어할 수 있습니다.


3. 공식 플러그인 소개 (@vitejs/plugin-react)

시작하며

여러분이 Vite로 React 프로젝트를 시작할 때, "JSX 문법을 어떻게 변환하지? Fast Refresh는 어떻게 설정하지?" 하고 복잡하게 고민한 적 있나요?

React 개발에 필요한 여러 설정들을 일일이 찾아서 적용하려면 시간이 오래 걸리고 실수하기도 쉽습니다. 이런 문제는 실제 개발 현장에서 자주 발생합니다.

React를 제대로 사용하려면 Babel 설정, JSX 변환, Fast Refresh, React DevTools 연동 등 다양한 설정이 필요한데, 이를 하나하나 설정하다 보면 프로젝트 시작도 전에 지치게 됩니다. 바로 이럴 때 필요한 것이 Vite의 공식 React 플러그인입니다.

이 플러그인 하나만 설치하면 React 개발에 필요한 모든 기능이 자동으로 설정되어 바로 개발을 시작할 수 있습니다.

개요

간단히 말해서, @vitejs/plugin-react는 Vite 팀이 공식적으로 관리하는 플러그인으로, React 프로젝트에 필요한 모든 핵심 기능을 제공합니다. 왜 이 플러그인이 필요한지 실무 관점에서 설명하자면, React는 JSX라는 특별한 문법을 사용하는데 브라우저는 JSX를 이해하지 못합니다.

따라서 JSX를 일반 JavaScript로 변환하는 작업이 필수입니다. 또한 개발 중에 코드를 수정하면 자동으로 화면이 업데이트되는 Fast Refresh 기능도 매우 중요합니다.

예를 들어, 컴포넌트의 state를 유지한 채로 UI만 업데이트할 수 있어 개발 속도가 크게 향상됩니다. 기존에는 Create React App 같은 도구가 이런 설정을 해주었다면, 이제는 Vite가 훨씬 빠른 속도로 같은 기능을 제공합니다.

이 플러그인의 핵심 특징은 Babel을 사용한 JSX 변환, Fast Refresh 자동 적용, React DevTools 연동입니다. 이러한 특징들이 중요한 이유는 별도의 복잡한 설정 없이 React 개발 환경을 즉시 구축할 수 있고, 프로덕션 빌드 시에도 최적화가 자동으로 적용되기 때문입니다.

코드 예제

// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react({
      // Fast Refresh 옵션 (기본값: true)
      fastRefresh: true,

      // Babel 옵션 커스터마이징
      babel: {
        plugins: [
          // emotion CSS-in-JS 지원
          '@emotion/babel-plugin'
        ]
      },

      // JSX 런타임 설정 (React 17+는 자동)
      jsxRuntime: 'automatic'
    })
  ]
})

설명

이것이 하는 일: 위 설정은 Vite 프로젝트에서 React 플러그인을 설치하고 커스터마이징하는 방법을 보여줍니다. 단 한 줄의 react() 호출만으로도 기본 기능은 모두 작동하지만, 세부 옵션을 통해 프로젝트에 맞게 조정할 수 있습니다.

첫 번째로, fastRefresh: true 옵션은 코드 변경 시 컴포넌트의 state를 유지한 채로 UI만 업데이트하는 기능을 활성화합니다. 왜 이렇게 하는지 설명하자면, 일반적인 새로고침은 전체 앱을 다시 로드하여 state가 초기화되지만, Fast Refresh는 변경된 컴포넌트만 교체하여 개발 중인 화면 상태를 그대로 유지할 수 있습니다.

예를 들어 모달이 열린 상태에서 코드를 수정해도 모달이 계속 열려있습니다. 그 다음으로, babel.plugins 옵션이 실행되면서 추가적인 Babel 플러그인을 적용합니다.

내부에서는 React JSX 변환 외에도 Emotion 같은 CSS-in-JS 라이브러리를 위한 추가 변환을 수행합니다. 이렇게 하면 styled components나 css prop 같은 고급 기능을 사용할 수 있습니다.

마지막으로, jsxRuntime: 'automatic' 설정은 React 17부터 도입된 새로운 JSX 변환 방식을 사용합니다. 최종적으로 이렇게 하면 각 파일마다 import React from 'react'를 작성하지 않아도 JSX를 사용할 수 있어 코드가 더 깔끔해집니다.

여러분이 이 플러그인을 사용하면 React 프로젝트를 몇 분 안에 설정할 수 있고, Webpack보다 훨씬 빠른 개발 서버를 경험할 수 있습니다. 또한 Vite 팀이 직접 관리하는 공식 플러그인이므로 버그가 적고 업데이트도 빠르게 이루어집니다.

실전 팁

💡 TypeScript를 사용한다면 별도의 플러그인 없이도 .tsx 파일이 자동으로 지원됩니다. tsconfig.json에서 "jsx": "react-jsx"로 설정하세요.

💡 Preact를 사용하고 싶다면 @vitejs/plugin-react 대신 @preact/preset-vite를 사용하세요. API는 거의 동일하지만 번들 크기가 훨씬 작습니다.

💡 Fast Refresh가 제대로 작동하지 않는다면 컴포넌트 이름이 대문자로 시작하는지 확인하세요. function MyComponent()는 작동하지만 function myComponent()는 작동하지 않습니다.

💡 프로덕션 빌드에서 React DevTools 관련 코드를 완전히 제거하려면 process.env.NODE_ENV를 명시적으로 체크하는 코드를 피하고, Vite의 import.meta.env.PROD를 사용하세요.

💡 Emotion이나 styled-components를 사용한다면 .babelrc를 만들지 말고 vite.config.js의 babel 옵션에 플러그인을 추가하세요. 그래야 Vite의 빠른 빌드 속도를 유지할 수 있습니다.


4. 커뮤니티 플러그인 추천 목록

시작하며

여러분이 Vite 프로젝트에서 특정 기능이 필요할 때, "공식 플러그인에는 없는데 어떻게 하지?" 하고 막막했던 경험 있나요? 예를 들어 PWA 지원, 이미지 최적화, Markdown 파일을 컴포넌트로 변환, 환경변수 타입 체크 같은 기능들은 공식 플러그인에서 제공하지 않습니다.

이런 문제는 실제 개발 현장에서 자주 발생합니다. 특정 프로젝트 요구사항을 충족하려면 추가 기능이 필요한데, 이를 직접 구현하려면 시간이 오래 걸리고 유지보수도 어렵습니다.

또한 어떤 플러그인이 신뢰할 만한지 판단하기도 쉽지 않습니다. 바로 이럴 때 필요한 것이 검증된 커뮤니티 플러그인 목록입니다.

Vite 생태계에는 수많은 고품질 플러그인들이 있고, 이들을 잘 활용하면 개발 생산성을 크게 높일 수 있습니다.

개요

간단히 말해서, Vite 커뮤니티에는 다양한 요구사항을 해결하는 수백 개의 플러그인이 있으며, 그중 검증되고 많이 사용되는 플러그인들을 선별하여 사용하는 것이 중요합니다. 왜 이런 플러그인 목록이 필요한지 실무 관점에서 설명하자면, 프로젝트마다 요구사항이 다릅니다.

어떤 프로젝트는 PWA가 필요하고, 어떤 프로젝트는 SVG를 컴포넌트로 사용하고, 어떤 프로젝트는 레거시 브라우저 지원이 필요합니다. 예를 들어, 모바일 앱처럼 오프라인에서도 작동해야 하는 웹앱이라면 vite-plugin-pwa가 필수입니다.

기존에는 각 기능을 직접 구현하거나 여러 도구를 조합해야 했다면, 이제는 한 줄의 플러그인 설치로 해결할 수 있습니다. 커뮤니티 플러그인의 핵심 특징은 특정 문제에 특화되어 있고, 활발하게 유지보수되며, 문서화가 잘 되어 있다는 점입니다.

이러한 특징들이 중요한 이유는 검증된 플러그인을 사용하면 버그가 적고 커뮤니티 지원을 받을 수 있어 문제 해결이 빠르기 때문입니다.

코드 예제

// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa' // PWA 지원
import viteImagemin from 'vite-plugin-imagemin' // 이미지 최적화
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' // SVG 아이콘
import checker from 'vite-plugin-checker' // TypeScript/ESLint 체크
import path from 'path'

export default defineConfig({
  plugins: [
    react(),
    VitePWA({ registerType: 'autoUpdate' }), // 자동 업데이트 PWA
    viteImagemin({ // PNG/JPEG/SVG 최적화
      gifsicle: { optimizationLevel: 7 },
      mozjpeg: { quality: 80 }
    }),
    createSvgIconsPlugin({ // SVG 스프라이트 생성
      iconDirs: [path.resolve(process.cwd(), 'src/icons')]
    }),
    checker({ typescript: true, eslint: { lintCommand: 'eslint src' } })
  ]
})

설명

이것이 하는 일: 위 설정은 실무에서 자주 사용되는 네 가지 커뮤니티 플러그인을 조합하여 프로젝트에 고급 기능을 추가하는 방법을 보여줍니다. 각 플러그인은 독립적으로 작동하며 서로 충돌하지 않습니다.

첫 번째로, VitePWA 플러그인은 Progressive Web App 기능을 자동으로 설정합니다. 왜 이렇게 하는지 설명하자면, Service Worker, Web App Manifest, 오프라인 캐싱 같은 복잡한 PWA 설정을 자동으로 생성해주기 때문입니다.

registerType: 'autoUpdate' 옵션은 새 버전이 배포되면 사용자 브라우저가 자동으로 업데이트하도록 설정합니다. 그 다음으로, viteImagemin 플러그인이 실행되면서 빌드 시 모든 이미지 파일을 자동으로 최적화합니다.

내부에서는 JPEG는 mozjpeg, PNG는 pngquant, SVG는 svgo 같은 최적화 도구를 사용하여 파일 크기를 줄입니다. 이렇게 하면 웹사이트 로딩 속도가 크게 개선됩니다.

보통 30-50% 정도 이미지 크기가 줄어듭니다. 세 번째로, createSvgIconsPlugin은 지정된 폴더의 모든 SVG 파일을 하나의 스프라이트로 합쳐서 네트워크 요청을 줄입니다.

예를 들어 100개의 아이콘이 있어도 한 번의 요청으로 모두 로드되고, 각 아이콘을 <svg><use href="#icon-name" /></svg> 형식으로 사용할 수 있습니다. 마지막으로, checker 플러그인은 개발 서버 실행 중에도 TypeScript 타입 에러와 ESLint 경고를 실시간으로 확인합니다.

최종적으로 이렇게 하면 코드를 저장하는 즉시 브라우저와 터미널에 에러가 표시되어 문제를 빠르게 발견할 수 있습니다. 여러분이 이런 플러그인들을 조합하면 엔터프라이즈급 기능을 몇 줄의 설정으로 추가할 수 있고, 각 플러그인은 독립적으로 업데이트되므로 유지보수도 쉽습니다.

또한 필요한 플러그인만 선택적으로 추가할 수 있어 번들 크기를 최소화할 수 있습니다.

실전 팁

💡 플러그인을 설치하기 전에 npm 다운로드 수와 GitHub 스타 개수를 확인하세요. 주간 다운로드가 1만 이상이고 스타가 500개 이상이면 안정적입니다.

💡 vite-plugin-inspect를 설치하면 각 플러그인이 파일을 어떻게 변환하는지 시각적으로 확인할 수 있습니다. 디버깅할 때 매우 유용합니다.

💡 레거시 브라우저(IE11 등) 지원이 필요하다면 @vitejs/plugin-legacy를 사용하세요. 자동으로 폴리필을 추가하고 구형 브라우저용 번들을 별도로 생성합니다.

💡 Markdown 파일을 React 컴포넌트로 변환하려면 vite-plugin-mdx를 사용하세요. MDX 문법을 지원하여 마크다운 안에 JSX를 작성할 수 있습니다.

💡 환경변수에 타입 안정성을 추가하려면 vite-plugin-env-types를 사용하세요. .env 파일을 분석하여 자동으로 TypeScript 타입 정의를 생성합니다.


5. vite-plugin-pwa 실습

시작하며

여러분이 웹앱을 개발할 때, "사용자가 오프라인일 때도 앱이 작동하게 하려면 어떻게 해야 하지? 홈 화면에 설치 가능하게 만들려면?" 하고 고민한 적 있나요?

Progressive Web App(PWA) 기능을 직접 구현하려면 Service Worker, Cache API, Web App Manifest 등 복잡한 개념들을 모두 이해해야 합니다. 이런 문제는 실제 개발 현장에서 자주 발생합니다.

모바일 사용자들은 네트워크 연결이 불안정한 환경에서도 앱이 작동하기를 기대하고, 네이티브 앱처럼 홈 화면에서 바로 실행하기를 원합니다. PWA를 수동으로 설정하면 실수하기 쉽고 유지보수도 어렵습니다.

바로 이럴 때 필요한 것이 vite-plugin-pwa입니다. 이 플러그인은 복잡한 PWA 설정을 자동화하여 몇 줄의 설정만으로 프로덕션급 PWA를 만들어줍니다.

개요

간단히 말해서, vite-plugin-pwa는 Vite 프로젝트에 PWA 기능을 추가하는 가장 인기 있는 플러그인으로, Service Worker 생성, 캐싱 전략, Manifest 설정을 모두 자동화합니다. 왜 이 플러그인이 필요한지 실무 관점에서 설명하자면, PWA는 웹과 네이티브 앱의 장점을 결합한 기술입니다.

오프라인 지원, 푸시 알림, 백그라운드 동기화, 홈 화면 설치 같은 기능을 웹 기술로 구현할 수 있습니다. 예를 들어, 사용자가 지하철에서 인터넷이 끊겨도 이전에 방문한 페이지들은 캐시에서 로드되어 계속 사용할 수 있습니다.

기존에는 Workbox 라이브러리를 직접 설정하고 Service Worker 코드를 작성해야 했다면, 이제는 설정 파일에 몇 줄만 추가하면 모든 것이 자동으로 생성됩니다. 이 플러그인의 핵심 특징은 Workbox 기반의 강력한 캐싱 전략, 자동 업데이트 지원, TypeScript 타입 정의 포함입니다.

이러한 특징들이 중요한 이유는 프로덕션 환경에서 안정적으로 작동하는 PWA를 빠르게 구축할 수 있고, 사용자 경험을 크게 개선할 수 있기 때문입니다.

코드 예제

// vite.config.js
import { defineConfig } from 'vite'
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
  plugins: [
    VitePWA({
      registerType: 'autoUpdate', // 새 버전 자동 업데이트
      includeAssets: ['favicon.ico', 'robots.txt', 'apple-touch-icon.png'],
      manifest: {
        name: '내 멋진 앱',
        short_name: '멋진앱',
        description: 'Vite + PWA 실습 프로젝트',
        theme_color: '#ffffff',
        icons: [
          {
            src: 'pwa-192x192.png',
            sizes: '192x192',
            type: 'image/png'
          },
          {
            src: 'pwa-512x512.png',
            sizes: '512x512',
            type: 'image/png',
            purpose: 'any maskable' // 다양한 플랫폼 지원
          }
        ]
      },
      workbox: {
        // 런타임 캐싱 전략
        runtimeCaching: [
          {
            urlPattern: /^https:\/\/api\.example\.com\/.*/i,
            handler: 'NetworkFirst', // API는 네트워크 우선
            options: {
              cacheName: 'api-cache',
              expiration: {
                maxEntries: 10,
                maxAgeSeconds: 60 * 60 // 1시간
              }
            }
          }
        ]
      }
    })
  ]
})

설명

이것이 하는 일: 위 설정은 완전한 기능을 갖춘 PWA를 만드는 실제 설정 예시입니다. 이 설정만으로 앱이 오프라인에서 작동하고, 사용자가 홈 화면에 설치할 수 있게 됩니다.

첫 번째로, registerType: 'autoUpdate'는 새 버전이 배포되면 사용자에게 별도의 확인 없이 자동으로 업데이트하도록 설정합니다. 왜 이렇게 하는지 설명하자면, 사용자가 수동으로 새로고침하지 않아도 항상 최신 버전을 사용할 수 있어 버그 수정과 기능 업데이트가 빠르게 전파되기 때문입니다.

대신 'prompt' 옵션을 사용하면 사용자에게 업데이트 확인을 요청할 수 있습니다. 그 다음으로, manifest 객체가 실행되면서 Web App Manifest 파일을 생성합니다.

내부에서는 앱 이름, 아이콘, 테마 색상 같은 메타데이터를 정의하여 모바일 기기에서 네이티브 앱처럼 보이게 만듭니다. 예를 들어 iOS에서 홈 화면에 추가하면 이 아이콘과 이름이 표시됩니다.

purpose: 'any maskable'은 다양한 플랫폼의 아이콘 형식을 지원합니다. 세 번째로, workbox.runtimeCaching 설정은 Service Worker의 캐싱 전략을 정의합니다.

이 예시에서는 API 요청에 대해 'NetworkFirst' 전략을 사용하는데, 이는 먼저 네트워크에서 데이터를 가져오려고 시도하고 실패하면 캐시에서 가져오는 방식입니다. 이렇게 하면 최신 데이터를 우선하면서도 오프라인에서도 작동합니다.

마지막으로, expiration 옵션은 캐시 관리 정책을 설정합니다. 최종적으로 최대 10개의 API 응답만 캐시에 저장하고, 1시간이 지난 데이터는 자동으로 삭제하여 캐시가 무한정 커지는 것을 방지합니다.

여러분이 이 설정을 사용하면 프로페셔널한 PWA를 쉽게 만들 수 있고, Lighthouse PWA 점수에서 높은 점수를 받을 수 있습니다. 또한 모바일 사용자들에게 훨씬 나은 사용자 경험을 제공할 수 있습니다.

실전 팁

💡 개발 중에는 PWA 기능을 테스트하기 어려우므로 pnpm build && pnpm preview 명령어로 프로덕션 빌드를 로컬에서 확인하세요.

💡 캐싱 전략은 리소스 타입에 따라 달라야 합니다. HTML은 'NetworkFirst', CSS/JS는 'CacheFirst', 이미지는 'CacheFirst', API는 'NetworkFirst' 또는 'StaleWhileRevalidate'를 사용하세요.

💡 Chrome DevTools의 Application 탭에서 Service Worker 상태와 캐시 내용을 실시간으로 확인할 수 있습니다. 디버깅할 때 꼭 확인하세요.

💡 PWA 아이콘은 반드시 192x192와 512x512 두 가지 크기를 제공해야 합니다. Maskable 아이콘을 만들려면 https://maskable.app 도구를 사용하세요.

💡 Service Worker 업데이트가 제대로 안 되면 workbox.cleanupOutdatedCaches: true 옵션을 추가하여 오래된 캐시를 자동으로 정리하세요.


6. vite-plugin-svg-icons 활용

시작하며

여러분이 웹 프로젝트에서 아이콘을 사용할 때, "아이콘마다 파일을 import하면 코드가 지저분해지고, Font Awesome 같은 라이브러리는 번들 크기가 너무 크다" 하고 고민한 적 있나요? 수십 개의 SVG 아이콘을 효율적으로 관리하고 사용하는 것은 생각보다 까다로운 문제입니다.

이런 문제는 실제 개발 현장에서 자주 발생합니다. 각 아이콘을 개별 파일로 import하면 네트워크 요청이 많아지고, 아이콘 폰트를 사용하면 불필요한 아이콘까지 모두 다운로드되어 초기 로딩이 느려집니다.

또한 아이콘 색상이나 크기를 동적으로 변경하기도 어렵습니다. 바로 이럴 때 필요한 것이 vite-plugin-svg-icons입니다.

이 플러그인은 모든 SVG 아이콘을 하나의 스프라이트로 합쳐서 효율적으로 관리하고, 컴포넌트처럼 쉽게 사용할 수 있게 해줍니다.

개요

간단히 말해서, vite-plugin-svg-icons는 프로젝트의 SVG 파일들을 자동으로 스프라이트 시트로 변환하여 한 번의 네트워크 요청으로 모든 아이콘을 로드하고, 각 아이콘을 ID로 참조할 수 있게 해줍니다. 왜 이 플러그인이 필요한지 실무 관점에서 설명하자면, 대규모 프로젝트에서는 수백 개의 아이콘을 사용하는 경우가 많습니다.

각 아이콘을 개별적으로 로드하면 네트워크 오버헤드가 크고, 아이콘 폰트는 사용하지 않는 아이콘까지 포함되어 비효율적입니다. 예를 들어, 50개의 아이콘을 사용한다면 50번의 HTTP 요청 대신 1번의 요청으로 모두 로드할 수 있습니다.

기존에는 수동으로 SVG 스프라이트를 만들고 관리해야 했다면, 이제는 SVG 파일을 폴더에 넣기만 하면 자동으로 스프라이트가 생성됩니다. 이 플러그인의 핵심 특징은 빌드 시 자동 스프라이트 생성, TypeScript 타입 지원, HMR(Hot Module Replacement) 지원입니다.

이러한 특징들이 중요한 이유는 아이콘을 추가하거나 수정할 때 즉시 반영되고, 타입 안정성을 유지하면서 개발할 수 있기 때문입니다.

코드 예제

// vite.config.js
import { defineConfig } from 'vite'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'

export default defineConfig({
  plugins: [
    createSvgIconsPlugin({
      // 아이콘 파일들이 있는 폴더 경로
      iconDirs: [path.resolve(process.cwd(), 'src/icons')],

      // 스프라이트에서 사용할 ID 형식
      symbolId: 'icon-[dir]-[name]',

      // SVG 최적화 옵션
      svgoOptions: {
        plugins: [
          {
            name: 'removeAttrs',
            params: { attrs: ['fill', 'stroke'] } // 색상 동적 변경 가능
          }
        ]
      }
    })
  ]
})

// src/main.js - 스프라이트 등록 (앱 시작 시 한 번만)
import 'virtual:svg-icons-register'

// src/components/SvgIcon.jsx - 재사용 가능한 아이콘 컴포넌트
export function SvgIcon({ name, color = 'currentColor', size = 24 }) {
  return (
    <svg width={size} height={size} style={{ color }}>
      <use href={`#icon-${name}`} />
    </svg>
  )
}

// 사용 예시
// <SvgIcon name="home" color="blue" size={32} />

설명

이것이 하는 일: 위 설정은 SVG 아이콘을 스프라이트로 관리하고 React 컴포넌트로 사용하는 완전한 워크플로우를 보여줍니다. 이 방식은 성능과 개발자 경험 모두를 최적화합니다.

첫 번째로, iconDirs 옵션은 SVG 파일들이 저장된 폴더를 지정합니다. 왜 이렇게 하는지 설명하자면, 빌드 시 이 폴더를 스캔하여 모든 SVG 파일을 자동으로 찾아 스프라이트에 포함시키기 때문입니다.

여러 폴더를 배열로 지정할 수 있어서 아이콘을 카테고리별로 구분할 수 있습니다. 예를 들어 ['src/icons/ui', 'src/icons/social'] 같은 구조로 관리할 수 있습니다.

그 다음으로, symbolId 패턴이 실행되면서 각 아이콘에 고유한 ID를 부여합니다. 내부에서는 [dir]은 폴더 이름, [name]은 파일 이름으로 치환되어 icon-ui-home, icon-social-twitter 같은 ID가 생성됩니다.

이렇게 하면 같은 이름의 아이콘이 다른 폴더에 있어도 충돌하지 않습니다. 세 번째로, svgoOptions는 SVG 최적화 설정을 정의합니다.

이 예시에서는 fillstroke 속성을 제거하여 CSS나 props로 색상을 동적으로 변경할 수 있게 만듭니다. 만약 이 속성들이 SVG에 하드코딩되어 있으면 색상을 변경할 수 없습니다.

마지막으로, SvgIcon 컴포넌트는 재사용 가능한 래퍼를 제공합니다. 최종적으로 이렇게 하면 <SvgIcon name="home" />처럼 간단하게 아이콘을 사용할 수 있고, props로 크기와 색상을 쉽게 변경할 수 있습니다.

<use> 요소는 스프라이트에서 특정 아이콘을 참조합니다. 여러분이 이 방식을 사용하면 수백 개의 아이콘도 효율적으로 관리할 수 있고, 네트워크 요청이 1번으로 줄어들어 로딩 속도가 크게 개선됩니다.

또한 아이콘을 추가하거나 수정할 때 코드 변경 없이 파일만 교체하면 되므로 유지보수가 매우 쉽습니다.

실전 팁

💡 SVG 파일은 가능한 한 단순하게 유지하세요. Figma나 Illustrator에서 export할 때 "Outline Stroke"와 "Simplify" 옵션을 활성화하여 불필요한 경로를 제거하세요.

💡 아이콘 색상을 동적으로 변경하려면 SVG에서 fillstroke를 제거하고, CSS의 currentColor를 사용하세요. 그러면 부모 요소의 color 속성을 따라갑니다.

💡 TypeScript를 사용한다면 symbolId 패턴에서 생성된 모든 아이콘 이름의 타입을 자동 생성할 수 있습니다. customDomId 옵션과 함께 타입 생성 스크립트를 작성하세요.

💡 개발 중에 아이콘이 보이지 않는다면 브라우저 DevTools에서 <body>의 맨 처음에 <svg> 스프라이트가 주입되었는지 확인하세요. display: none 스타일이 적용되어 있어야 정상입니다.

💡 아이콘을 카테고리별로 폴더 구조로 관리하고, symbolId[dir]을 포함시키면 <SvgIcon name="ui-home" />, <SvgIcon name="social-twitter" /> 같은 명확한 이름을 사용할 수 있습니다.


#Vite#Plugin#Rollup#PWA#SVG#Vite,빌드도구,프론트엔드

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

WebSocket과 Server-Sent Events 실시간 통신 완벽 가이드

웹 애플리케이션에서 실시간 데이터 통신을 구현하는 핵심 기술인 WebSocket과 Server-Sent Events를 다룹니다. 채팅, 알림, 실시간 업데이트 등 현대 웹 서비스의 필수 기능을 구현하는 방법을 배워봅니다.

API 테스트 전략과 자동화 완벽 가이드

API 개발에서 필수적인 테스트 전략을 단계별로 알아봅니다. 단위 테스트부터 부하 테스트까지, 실무에서 바로 적용할 수 있는 자동화 기법을 익혀보세요.

효과적인 API 문서 작성법 완벽 가이드

API 문서는 개발자와 개발자 사이의 가장 중요한 소통 수단입니다. 이 가이드에서는 좋은 API 문서가 갖춰야 할 조건부터 Getting Started, 엔드포인트 설명, 에러 코드 문서화, 인증 가이드, 변경 이력 관리까지 체계적으로 배워봅니다.

API 캐싱과 성능 최적화 완벽 가이드

웹 서비스의 응답 속도를 획기적으로 개선하는 캐싱 전략과 성능 최적화 기법을 다룹니다. HTTP 캐싱부터 Redis, 데이터베이스 최적화, CDN까지 실무에서 바로 적용할 수 있는 핵심 기술을 초급자 눈높이에서 설명합니다.

OAuth 2.0과 소셜 로그인 완벽 가이드

OAuth 2.0의 핵심 개념부터 구글, 카카오 소셜 로그인 구현까지 초급 개발자를 위해 쉽게 설명합니다. 인증과 인가의 차이점, 다양한 Flow의 특징, 그리고 보안 고려사항까지 실무에 바로 적용할 수 있는 내용을 다룹니다.