Vite의 공략대상이 되어버렸습니다.

RISTRETTO·2024년 7월 30일
0

프론트엔드

목록 보기
3/3

Vite가 무엇인가요?

Vite는 프랑스어로 "빠르다(Quick)" 를 의미하며, 발음은 "veet"와 비슷한 /vit/ 입니다. 빠르고 간결한 모던 웹 프로젝트 개발 경험에 초점을 맞춰 탄생한 빌드 도구입니다.

Vite는 esbuild와 roleup을 사용해서 cra에서 사용하는 webpack보다 빠른 빌드 속도를 자랑하는데요!

Vite에 대해 본격적으로 알아보기 전에 번들러가 무엇인지에 대해 다시 개념을 잡고가는게 좋을 것 같습니다.

모듈 등장 이유

<script> 태그로 연결하는 방식 → 전역 오염이나 의존성 관리가 어려웠음 → 모듈 시스템의 등장.

근데 여기서 → 모듈 시스템이 뭔데?

모듈시스템이란?
외부에서 사용할 수 있게 특정 함수나 오브젝트 등을 모듈화 하고,
해당 모듈을 사용하려는 쪽에서는 필요한 모듈만 불러 와서 사용하게하는 시스템

간단하게 우리가 지금 import export 하고 있는 그것들을 가능하게 하는것을 말합니다.

번들러 등장 이유

이러한 모듈 시스템을 관리하기 위해 번들러 등장.

번들러란?

번들러(Bundler)는 웹 애플리케이션을 개발하기 위해 필요한 HTML, CSS, JS 등의 파편화된(모듈화된) 자원들을 모아서, 하나 혹은 최적의 소수 파일로 결합(번들링)하는 도구입니다.

결국, 현대의 번들러는 개발자의 작업 효율성을 높이고 브라우저의 호환성이나 성능 등을 개선하는데 크게 도움을 줍니다.

번들러 비교

📌 webpack

장점

  • 오랫동안 사용되어 다양한 레퍼런스 등 생태계가 풍부하고 안정성이 뛰어나다.
  • 특히, 서드파티 라이브러리 관리나 CSS 전처리, 이미지 에셋 관리에 있어 다른 번들러보다 강점을 보인다.
  • 코드 스플리팅이 활성화된 단계에서 빌드 시간이 Rollup, Parcel과 비교했을 때 웹팩이 가장 빠르다.
    • 초기에 구동될 필요가 없는 코드를 분리하여 lazy loading을 통해 페이지 초기 로딩속도를 개선할 수 있다.
  • 개발 중에 변경사항을 자동으로 새로고침 해주는 라이브 리로딩 기능, 새로고침 없이 런타임에 브라우저의 모듈을 업데이트 하는 핫 모듈 교체(HMR) 등 개발 서버가 다른 번들러에 비해 뛰어나다.
    • Rollup과 Parcel은 플러그인을 설치하면 되긴 하지만 설정을 추가해주고, 특정 상황에서는 동작하지 않는 경우가 있다.

단점

  • 웹팩은 웹 애플리케이션에서 사용하는 CSS나 이미지 같은 에셋들을 JavaScript 코드로 변환하고, 이를 분석해서 번들하는 방식을 사용한다. 그렇기 때문에 다른 번들러에 비해 웹팩의 구성은 설정할 게 많고 많이 복잡한 편이다.
  • 코드 스플리팅에 있어선 Rollup과 Parcel이 성능적으로 더 뛰어나다. (하지만 활성화 단계에서는 Webpack이 뛰어남)
  • 자바스크립트가 아닌 파일들은 로더(번들 되기 전 파일 단위를 처리)나 플러그인(번들된 결과물을 추가로 후처리) 등으로 변경해주어야 한다.
  • 트리 쉐이킹이 지원되기는 하지만 CommonJs 방식으로 모듈을 로드한 부분을 ES6 문법으로 교체해야 하고 Terser 등 별도의 플러그를 설치해야 한다.
  • ES6 모듈 형태로 빌드 결과물을 출력할 수 없다.
  • 복잡한 문서가 진입장벽을 높인다.
  • 퍼포먼스 문제로 하여 수십 초 이상 걸리던 개발 서버 구동을 1초 이하로 단축하는 등 사례가 보인다. (하지만, Vite로 마이그레이션했다가 빌드가 안정적이지 않아 골치를 앓았다는 포스팅도 보인다.)

📌 Rollup

장점

  • ES6 모듈 형식으로 빌드 결과물을 생성할 수 있는 번들러 입니다.
    • 라이브러리나 패키지에 활용하기 유리하다.
  • 자체 로더가 아닌 ES6 사용
    • 롤업은 명시적 import , export를 사용하기 때문에 컴파일된 출력 코드에서 트리 쉐이킹을 하여 최소한의 것들만 번들링 할 수 있습니다.
  • 코드를 동일한 수준으로 올리고(Scope Hoisting) 한 번에 번들링 합니다.
    • 한 번에 하기때문에 속도는 웹팩보다 빠르고 번들링 결과물도 가볍습니다. 그러나 변수 충돌에 있어서는 웹팩보다 덜 안정적입니다.
  • 진입점을 다르게 설정하여 번들링 가능합니다.
    • 진입점이 다르기 때문에 중복해서 번들링될 수 있는 부분을 알아내고, 독립된 모듈로 분리가 가능합니다. 따라서 코드 스플리팅 측면에서 다른 번들러와 비교해 강점을 보입니다.

단점

  • input, output 이 많아질수록 복잡해질 수 있습니다. (롤업은 다른 번들러와 비교했을때 중복 제거에 특화되어 있기때문에 진입점이 여러개 있을 때 이 부분이 두드러집니다. 하지만 너무 많아지면 설정이 복잡해지겠죠.)
  • 트랜스파일을 하기 위해 플러그인을 사용해야 합니다.

📌 ESbuild

장점

  • 내부적으로 JavaScript로 작성된 다른 번들러와 달리(Webpack) ESBuild는 Go로 작성되었고, JS 기반의 번들러보다 10배~100배 빠른 퍼포먼스를 보여준다.
    • JavaScript는 인터프리터 언어이기 때문에 한줄씩 기계어로 변환하지만(+싱글 스레드), Go는 컴파일 단계에서 미리 소스 코드를 기계어로 변환해둔다.(+멀티 스레드)
    • 네이티브 코드 방식 사용, 병력처리 최적화, 메모리 사용 최적화 등

단점

  • 메이저 버전이 릴리즈되지 않았다.
  • 설정이 wepack 등 처럼 유연하지 못하고 안전성 관련 이슈가 있다. (es5이하 문법을 100% 지원하지 않는 등)
  • 빌드만 할 수 있는 도구로 트랜스파일링, 코드 스플리팅, HMR 등 여러 기능을 종합적으로 제공해주는 webpack같은 도구가 여전히 필요하다.

📌 parcel

장점

  • Parcel은 Webpack과 달리 애플리케이션 진입을 위한 HTML 파일 자체를 읽기 때문에 별도의 설정 파일 없이, 설치만 하면 별도의 설정 파일 없이 빌드 명령어를 입력해 바로 사용이 가능하다. (Webpack은 에셋을 읽기 위해 JavaScript로 변환하기 위한 플러그인과 로더 등을 깔아야 함)
  • ES6 및 CommonJS 모듈 모두에 대해 트리 쉐이킹을 지원한다.
  • 트랜스파일에 대한 기본 제공을 지원하여 트랜스파일러도 간편하게 설정할 수 있다.
    • Webpack과 Rollup은 트랜스파일에 필요한 파일 유형을 일일이 설정해야 한다.
    • Parcel은 .babelrc, posthtml 등 설정파일들을 프로젝트 루트 디렉토리에 만들기만 하면 자동으로 파일을 읽어와 세팅을 해준다.
    • 사용자가 설정한 트랜스파일 외에도 모든 모듈에서 Babel을 사용하여 최신 JavaScript를 브라우저에서 지원하는 형식으로 컴파일한다.

단점

  • Webpack에 비해 생태계가 좁고 안정적이지 않다. (깃헙의 이슈)
  • 공식 문서가 잘 작성되어 있지만, 커스텀한 설정이 필요하다면 설정 파일을 다시 작성해야 한다.

그래서 Vite 왜 써야하는건데?

npmtrends 에서도 확인가능 하듯이 2020년에 나온 vite의 다운로드 수가 2012년에 나온 webpack을 따라잡고있음.

인기와 커뮤니티 지원을 측정하는 star-history를 사용하여 GitHub 스타를 살펴보면 vite는 webpack에 필적한다.

지루할 정도로 길었던 서버 구동

vite는 애플리케이션의 모듈을 dependencies와 source code 두 가지 카테고리로 나누어 개발 서버의 시작 시간을 개선합니다.

  • Dependencies: 개발 시 그 내용이 바뀌지 않을 일반적인(Plain) JavaScript 소스 코드입니다. 기존 번들러로는 컴포넌트 라이브러리와 같이 몇 백 개의 JavaScript 모듈을 갖고 있는 매우 큰 디펜던시에 대한 번들링 과정이 매우 비효율적이었고 많은 시간을 필요로 했습니다. Vite의 사전 번들링 기능은 Esbuild를 사용하고 있습니다. Go로 작성된 Esbuild는 Webpack, Parcel과 같은 기존의 번들러 대비 10-100배 빠른 속도를 제공합니다.
  • Source code: JSX, CSS 또는 Vue/Svelte 컴포넌트와 같이 컴파일링이 필요하고, 수정 또한 매우 잦은 Non-plain JavaScript 소스 코드는 어떻게 할까요? (물론 이들 역시 특정 시점에서 모두 불러올 필요는 없습니다.

느렸던 소스 코드 갱신

기존의 번들러 기반으로 개발을 진행할 때, 소스 코드를 업데이트 하게 되면 번들링 과정을 다시 거쳐야 했었습니다. 따라서 서비스가 커질수록 소스 코드 갱신 시간 또한 선형적으로 증가하게 됩니다.

일부 번들러는 메모리에서 작업을 수행하여 실제로 갱신에 영향을 받는 파일들만을 새롭게 번들링하도록 했지만, 결국 처음에는 모든 파일에 대한 번들링을 수행해야 했습니다. "모든 파일"을 번들링 하고, 이를 다시 웹 페이지에서 불러오는 것이 얼마나 비효율적인 것인지 느껴지시나요? 이러한 이슈를 우회하고자 HMR(Hot Module Replacement) 이라는 대안이 나왔으나, 이 역시 명확한 해답은 아니었습니다.

물론, vite는 HMR을 지원합니다. 이는 번들러가 아닌 ESM을 이용하는 것입니다. 어떤 모듈이 수정되면 vite는 그저 수정된 모듈과 관련된 부분만을 교체할 뿐이고, 브라우저에서 해당 모듈을 요청하면 교체된 모듈을 전달할 뿐입니다. 전 과정에서 완벽하게 ESM을 이용하기에, 앱 사이즈가 커져도 HMR을 포함한 갱신 시간에는 영향을 끼치지 않습니다.

또한 vite는 HTTP 헤더를 활용하여 전체 페이지의 로드 속도를 높입니다. 필요에 따라 소스 코드는 304 Not Modified로, 디펜던시는 Cache-Control: max-age=31536000,immutable을 이용해 캐시됩니다. 이렇게 함으로써 요청 횟수를 최소화하여 페이지 로딩을 빠르게 만들어 줍니다.

이렇게나 빠른 Vite를 사용하지 않을 이유가 있나요?

배포 시 번들링 과정이 필요한 이유

이제 기본적으로 ESM이 대부분의 환경에서 지원되지만, 프로덕션에서 번들 되지 않은 ESM을 가져오는 것은 중첩된 import로 인한 추가 네트워크 통신으로 인해 여전히 비효율적입니다(HTTP/2를 사용하더라도). 프로덕션 환경에서 최적의 로딩 성능을 얻으려면 트리 셰이킹, 지연 로딩 및 청크 파일 분할(더 나은 캐싱을 위해)을 이용하여 번들링 하는 것이 더 좋습니다.

개발 서버와 프로덕션 빌드 간에 최적의 출력과 동작 일관성을 보장하는 것은 쉽지 않습니다. 이것이 바로 Vite가 미리 설정된 빌드 커맨드를 이용하고, 빌드 퍼포먼스 최적화를 진행하는 이유입니다.

출처 : https://ko.vitejs.dev/guide/why.html

Vite vs Webpack

vite의 간소화된 구성

vite 설정

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
})

webpack 설정

const webpack = require('webpack');
const path = require('path');
const { HotModuleReplacementPlugin } = require('webpack');
const { VueLoaderPlugin } = require('vue-loader');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, './build'),
        filename: 'bundle.js',
    },
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                    },
                },
            },
            {
                test: /.vue$/,
                use: {
                    loader: 'vue-loader',
                },
            },
            {
                test: /.css$/,
                use: ['vue-style-loader', 'css-loader'],
            },
        ],
    },
    resolve: {
        alias: {
            vue: 'vue/dist/vue.js',
        },
    },
    plugins: [
    new HotModuleReplacementPlugin(),
    new VueLoaderPlugin(),
    ]
};

Vite와 비교할 때 Webpack의 구성에는 수동 설정이 더 많이 포함.

개발서버

서버 구성

Vite는 기본 제공되는 즉시 사용 가능한 개발 서버로 눈에 띄며 종종 광범위한 구성이 필요하지 않습니다.

이와 대조적으로 Webpack은 유연성을 제공하지만 추가 설정이 필요합니다. 개발자는 Webpack의 Watch Mode , webpack-dev-server및 webpack-dev-middleware변경 시 자동 코드 컴파일과 같은 옵션을 선택할 수 있습니다. 그러나 일반적으로 이러한 옵션을 설정하고 세부 조정하려면 구성이 필요합니다.

콜드 스타트 속도

기존 번들러 기반 설정에는 적극적인 크롤링이 포함되며 서비스를 제공하기 전에 전체 애플리케이션을 구축해야 하므로 특히 복잡한 프로젝트에서 눈에 띄는 지연이 발생합니다.

Vite는 근본적으로 다른 접근 방식으로 콜드 스타트에 혁명을 일으켜 초기화 시간을 획기적으로 단축합니다.

효율적인 종속성 처리 : Vite는 고성능 Go 기반 번들러인 esbuild를 활용하여 일반 JavaScript 및 대규모 모듈을 포함한 종속성을 사전 번들링합니다. 예를 들어 lodash-es 에는 600개가 넘는 내부 모듈이 포함되어 있습니다. 전통적인 방법을 사용하고 와 같은 함수를 가져올 때 600개 이상의 HTTP 요청이 트리거됩니다. Vite의 솔루션은 단일 모듈로 사전 번들링하여 HTTP 요청을 하나로 줄이는 것입니다. 이렇게 요청이 크게 줄어들면 개발 서버의 페이지 로드 속도가 크게 향상됩니다.

ESM 기반 개발서버

주문형 소스 코드 로딩: Vite는 기본 ES 모듈을 활용하여 소스 코드를 제공하고 서버 로드 및 대기 시간을 최소화합니다. 브라우저 요청 시 소스 코드 변환 및 제공이 이루어지므로 효율성이 향상되고 대기 시간이 단축됩니다.

번들 기반 개발서버

반면 Webpack은 번들 기반 접근 방식을 채택하여 소스 코드와 종속성을 사전 번들링하여 개발 중에 서버 시작 시간을 연장합니다. Vite의 효율적인 초기화에 비해 Webpack의 서버 설정 시간은 본질적으로 더 깁니다.

그러나 Vite의 주문형 로딩 접근 방식은 사용자가 추가 데이터, CSS 및 자산이 필요한 경로로 이동할 때 약간의 지연을 초래할 수 있습니다. 이는 이러한 리소스가 추가 번들링 단계를 요구하는 경우 특히 두드러집니다. 반대로 Webpack의 전략은 모든 사이트 데이터를 사용할 수 있도록 보장하여 개발 서버 내의 새 페이지로의 브라우저 탐색을 더욱 빠르게 만듭니다.

HMR(핫 모듈 교체)

Vite는 기본 ESM을 통해 HMR을 사용하여 일부 번들링 작업을 브라우저로 오프로드하여 서버 로드와 대기 시간을 줄입니다. 이는 전체 페이지를 다시 로드하지 않고도 빠른 업데이트를 보장하며, 이는 개발 중 실시간 피드백에 매우 중요합니다.

Webpack은 또한 HMR을 지원하여 실시간 업데이트를 가능하게 하고 개발 중에 애플리케이션 상태를 보존합니다. 그러나 기본 ES 모듈을 활용하는 데 있어 잠재적인 제한으로 인해 서버 로드 및 대기 시간이 높아질 수 있습니다.

캐싱 성능

캐싱은 저장된 자산을 재사용하여 웹 애플리케이션 성능을 향상하고 로드 및 빌드 시간을 줄이는 데 필수적입니다.

Vite의 캐싱은 파일 시스템 캐시 로 관리되며 package.json , lockfiles 및 vite.config.js 의 변경 사항에 따라 종속성을 업데이트합니다 . 해결된 종속성 요청을 캐시하여 페이지 다시 로드를 최적화합니다.

Webpack은 파일 시스템 캐싱 도 사용하여 감시 모드에서 수정된 파일을 지우고 비감시 모드에서 각 컴파일 전에 캐시를 제거하므로 최적의 캐싱을 위한 사용자 정의 구성이 필요합니다.

개발 서버 비교를 마무리하기 위해 Vite와 Webpack은 개발 서버에 대한 고유한 접근 방식을 제공합니다.

  • Vite는 즉시 사용 가능한 개발 서버를 제공하여 구성 오버헤드를 최소화합니다.
  • Webpack은 구성 유연성을 제공하지만 추가 설정이 필요합니다.
  • Vite는 콜드 스타트 속도와 빠른 코드 변경을 위한 HMR에 탁월합니다.
  • Webpack은 사전 번들로 제공되는 사이트 데이터로 인해 브라우저 탐색 속도가 더 향상됩니다.
  • 둘 다 HMR을 지원하지만 모듈 제공 메커니즘이 다릅니다.
  • Vite는 로컬 및 브라우저 캐싱을 원활하게 관리하는 반면 Webpack은 사용자 정의 구성이 필요합니다.

빌드 시간 및 번들 크기

테스트 환경에는 다음이 포함됩니다.

  • Apple M1 칩과 8코어 GPU를 탑재한 MacBook Air에서 테스트를 실행합니다.
  • 상태 관리를 위해 Vuex를 사용하고 라우팅을 위해 Vue Router를 활용하는 10개의 구성 요소로 구성된 중간 규모의 Vue 3 프로젝트입니다.
  • 적당한 수의 종속성과 함께 스타일시트(CSS/SASS), 이미지와 같은 자산, 글꼴을 통합합니다.

번들링 시간을 비교하는 것부터 시작해 보겠습니다.

Vite [v4.4.11]웹팩 [v5.89.0]
개발 첫 빌드376ms6초
핫체인지즉각적인1.5초
프로덕션 빌드2초11초

Vite는 번들링 속도의 확실한 승자로 등장하여 빌드 시간을 대폭 단축합니다. Webpack은 구성 가능성과 강력한 개발 도구를 제공하지만 Vite에 비해 뒤떨어집니다.

Vite v4.4.11웹팩 v5.89.0
제품 번들 크기866kb934kb

이 수치는 중간 정도의 종속성이 있는 중간 크기의 Vue.js 애플리케이션을 기반으로 합니다. 실제 번들 크기는 프로젝트 복잡성, 종속성 및 최적화 기술에 따라 달라질 수 있습니다.

Vite의 작은 번들 크기는 esbuild 및 기본 ES 모듈과의 효율적인 사전 번들링 때문입니다.

Webpack의 번들 크기는 다양한 구성 옵션과 플러그인을 통해 최적화될 수 있지만 일반적으로 포괄적인 번들링 프로세스로 인해 더 큰 번들을 생성합니다.

코드 분할 및 청크 로딩

코드 분할은 코드를 더 작고 관리하기 쉬운 조각으로 나누어 필요할 때 정확하게 필요한 부분만 로드하는 데 사용되는 기본 기술입니다. 이렇게 하면 초기 로드 시간이 크게 줄어들고 리소스가 절약됩니다.

청킹에 대한 Vite의 접근 방식

Vite가 Rollup을 사용하여 코드를 동적 로딩이나 다중 진입점과 같이 자동으로 별도의 청크로 분할하는 경우가 있으며,output.manualChunks 옵션을 통해 Rollup에 어떤 모듈을 별도의 청크로 분할할지 명시적으로 알려주는 방법이 있습니다 .

Vite의 사전 구성된 코드 분할 기능 외에도 Vite는 변수를 사용한 동적 가져오기도 지원합니다 .

const module = await import(`./dir/${kinsta}.js`)

Vite를 사용하면 개발자는 공식을 사용하여 공급업체 청크를 분할할 수도 있습니다 splitVendorChunkPlugin().

import { splitVendorChunkPlugin } from 'vite'
export default defineConfig({
  plugins: [splitVendorChunkPlugin()],
})

모든 동적 가져오기 및 코드 분할로 인해 코드가 모듈 또는 청크로 구조화되는 것이 일반적이며 이러한 모듈 중 일부는 웹 애플리케이션의 여러 부분 간에 공유됩니다. Vite는 일반적인 청크를 인식하고 로딩 프로세스를 최적화합니다. 이를 더 잘 이해하기 위해 Vite 공식 문서 의 예를 살펴보겠습니다.

두 개의 비동기 청크에 필요한 공통 청크를 표시하는 그래프입니다. (이미지 출처 : VITE )

최적화 없이 사용자가 웹 애플리케이션의 섹션(공유 코드 Common Chunk C 를 사용하는 섹션 A 라고 함 )을 열면 브라우저는 섹션 A를 가져오는 것으로 시작합니다 . 섹션 A를 구문 분석하는 동안 Common Chunk C 가 필요하다는 것을 깨닫습니다 . 이를 위해서는 추가 네트워크 왕복이 필요하며 이로 인해 초기 페이지 로드 속도가 느려질 수 있습니다.

Entry (Section A) ---> async chunk A ---> common chunk C

반면에 Vite는 Async Chunk Loading Optimization 이라는 정교한 기능을 사용합니다 . 브라우저가 요구 사항을 발견할 때까지 기다리지 않습니다. 대신 적극적으로 대비합니다. 사용자가 섹션 A를 요청하면 Vite는 섹션 A 와 공통 청크 C를 동시에 보냅니다 . 필요한 청크를 병렬로 가져오면 로딩 프로세스 속도가 크게 향상됩니다.

Entry (Section A) ---> (async chunk A + common chunk C)

그러나 여기서 끝나지 않습니다. 공통 청크 C에는 자체 종속성이 있어 최적화되지 않은 시나리오에서 잠재적으로 추가 왕복이 발생할 수 있습니다. Vite는 이 측면을 간과하지 않습니다. 이러한 종속성을 엄격하게 분석하여 깊이에 관계없이 필요한 모든 것이 한 번에 효율적으로 로드되도록 합니다. 이는 추가 네트워크 왕복의 필요성을 없애고 응답성이 뛰어난 웹 애플리케이션을 보장합니다.

Vite의 비동기 청크 로딩 접근 방식은 필요한 모든 코드 청크를 병렬로 사전에 가져오고 제공함으로써 로딩 프로세스를 최적화합니다. 추가 네트워크 왕복을 제거하면 더 빠른 웹 경험이 가능해집니다. 이는 브라우저에 잘 준비된 여행 일정을 제공하여 불필요한 지연 없이 필요한 모든 리소스를 수신하도록 하는 것과 유사합니다.

코드 분할에 대한 Webpack의 접근 방식

Webpack의 경우 코드 분할에 사용할 수 있는 세 가지 일반적인 기술이 있습니다.

  1. 진입점:

    이는 코드 조각을 분할하는 가장 쉬운 방법입니다. 구성 파일과 Webpack에 새 진입점을 정의하고 이를 별도의 청크로 추가할 수 있습니다.

    const path = require('path');
     module.exports = {
      mode: 'development',
      entry: {
        index: './src/index.js',
        another: './src/separate-module.js',
      },
       output: {
        filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist'),
       },
     };

    그러나 이 접근 방식에는 한계가 있습니다. 모듈을 다른 항목 청크로 가져오면 두 번들 모두에 포함되어 코드가 중복됩니다. 또한 필요할 때 핵심 애플리케이션 논리를 분할하는 데 적합하지 않습니다.

  2. 중복 방지entry[SplitChunksPlugin](https://webpack.js.org/plugins/split-chunks-plugin/)entry

    : 또 다른 접근 방식은

    종속성을 사용하거나

    청크를 분할하여 중복성을 줄이는 데 도움이 됩니다. 다음은 종속성을 사용하여 코드 분할을 구성할 수 있는 방법의 예입니다

    .

    const path = require('path');
     module.exports = {
       mode: 'development',
       entry: {
         index: {
           import: './src/index.js',
           dependOn: 'shared',
         },
         another: {
           import: './src/another-module.js',
           dependOn: 'shared',
         },
         shared: 'lodash',
       },
       output: {
         filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist'),
       },
      optimization: {
        runtimeChunk: 'single',
      },
     };
  3. 동적 가져오기

    : 마지막으로 Webpack은 주문형 코드 로딩에 유용한 기능인

    동적 가져오기에 대한 ECMAScript 제안을 따르는 구문을 사용합니다. 이 방법은 더욱 유연하고 세분화되어 다양한 코드 분할 시나리오에 적합합니다.

    const { default: _ } = await import('lodash');

    또한 Webpack의 Magic Comments를 사용하여 청크의 이름을 설정하고, 지연 로드하고, 모듈 내보내기를 지정하고, 가져오기 우선순위를 설정할 수 있습니다.

    import(
      /* webpackChunkName: "my-chunk-name" */
      /* webpackMode: "lazy" */
      /* webpackExports: ["default", "named"] */
      /* webpackFetchPriority: "high" */
      'module'
    );

트리 쉐이킹

트리 쉐이킹은 Vite와 Webpack 모두 JavaScript 번들의 크기를 줄이기 위해 사용하는 중요한 최적화 기술입니다.

Vite는 ES 모듈을 사용할 수 있을 뿐만 아니라 가져온 코드를 정적으로 분석하는 롤업을 활용합니다. 이는 Vite가 사용하지 않는 모듈의 모든 부분을 제외하여 번들 크기를 더 작게 만들 수 있음을 의미합니다. 예를 들어, 여러 기능이 있는 모듈이 있지만 그 중 하나만 사용하는 경우 Vite는 해당 기능만 번들에 포함합니다. 간단한 예는 다음과 같습니다.

  • ES 모듈을 사용하지 않고 ./utils.jsajax 에서 가져오려면 전체 파일을 가져와야 합니다.
    const utils = require('./utils');
    const query = 'Kinsta';
    // Use the 'ajax' method of the 'utils' object
    utils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);
  • 반면에 ES 모듈을 사용하면 필요한 것만 가져올 수 있으므로 더 가볍고 빠르며 덜 복잡한 라이브러리와 애플리케이션을 얻을 수 있습니다. importexport Vite는 명시적 및 명령문을 사용하므로 사용되지 않는 코드를 감지하기 위해 자동화된 축소기에만 의존하지 않고도 매우 효과적인 트리 쉐이킹을 수행할 수 있습니다.
    import { ajax } from './utils';
    const query = 'Kinsta';
    // Call the 'ajax' function
    ajax(`https://api.example.com?search=${query}`).then(handleResponse);

마지막으로 Vite의 경우 트리 쉐이킹을 위해 Rollup의 사전 구성된 옵션을 사용할 수 있습니다 .

Webpack은 트리 쉐이킹도 지원하지만 메커니즘이 다릅니다 . 코드의 종속성을 분석하고 번들링 프로세스 중에 사용되지 않는 부분을 제거합니다. 효과적이긴 하지만 특히 대규모 모듈이나 라이브러리를 처리할 때 Vite의 접근 방식만큼 철저하지 않을 수 있습니다.

또한 Webpack의 문서 에 따르면 . 프로덕션 환경에서 해당 파일에 의존하는 다른 코드가 있는 코드가 제거되지 않도록 파일을 부작용 없음 으로 표시해야 합니다 .

이를 수행하는 방법은 sideEffects package.json 속성입니다.

{
  "name": "kinsta-app",
  "sideEffects": false
}

부작용을 정의하는 유사한 구성 옵션이 Vite의 롤업 옵션에도 존재한다는 점은 주목할 가치가 있습니다.

출처 : https://kinsta.com/blog/vite-vs-webpack/


아 3줄 요약은요?

Vite는...
1. 빠른 빌드! 빠른 ES Build 사용
2. 라이브러리 설치 직후 미리 bundle을 만들어 놓음
3. 소스코드 변경 시 필요한 것만 수정.

모듈 시스템 : https://www.youdad.kr/js-module-system/
마이그레이션 후기 : https://blog.seiker.kr/vite-migration-from-create-react-app/
마이그레이션 후기 2 : https://programmerplum.tistory.com/189

결국 vite 사용하는 이유는 ES build 이용하여 사전 번들링으로 빠른 빌드 가능, 개발서버 페이지 로드 속도 향상, 소스 코드 변경시 필요한 것만 수정이 가능. Vite의 단점은 브라우저가 ESM을 지원하지 않는 경우 위의 장점을 활용할 수 없다는 것이다.위의 단점은 IE의 지원 종료로 인해 해결되었다.


cra → vite 마이그레이션 해보기.

발표 중간에 런칭되어 있는 실무 React 프로젝트를 가져와서 직접 마이그레이션 해보았습니다. Cra에서 Vite로 넘어가는 것은 어렵지 않고, 생각보다 간단한 작업입니다.

1. 의존성 교체

yarn remove react-scripts @craco/craco webpack

  • react-scripts, webpack, craco 의존성을 삭제합니다

yarn add vite @vitejs/plugin-react vite-tsconfig-paths vite-plugin-svgr

  • @vitejs/plugin-react : react를 위한 vite
  • vite-tsconfig-paths : ts path 설정을 위한 vite-tsconfig-paths
  • vite-plugin-svgr : svg를 컴포넌트로 사용하기 위한 패키지

2. 실행 스크립트 추가

"start": "vite",
"build": "tsc && vite build",

3. index.html

  1. public / index.html은 프로젝트 root에 위치합니다.
  2. body의 하단에 index.tsx를 import 해줍니다.
    <script type="module" src="/src/index.tsx"></script>

4. config

  1. webpack.config.js 대신에 vite.config.js를 사용합니다.
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';
import vitePluginSvgr from 'vite-plugin-svgr';

export default defineConfig({
  base: '',
  plugins: [react(), viteTsconfigPaths(), vitePluginSvgr()],
  server: {
    open: true,
    port: 3000,
  },
});

5. 환경변수

  1. process.env.* 대신에 import.meta.env.* 를 사용합니다
  2. 환경변수의 변수명은 REACT_APP_* 대신에 VITE_APP_*를 사용합니다.

6. tsconfig.json

  1. 컴파일러 옵션을 추가합니다.
"target": "ESNext",
"types": ["vite/client"],

7. vite-env.d.ts (option)

<reference types="vite/client" />

8. 참고 사항

  1. Storybook, Jest등 path를 사용하는 라이브러리를 사용 중이라면, 다시 path를 잡아주어야 합니다.
  2. package.json에 local file 의존성이 있다면, 다시 핸들링해줘야합니다.

용어 설명

ESM Native : ESM은 모듈화 문법인 importexport를 별도의 도구 없이 브라우저 자체에서 소화해 낼 수 있는 모듈 방식을 의미합니다. 만약 아래와 같은 코드를 웹팩과 같은 번들러 없이 브라우저에서 실행하면 에러가 발생합니다.

Tree Shaking : 임포트 되었지만 실제로는 사용되지 않는 코드를 분석하고 삭제하는 코드 최적화 기술.

Cold Start : 콜드 스타트는 최초로 실행되어 이전에 캐싱한 데이터가 없는 경우를 의미합니다.

Chunk : 하나의 번들 파일을 효과적으로 다루기 위해 여러가지의 파일로 다시 나누는 것

Crawling : 크롤링(crawling) 은 웹 페이지를 그대로 가져와서 거기서 데이터를 추출해 내는 행위다.


※ 해당 포스팅은, 상업적인 용도가 아닌 학습을 위한 내용입니다.
자료출처가 빠진 부분이 있을 수 있습니다. 코멘트 남겨주시면 추가하도록 하겠습니다.


profile
빛나는 개발자

0개의 댓글