vue-cliをviteに移行する
viteとは一言で言うとめちゃくちゃ早いビルドツールです。
ビルドを超高速化することで開発時の生産性を大幅に向上させてくれます。
vite自体についての詳しい説明は本家を見ていただくとして、この記事ではvue-cliで開発しているプロジェクトをviteに移行する方法についてご紹介します。
実際どのくらい早くなるのかが気になるかと思うので、自分のプロジェクトで体感どのくらい早くなったかをご紹介します。
ちょっとわかりにくいですが、3秒くらい待ってたのが0.5秒くらいになっています。
導入前
導入後
スムーズにいけば1時間程度で導入でき、開発者全員が1日数百回ビルドすることを考えるとやって損はないと思います。(何よりビルドが早いと開発が楽しくなりますしね😆)
では行ってみましょう!
バージョン情報
Vue 3.2.20(※Vue2でも基本的に同じ方法で移行できますが検証は行っていません🙏)
vite: 2.6.14
単純なプロジェクトで移行を試してみる
いきなり本プロジェクトに導入するとハマって辛くなるのが目に見えてるので、まずは単純なプロジェクトで移行してみます。
基本的な移行方法を理解することで、自信を持って本プロジェクトに導入するとができ、結果的に時短になるのでおすすめです。
(急いでるのでいきなり本プロジェクトで試したい方はスキップしてください。)
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.
2. viteのインストール
- viteをインストールして、cli-serviceを削除します。
yarn add -D vite @vitejs/plugin-vue
yarn remove @vue/cli-plugin-babel @vue/cli-plugin-eslint @vue/cli-service
- serveコマンドを
vite
に差し替えます。
"scripts": {
"serve": "vite",
"build": "vite build",
"lint": "eslint src"
},
3. index.htmlの修正
- 続いて index.htmlをルートディレクトリに移動させます。viteではルートフォルダにあるindex.htmlをエントリポイントとするためです。
public/index.html
→ index.html
- 移動させたindex.htmlにエントリーポイントとなる<script>タグを追加します。合わせてBASE_URLも削除します。
...
-<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は不要なので全て削除します。
-"@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に修正します。
-"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を修正する
-
続いて index.htmlをルートディレクトリに移動させます。viteではルートフォルダにあるindex.htmlをエントリポイントとするためです。
public/index.html
→index.html
-
移動させたindex.htmlにエントリーポイントとなる<script>タグを追加します。合わせてBASE_URLも削除します。
(⚠️main.jsではなくtsであることに注意⚠️)
...
-<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で
"paths": {
"@/*": [
"src/*"
]
},
のようなpaths
の設定を行なっている場合は、そのままでは読み込めないので、viteに設定を追加します。
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'
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が出てしまう
ページにアクセスると以下のような画面になってしまいました。
これはなぜかURLのパス内に.
が含まれていると正しく処理されなくなってしまっているようです。
自分の場合はOauthのコールバックに/login/{Firebaseのログイントークン}
のようにしていて、そのトークンに.が含まれており、この問題が起きてしまいました。
対処法としてはパスで.を使わないようにするが良さそうです。
パラメータであれば問題なく動くので
/login?token={Firebaseのログイントークン}
のようにすれば解決しました✅
Vercelのデプロイに失敗した
もしVercelでBuildコマンドを上書いている場合は忘れずに、vite
に書き換えておきましょう。
console.logを削除したい
ドキュメントにあるterserOptionsを使ってこう書いても
...
build: {
terserOptions: {
compress: {
drop_console: true
}
}
}
なぜか効きません。
こちらを参考にrollup-plugin-terser
を使うと効きました。(dev環境にも効くので環境変数などでtrue/faselを切り替えるようにする必要があります。)
import { terser } from 'rollup-plugin-terser'
...
export default defineConfig({
...
plugins: [
terser({
compress: {
drop_console: true
}
})
]
})
以上です!
Good Hack🔥
参考🙏
Discussion
大変参考になりました。
terserOptionsがなぜか効かないというのは
minifyの設定がデフォルトで'esbuild'
になってるからのようです。としたらconsole.log消えました。
esbuildのままでもconsole.logを削除する設定もありました。
この変更でビルドタイムが 2/3 ほどになりました。
情報ありがとうございます!!