Vite 가이드에서는 이렇게 설명하고 있다.
Vite(프랑스어로 "빠르다(Quick)"를 의미하며, 발음은 "veet"와 비슷한 /vit/
입니다.)은 빠르고 간결한 모던 웹 프로젝트 개발 경험에 초점을 맞춰 탄생한 빌드 도구이며, 두 가지 컨셉을 중심으로 하고 있습니다.
- 개발 시 네이티브 ES Module을 넘어 더욱 다양한 기능을 제공합니다. 가령, Hot Module Replacement (HMR)과 같은 것들 말이죠.
- 번들링 시, Rollup 기반의 다양한 빌드 커맨드를 사용할 수 있습니다. 이는 높은 수준으로 최적화된 정적(Static) 리소스들을 배포할 수 있게끔 하며, 미리 정의된 설정(Pre-configured)을 제공합니다.
vite는 기본적으로 최적화 된 설정을 제공하지만, Plugin API 또는 JavaScript API를 이용할 수 있습니다. (물론 TypeScript 역시 지원하구요.)
예전에는 HTML, CSS, JS 파일을 모두 서버에 올리면 그것으로 배포가 끝이었다.
하지만 JS 라이브러리를 사용하기 시작하면서 편하게 사용하기 위해 npm(node package manager)이 생겼고 여러 라이브러리를 import
하여 사용하기 시작했다.
node_modules
폴더가 너무 커져서 서버에 올리는 데에 많은 비용이 든다.import/require
문법은 브라우저 친화적이지 않다. (호환성이나 지원하지 않는 문법)모든 JS 파일을 하나로 합친다. (bundling) ex) webpack
import/require
문법을 사용하지 않는다.사용하는 npm 라이브러리가 많아질수록 webpack의 번들링이 오래걸린다.
vite는 depenendcies와 soure code 두가지 카테리로 나누어 개발 서버를 시작하도록 하여 서버 구동에 걸리는 시간을 단축했다.
vite의 pre-bundling 기능은 esbuild를 사용하고 있다.
Go 기반으로 만든 esbuild는 기존 번들러인 Webpack, Parcel 대비 10-100배 빠른 번들링 속도를 보였다.
vite는 native ESM을 이용해 소스코드를 제공하도록 한다.
브라우저가 곧 번들러라는 뜻
브라우저가 특정 모듈에 대한 소스 코드를 요청하면 이를 전달할 뿐이다.
조건부 동적 import 이후의 코든느 현재 화면에서 실제로 사용되어야만 처리한다.
느렸던 소스 코드 업데이트
기존의 번들러 기반으로는 소스 코드를 업데이트하면 전체 번들링을 다시 해야 했기 때문에 서비스가 커질수록 시간이 더 걸릴 수 밖에 없었다.
일부 번들러의 경우 메모리 상에서 이를 진행하여 실제로 갱신에 영향을 받는 파일들만을 새로이 번들링 하게끔 했으나, 결국 처음에는 모든 파일에 대한 번들링이 필요했다.
vite는 ESM을 이용한 HMR(Hot Module Replacement)을 지원한다. 어떤 모듈이 수정되면 vite는 수정된 모듈과 관련된 부분만 교체하고 브라우저에서 해당 모듈을 요청하면 교체된 모듈을 전달한다. 전 과정에서 ESM을 완벽하게 이용하므로 앱 사이즈가 커져도 갱신 시간에는 영향을 끼치지 않는다.
또한 vite는 HTTP 헤더를 이용해 소스코드는 304 Not Modified
, 디펜던시는 Cache-Control: max-age=31536000,immutable
을 이용해 캐시되도록 하여 한번으 요청이라도 줄여 퍼포먼스를 높였다.
import {method} from 'some-where'
이 코드는 네이티브 es에서 모듈의 위치를 찾을 수 없기 때문에 정상적으로 실행되지 않는다.
하지만 vite은 다음을 기준으로 모듈을 가져오기 때문에 정상적으로 실행된다.
/node_modules/.vite/deps/my-dep.js?v=f2sf5t3ed
와 같이 URL을 이용해 ESM을 지원하는 브라우저에서 모듈을 가져올 수 있도록 import
구문을 수정한다.추가로 디펜던시는 반드시 캐싱된다.
vite는 HTTP 헤더를 이용해 요청한 디펜던시를 브라우저에서 캐시하도록 한다.
vite에서는 기본적으로 ESM을 통해 HMR API를 제공한다. HMR 기능이 있는 프레임워크는 API를 활용하여 페이지를 다시 로드하거나 상태를 날려버리지 않고 즉각적이고 정확한 업데이트를 제공한다. vite는 Vue Single File Components, React Fast Refresh 또는 @prefresh/vite 와 같은 First-party HMR 모듈을 제공한다.
물론,create-vite
에서 제공하는 템플릿에 기본적으로 HMR 모듈이 포함되어 있다.
.ts
파일에 대한 컴파일 및 import 역시 지원한다.
vite는 ts 파일에 대하여 트랜스파일링만 수행한다. (타입 검사는 IDE와 빌드 프로세스에서 수행된다.)
기본적으로 두 작업이 다르기 때문인데, 트랜스파일링은 파일 단위로 작동할 수 있으며, vite의 컴파일 모델과 일치한다. 하지만 타입 검사는 전체 모듈 그래프에 대한 탐색이 필요하므로 vite의 파이프라인에 타입 검사를 추가하게 되면 속도 이점이 사라지기 때문이다.
vite의 TypeScript 컴파일링은 esbuild를 이용하며, TypeScript 소스 코드를 JavaScript 소스 코드로 변환하는 작업에 대해 tsc 대비 약 20~30배 정도 빠른 퍼포먼스를 보이고 있다. (HMR은 50ms 미만)
ClientTypes
vite는 기본적으로 Node.js API 기반의 타입 시스템을 차용하고 있기 때문에 Client-side의 환경을 위해 Shim을 구성하고자 한다면 d.ts
선언 파일을 추가해야한다.
/// <reference types="vite/cleint" />
또는, tsconfig
내 compilerOptions.types
옵션에 vite/client
를 명시해 줄 수도 있다.
.svg
와 같은 에셋import.meta.env
에 명시된 환경 변수 타입들import.meta.hot
에 명시된 HMR API 타입들ex
declare module '*.svg' {
const content: React.FC<React.SVGProps<SVGElement>>
export default content
}
/// <reference types="vite/client" />
vite는 기본적으로 vue를 지원하고 있다.
.jsx
와 .tsx
사용 가능. 마찬가지로 esbuild를 통해 컴파일링한다.
.css
파일을 import 할 때, 기본적으로 HMR을 위해 <style>
태그로 변환되어 불러온다.
css @import
와 URL 재정의(Rebasing)
vite는 postcss-import
를 이용해 css의 @import
를 처리한다. 또한, CSS url()
로 참조되는 모든 리소스에 대해 별다른 설정 없이 base를 맞춰주는 Rebasing 역시 진행한다.
별칭을 이용한 @import
도 지원하며, 모든 것은 Sass나 Less에서도 사용이 가능하다.
PostCSS
만약 프로젝트에 PostCSS 설정 파일이 존재한다면 vite는 이를 이용해 모든 CSS 파일에 해당 설정을 적용한다.
CSS의 최소화는 PostCSS 이후에 진행되며, build.cssTarget
옵션을 이용해 설정할 수 있다.
CSS Modules
.module.css
확장자로 끝나는 모든 CSS 파일은 CSS 모듈 파일로 취급하고 일반적인 JS 모듈처럼 사용이 가능하다.
정적 에셋을 import 하는 경우, 이에 대한 Public URL이 반환된다.
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl
URL 쿼리를 이용해 에셋을 가져올 때 어떻게 이를 가져올 것인지 명시할 수도 있다.
URL로 에셋 가져오기
import assetAsURL from './asset.js?url'
String 타입으로 에셋 가져오기
import assetAsString from './shader.glsl?raw'
JSON 파일은 바로 Import가 가능하다.
객체 형태로 가져오기
import json from './example.json'
필드를 지정해 가져오기
import { field } from './example.json'
CSS 코드 분리
이번에 진행한 프로젝트에서 선임분께서 vite라는 번들링 툴을 사용한 것을 보고 어떠한 문제로 탄생하게 된 툴이며 어떤 해결책을 사용했는지 궁금하여 공식 가이드를 보며 정리해봤다.
어떤 문제가 있었고 그것을 해결하기 위해 어떤 방법을 사용했는지 아는 것은 늘 나를 설레게 한다.
비록 문제를 해결하기 위해 또 다른 문제가 생기기도 하고 해결해 나감으로 또 새롭게 알아야 할 것들이 너무나도 많아졌다지만, 우리는 언제나 그래왔듯 방법을 찾을 것이지 않은가?