vue-cli 프로젝트를 vite로 마이그레이션해보기

kdeun1·2022년 6월 20일
1
post-thumbnail

vue-cli로 구성된 프로젝트를 vite 환경으로 옮기는 작업이다.

1. vite 설치

1) 지원 Node 버전 확인

Vite는 EOL(End-of-life)에 도달한 Node v12를 더이상 지원하지 않는다. Node 버전 14.18+ 이상을 사용해야한다. node v14의 마지막 버전은 14.19.3 이므로 이 버전을 사용하기로 생각했다. 기존 프로젝트들이 node v12를 사용하는 경우도 존재하므로, nvm을 사용하여 다중 노드 환경을 구성해준다.

2) 최신 브라우저 기준 변경

프로덕션 버전으로 빌드 및 번들링 시 소스코드가 최신 JS를 지원하는 환경에서 동작한다고 가정하고 진행된다. 기본적으로 Vite는 Native ES Module, Native ESM의 동적 Import, import.meta를 지원하는 브라우저를 대상으로 하고 있다.

Chrome >= 87
Firefox >= 78
Safari >= 13
Edge >= 88

3) 설치

생성 명령어 사용

npm create vite@latest

Scaffolding Project

  • Project Name
  • Package Name
  • Select a framework : vue
  • Select a variant : vue-ts

4) 실행

npm install
npm run dev

정상적으로 프로젝트가 돌아가는 것을 확인한다.

5) package.json의 dependency 수정

package.json 파일에 필요한 라이브러리를 설치/삭제한다.

vue-cli에서 사용되었던 디펜던시를 삭제

  • @vue/cli-plugin-ㅁㅁㅁ 들을 삭제하였음
  • sass-loader 삭제하였음

디펜던시 최신화

  • vite로 설치된 vue 버전은 고정되어있음. vue 버전을 최신화한다.

모던 브라우저 지원으로 인한 디펜던시 수정

  • vue3버전을 사용하고 있으며, IE11 지원중단에 따라 프로젝트의 지원브라우저를 크롬으로 한정하는 스펙으로 정했음.
  • 트랜스파일링 관련 바벨 디펜던시인 babel-eslint, 폴리필 관련 디펜던시인 core-js 삭제

2. 마이그레이션 시작

0) 프로젝트 폴더, 파일들 복사

우선 폴더를 그대로 복붙한다. src/App.vue, src/main.ts 파일 내용도 복붙한다.

1) main.ts 파일 에러를 잡아보자

에러 1) alias인 '@' 에러 발생

(Javascript 관련)'@'와 같은 alias를 vite.config.js 파일에 세팅해준다.

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

export default defineConfig({
  resolve: {
    alias: [
      { find: '@', replacement: '/src' },
    ]
  },
  plugins: [vue()]
})

구글링하면 path를 사용해 path.resolve로 alias를 추가하는 방법이 많이 나온다. 하지만 기본적으로 위 코드처럼 alias를 지원해주기 때문에 불필요하게 path 라이브러리가 없어도 된다.

(Typescript 관련) IDE(webstorm)에서 alias를 인식해주기 위해 tsconfig.json 파일에 다음과 같이 추가한다.

baseUrl, paths 옵션을 추가한다.

{
  "compilerOptions": {
    // ...
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ],
    }
  },
  // ...
}

에러 2) TypeScript로 정의하지 않은 Javascript용 라이브러리를 사용할 때 발생하는 에러

TS 해결방법

2-1) @types/... 관련 라이브러리를 설치한다. 하지만 TS를 지원하지 않는다면 다음과 같이 해결한다.
2-2) // @ts-ignore 주석 사용하기. 이 방법도 임시방편인 것 같다.
2-3) d.ts 파일로 직접 모듈화하기.
vite 프로젝트를 생성하면 env.d.ts 파일이 존재한다.

declare module '라이브러리명';

위와 같이 라이브러리명을 선언해준다.

2) vite의 환경으로 변경해보자

환경 변수 변경

vue-cli에서 사용되었던 process.env.ㅁㅁㅁ 형태의 환경변수가 잡히지 않는다. vite에서도 .env 파일의 명명규칙이 유지된다. vue3 환경에서는 VUE_APP_* 접두사를 사용해서 환경변수를 선언하는데, VITE_* 로 변경되었으며 그에 따라 환경변수명도 변경한다.

대표적인 환경변수를 다음과 같이 변경한다. 프로젝트 전체 검색을 통해 변경한다.

  • process.env.BASE_URL -> import.meta.env.BASE_URL 로 변경
  • process.env.NODE_ENV -> import.meta.env.NODE_ENV 로 변경

.env 파일의 내용을 다음과 같이 변경한다.

  • VUE_APP_BASE_URL -> VITE_BASE_URL 로 변경

index.html 파일 위치가 변경

public 폴더 내부에 있는 index.html 파일의 위치가 프로젝트로 루트로 변경되었다. vite는 개발모드 시 esbuild를 사용하기 때문에 <script type="module" src="/src/main.ts"></script> 코드가 html 파일의 body 하단에 위치하게 된다.

생략 확장자 관련

resolve.extensions에 기본값은 ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']이다. .vue 확장자는 vue3에서도 생략하지 않도록 되어있으며, 기본 값을 그대로 유지해준다. 추후 필요한 확장자가 있는 경우 vite.config.js에 추가해준다.

webpackChunkName 제거

webpack 환경이 아니기 때문에 vue-router에서 사용되는 dynamic import의 webpackChunkName 코드를 제거한다.

3) sass 문제 수정

~ 제거(tilde 제거)

vite는 모던 브라우저만을 타깃으로 하기 때문에, 표준을 준수하도록 native css를 사용하도록 권고된다. 다시말해 CSS Pre-processors를 기본적으로 지원하지 않는다는 뜻이다. 다만 필요한 경우에는 어렵지 않게 설치해서 바로 사용할 수 있다.

# .scss and .sass
npm add -D sass

# .less
npm add -D less

# .styl and .stylus
npm add -D stylus

Vue SFC를 사용하는 경우 설치후 별다른 설정없이 <style lang="sass">와 같은 css 전처리기를 바로 사용할 수 있다. Sass나 Less에서의 @import aliasurl()도 사용가능하다.


위 이미지는 webpack의 sass-loader 공식문서 내용에 일부이다. ~를 사용하는 것은 deprecated되었으며, 코드에서 제거하는 것을 권장한다. 이미 구식 코드에서 사용 중이기 때문에 역사적인 이유(?) 때문에 호환성을 지원한다.


sass-loader의 change log중 일부이다. 11.0.0 버전이 되면서 위와 같은 내용이 적용된다.


프로젝트의 alias 중 가장 유명한 별칭은 at(@)이다. webpack 설정으로 @을 src 폴더를 가리키게 세팅해준다. tilde를 사용하는 ~@는 sass 구문에서 alias를 사용하기 위한 prefix이다. ~는 sass의 기능이 아니고 sass-loader에서 구현되는 기능이다. 그러므로 sass-loader의 문법을 수정해야한다. vite에는 sass의 package만 필요할 뿐 loader는 필요없다.

sass의 alias 세팅

~@에서 ~를 제거하는 방식으로 진행하려고 했다. 하지만 프로젝트 코드 중 모든 ~@를 제거하기에 너무 노가다스럽다는 생각을 하였다. 혹시 ~@를 sass의 alias로 세팅하면 *.scss 파일 내 코드를 수정없이 사용할 수 있지 않을까 생각하여 검색하게 되었다. vite > github > issue에서 검색한 내용을 힌트로 삼아 다음과 같은 코드로 해결하게 되었다.

export default defineConfig({
  resolve: {
    alias: [
      { find: '@', replacement: '/src' },
      { find: /^~@/, replacement: '/src' }
    ]
  },
  // ...
})

~@/src로 치환하는 alias로 설정하여 scss파일 내 url(~@/...) 코드를 정상적으로 읽을 수 있게 되었다.

vite 2.9.13의 bug fix내역

2.9.13 (2022-06-27)
fix: backport #8804, /@fs/ dir traversal with escaped chars (fixes #8498) (#8805) (e109d64), closes #8498 #8805
fix(wasm): support decoding data URL in Node < v16 (#8668) (1afc1c2), closes #8668

처음에는 { find: /^~/, replacement: '' }로 세팅하였으나 /@fs/ 버그가 생겨서 위 방식처럼 적용하였다. 하지만 vite v2.9.13이후에 패치된 내역과는 다르게 /^~/ 방식이 적용되지 않았다. 현재는 /^~@/ 방식을 사용하고 있다.

export default defineConfig({
  resolve: {
    alias: [
      { find: '@', replacement: '/src' },
      { find: /^~/, replacement: '' }
    ]
  },
  // ...
})

sass, css.preprocessorOptions 옵션

2)과정까지 적용하면 vite 서버는 정상적으로 작동한다. 하지만 실제 localhost:3000로 접속해보면 sass의 문제가 발생한다.

Undefined variable.                                                           
   ╷                                                                          
53 │     border-radius: $border-radius-base;                                  
   │                    ^^^^^^^^^^^^^^^^^^^                                   
   ╵    

vite.config.ts에 css.preprocessorOptions를 추가한다(참고 : https://vitejs.dev/config/#css-preprocessoroptions).

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

export default defineConfig({
  resolve: {
    alias: [
      { find: '@', replacement: '/src' },
    ]
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '@import "@/styles/main.scss";'
      }
    }
  },
  plugins: [vue()]
})

dev 환경에서 여러 개의 stylesheet 복사본이 중복되는 현상 발생


위와 같이 scss 옵션을 세팅하고나서 dev 환경에서 style에 대한 문제가 발생한다. 같은 스타일이 반복되게 중복되는 현상이 생기는데, 이 문제는 vite github > issue(https://github.com/vitejs/vite/issues/4448, https://github.com/vitejs/vite/issues/7504)에 올라와있는 이슈이다. 프로젝트 내 scss 파일에 대한 이해가 필요하다. 우선 vite.config.ts 파일의 css.preprocessorOptions.scss.additionalData에 대해 알아보자.

additionalData


additionalData 옵션은 다음과 같이 정의할 수 있다. (https://github.com/vitejs/vite/issues/4448#issuecomment-1110997673)

vite는 각각의 sass, scss, css import를 webpack과 동일한 방식으로 개별적으로 처리한다. 프로젝트 내 js, ts파일에서 import된 모든 sass, scss, css 파일 앞에 additionalData가 추가된다.

그러므로 모든 스타일 앞에 추가하는 역할을 하는 scss.additionalData 옵션에는 saas의 공통 variables(변수들), mixins(함수들)에 해당하는 scss파일을 추가한다.

// vite.config.ts
export default defineConfig({
  // ...
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '@import "@/styles/utils/index";'
      }
    }
  },
  // ...

그리고 나머지 공통 스타일은 main.ts파일에 추가한다.

// main.ts
import { createApp } from 'vue';
import App from '@/App.vue';
import router from '@/router';
import { store, key } from '@/store';
import '@/styles/main.scss';

const app = createApp(App);
// ...
app.mount('#app');

vite.config.ts의 additionalData 옵션과 main.ts에 공통 스타일 import를 통해 scss가 정상적으로 반영되는 것을 볼 수 있다.

4) proxy 설정

vite 환경에 Restful API를 위한 proxy 설정을 해준다. vite.config.ts 파일에 server.proxy의 값을 추가해준다.

export default defineConfig({
  // ...
  server: {
    proxy: {
      '/api/v1': {
        target: 'http://0000.0000.000/',
      },
      '/api/v2': {
        target: 'http://0000.0000.000/',
      },
    },
  },
  // ...
})

참고

profile
프론트엔드 개발자입니다.

0개의 댓글