🚀

vue-cliをviteに移行する

2021/11/11に公開
3

viteとは一言で言うとめちゃくちゃ早いビルドツールです。
ビルドを超高速化することで開発時の生産性を大幅に向上させてくれます。

vite自体についての詳しい説明は本家を見ていただくとして、この記事ではvue-cliで開発しているプロジェクトをviteに移行する方法についてご紹介します。

実際どのくらい早くなるのかが気になるかと思うので、自分のプロジェクトで体感どのくらい早くなったかをご紹介します。
ちょっとわかりにくいですが、3秒くらい待ってたのが0.5秒くらいになっています。

導入前
before

導入後
after

スムーズにいけば1時間程度で導入でき、開発者全員が1日数百回ビルドすることを考えるとやって損はないと思います。(何よりビルドが早いと開発が楽しくなりますしね😆)
では行ってみましょう!

バージョン情報
Vue 3.2.20(※Vue2でも基本的に同じ方法で移行できますが検証は行っていません🙏)
vite: 2.6.14

単純なプロジェクトで移行を試してみる

いきなり本プロジェクトに導入するとハマって辛くなるのが目に見えてるので、まずは単純なプロジェクトで移行してみます。
基本的な移行方法を理解することで、自信を持って本プロジェクトに導入するとができ、結果的に時短になるのでおすすめです。
(急いでるのでいきなり本プロジェクトで試したい方はスキップしてください。)

1. サンプルプロジェクトの作成

  1. まずはプロジェクトの雛形を作ります。tsを使いたいので、Manually select features を選択します。
~/g/g/k/L/vite (master ⚡☡+) vue create hello-world
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a linter / formatter config: Prettier
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

こんな感じのシンプルなプロジェクトができました!
念の為vue-cliで起動することを確認しておきます。

yarn run serve
DONE  Compiled successfully in 2391ms                                                                                                                                                                                                                                                                      17:12:58
App running at:
- Local:   http://localhost:8080/ 
- Network: http://192.168.1.7:8080/

Note that the development build is not optimized.
To create a production build, run yarn build.

vue-app

2. viteのインストール

  1. viteをインストールして、cli-serviceを削除します。
yarn add -D vite @vitejs/plugin-vue
yarn remove @vue/cli-plugin-babel @vue/cli-plugin-eslint @vue/cli-service
  1. serveコマンドをviteに差し替えます。
"scripts": {
  "serve": "vite",
  "build": "vite build",
  "lint": "eslint src"
},

3. index.htmlの修正

  1. 続いて index.htmlをルートディレクトリに移動させます。viteではルートフォルダにあるindex.htmlをエントリポイントとするためです。

public/index.htmlindex.html

  1. 移動させたindex.htmlにエントリーポイントとなる<script>タグを追加します。合わせてBASE_URLも削除します。
index.html
...
-<link rel="icon" href="<%= BASE_URL %>favicon.ico">
+<link rel="icon" href="/favicon.ico">
...
<div id="app"></div>
+ <script type="module" src="/src/main.js"></script>

4. vite.config.jsの設定

viteが.vue ファイルを扱えるように、vite.config.js@vitejs/plugin-vue の設定を追加します。

// vite.config.js
import vue from '@vitejs/plugin-vue'

export default {
  plugins: [vue()],
  server: {
    port: 8080,
  }
}

以上でシンプルなプロジェクトでの移行が完了しました🎉

(ビルドが早くなりましたね🚀)

~/g/g/k/migrate-to-vite (master ⚡) yarn serve
yarn run v1.22.15
$ vite
Pre-bundling dependencies:
  vue
(this will be run only when your dependencies or config have changed)

  vite v2.6.14 dev server running at:

  > Local: http://localhost:8080/
  > Network: use `--host` to expose

  ready in 235ms.

いざプロジェクトに導入

ではいよいよ本プロジェクトに導入していきましょう!

1. viteのインストール

はじめにviteをインストールします。

yarn add -D vite @vitejs/plugin-vue

2. vue-cli関連のpackageを削除

@vue/cli-xxxx系のpackageは不要なので全て削除します。

package.json
-"@vue/cli-plugin-babel": "~4.5.13",
-"@vue/cli-plugin-e2e-cypress": "^4.5.13",
-"@vue/cli-plugin-eslint": "~4.5.13",
- "@vue/cli-plugin-pwa": "~4.5.13",
- "@vue/cli-plugin-router": "~4.5.13",
- "@vue/cli-plugin-typescript": "~4.5.13",
- "@vue/cli-plugin-unit-jest": "~4.5.13",
- "@vue/cli-plugin-vuex": "~4.5.13",
- "@vue/cli-service": "~4.5.13",

3. vue-cliコマンドをviteコマンドに修正

package.json内のコマンドをviteに修正します。

package.json
-"serve": "vue-cli-service serve",
-"build": "vue-cli-service build",
-"lint": "vue-cli-service lint",
+"serve": "vite",
+"build": "vite build",
+"lint": "eslint lint src",

4. index.htmlを修正する

  1. 続いて index.htmlをルートディレクトリに移動させます。viteではルートフォルダにあるindex.htmlをエントリポイントとするためです。
    public/index.htmlindex.html

  2. 移動させたindex.htmlにエントリーポイントとなる<script>タグを追加します。合わせてBASE_URLも削除します。
    (⚠️main.jsではなくtsであることに注意⚠️)

index.html
...
-<link rel="icon" href="<%= BASE_URL %>favicon.ico">
+<link rel="icon" href="/favicon.ico">
...
<div id="app"></div>
+ <script type="module" src="/src/main.js"></script>

5. vite.config.jsの設定

viteが.vue ファイルを扱えるように、vite.config.js@vitejs/plugin-vue の設定を追加します。

// vite.config.js
import vue from '@vitejs/plugin-vue'

export default {
  plugins: [vue()],
  server: {
    port: 8080,
  }
}

6. resolve.aliasを設定する

tsconfig.jsonで

tsconfig.json
"paths": {
  "@/*": [
    "src/*"
  ]
},

のようなpathsの設定を行なっている場合は、そのままでは読み込めないので、viteに設定を追加します。

vite.config.json
import vue from '@vitejs/plugin-vue'
import path from 'path'

export default {
  plugins: [vue()],
  server: {
    port: 8080
  },
+ resolve: {
+   alias: {
+     '@': path.resolve(__dirname, './src')
+   }
+ }
}

7. 環境変数を書き換える

viteでは環境変数名、読み込みの方法が以下のように変更になります。

vue-cli vite
変数名 VUE_APP_XXXX VITE_APP_XXXX
読み込みの方法 process.env.XXXX import.meta.env.XXXX

こちらに合わせて、既存の環境変数を書き換えます。

-VUE_APP_XXXX
+VITE_APP_XXXX
-process.env.XXXX
+import.meta.env.XXXX

以上で基本的な移行は完了になります。
yarn serveを叩いて動作を確認してみましょう!

もし何かエラーが出てしまった場合は以下のトラブルシューティングも参考にしてみてください😎


トラブルシューティング

以下自分が移行中に遭遇した問題と解決策について紹介します。

XXXX.vue: Uncaught ReferenceError: Cannot access 'YYYY' before initialization

コンポーネントを初期化前に参照できませんよというエラーです。
自分の場合は以下のようにindex.ts経由で読み込もうとしたコンポーネントで発生しました。

import {
  Spacer
} from '@/common'
common/index.ts
export { default as Spacer } from './Spacer.vue'
# 他のexportがずらずら...

原因としてはコンポーネントで循環参照をしてると起きる問題のようです

循環参照を探すのが辛かったので大人しく直接読むようにして解決しました✅

import Spacer from 'path/to/spacer.vue'

ReferenceError: require is not defined

ちょっと特殊ですが、以下のようにコンポーネント内でrequireを使っているとReferenceError: require is not definedで失敗します。

<nit-user-icon
  :src="require('@/assets/icons/guest-user.svg')"
>

ここは単純に読み込みパスを書き換えることで解決できました✅

<nit-user-icon
-:src="require('@/assets/icons/guest-user.svg')"
+:src="/src/assets/icons/guest-user.svg"
>

また、cssで~@のような読み込みを行なっている箇所も~を削除する必要がありました。

-background-image: url('~@/assets/background.png');
+background-image: url('@/assets/background.png');

アクセスすると404が出てしまう

ページにアクセスると以下のような画面になってしまいました。
404

これはなぜかURLのパス内に.が含まれていると正しく処理されなくなってしまっているようです。
自分の場合はOauthのコールバックに/login/{Firebaseのログイントークン}のようにしていて、そのトークンに.が含まれており、この問題が起きてしまいました。

対処法としてはパスで.を使わないようにするが良さそうです。
パラメータであれば問題なく動くので
/login?token={Firebaseのログイントークン}
のようにすれば解決しました✅

こちらはバグっぽいので報告しておきました。

Vercelのデプロイに失敗した

もしVercelでBuildコマンドを上書いている場合は忘れずに、viteに書き換えておきましょう。
vercel

console.logを削除したい

ドキュメントにあるterserOptionsを使ってこう書いても

vite.config.js
...
  build: {
    terserOptions: {
      compress: {
        drop_console: true
      }
    }
  }

なぜか効きません。

こちらを参考にrollup-plugin-terserを使うと効きました。(dev環境にも効くので環境変数などでtrue/faselを切り替えるようにする必要があります。)

vite.config.js
import { terser } from 'rollup-plugin-terser'
...
export default defineConfig({
  ...
  plugins: [
   terser({
      compress: {
        drop_console: true
      }
    })
 ]
})

以上です!
Good Hack🔥

参考🙏
https://medium.com/nerd-for-tech/from-vue-cli-to-vitejs-648d2f5e031d
https://vitejs.dev/

Discussion

もくめもくめ

大変参考になりました。

terserOptionsがなぜか効かないというのは

https://vitejs.dev/config/#build-minify
minifyの設定がデフォルトで 'esbuild'になってるからのようです。

build.minify: 'terser'

としたらconsole.log消えました。