Open10
既存Vue CLIプロジェクトのVite化
現行のプロジェクトをVue CLIからVite化したのでその作業メモ。
from
- @vue/cli-service@4.5.9 (webpack@4.46.0)
- Vue@2
- Vuex
to
- vite@2.8.4 (esbuild@0.14.21, rollup@2.67.2)
- Vue@3(予定)
- Pinia
なぜvite化するか
- devServerやHMRに時間がかかり開発体験が悪くなってきた
- モダンなライブラリを導入しようとしてもエラーになってしまった(piniaが導入できなかった)
- viteにすれば解決する問題なのかは分からなかったが、webpack@1の頃から5年以上開発してきたプロジェクトのせいでいろいろしがらみが増えてしまい、まずは足回りをシンプルにしたかった
- 結果的にpiniaが導入できるようになった
- これまでも改善したい要望はあったが、その場その場では「更新するコスト>そのまま開発するコスト」となりがちで手を付けにくかった(大局的には木こりのジレンマ)
- しかしvite自体のメリットはそうした懸念を吹き飛ばすくらいのインパクトがある
- 将来的な改善も進めていきやすそう
- 今回のプロジェクトではSSRやes5対応が不要
- vite化しても問題が無い
どうやってvite化していくか
- 現行コードのままviteを入れたとしても、エラーが出まくるのでどこまでやったら動かせる状態になるか読めない
- そのため新しくviteプロジェクトを作り、動いている環境に現行コードを段階的に移していくことにした
- Vue2プロジェクトなので、vite-vue2-windicss-starter を元にした
-
Webpack to Viteというツールもあるらしい
- こちらの存在は作業後に知ったが、やってみたら途中でエラーになってしまった
- 移行させる要点としては参考になるかも
段階的に動作させる
- mainファイルで動かなそうなところはいったんコメントアウト
- route毎に動くか確認していく
- packageは足りないとエラーになったものだけ入れていく
とにかくエラーが色々出る
- import周り
- env周り
- firebase周り
- node周り
- ビルド時
- HMR時
import周りの修正
vueファイルのimport
-
.vue
の拡張子が省略されていると読み込めない - js時代に作られたコンポーネントだと拡張子なしがデフォルトだった(ts化以降では拡張子をつけるようになった)
- 古いコンポーネントもけっこう残っていたので対応が必要になった
- 拡張子の省略に対応するなどで処理することもできそうだったけど、省略しないほうに統一したかったので全部書き換えた
require-> import
- 動的assetの読み込みにrequireを使っているとエラーになる
- 実行時に
require is not defined
になる
- 実行時に
- commonJSは使わないのでimportに書き換える
動的importのパスを相対パスにする
- 変数を含んだimportの場合、@などのエイリアスが効かない
- 実行時に
Failed to resolve module specifier '@/someDynamicPath'
になる
- 実行時に
- 内部的に dynamic-import-vars が使われている(ビルド時に警告が出る)
-
#limitationsにあるように、
.
から始まる相対パスにする
-
#limitationsにあるように、
動的アセットsrcの場合
-
<img :src="`@/assets/${name}.svg`">
は -
return new URL(`../assets/${name}.svg`, import.meta.url).href
のように生成したパスを使う
importでwebpackのloaderを使っていた部分を書き換える
-
raw-loader!./file.txt
としていたところは./file.txt?raw
になる
env周りの修正
.envファイル の変数定義
- VUE_APP_SOME_KEY -> VITE_SOME_KEY
env変数の読み込み
- process.env -> import.meta.env
- process.env.VUE_APP_SOME_KEY -> import.meta.env.VITE_SOME_KEY
- process.env.NODE_ENV -> import.meta.env.MODE
ライブラリ内でprocessを使ってるところ対策
- axios内部でprocess.envを参照していてランタイムエラーになるところがあった
- vite.configのdefineで
'process.env': {}
にした-
'process.env': 'import.meta.env'
だとなんか環境によってエラーになってしまったので、とりあえず空オブジェクトで回避するだけ
-
firebase周り
firebase@9にアップグレード
- firebase周りもimportでエラーが出てしまい、v7の古いものを使っていたので最新のv9に更新した
- v8までは全部入りのnamespacedな形式で、v9からは必要な関数だけimportするmodular形式に変更された
- ほぼ書き方が逆順になるので頑張って直す必要がある
node周り
- zlibやstreamが使えなかったので代替対応した
ビルド時の問題
import pathが解決しない
- devServerでは大丈夫だったがbuild時には解決されないケースがある
-
import(`../../icons/${props.name}.svg?component`
のような動的パス+?パラメータのケース- https://github.com/jpkleemans/vite-svg-loader/issues/24
- ?パラメータをつけていると現状では動的パスの解決がされない
対策
- ?パラメータをつけない
- loader pluginを自作し、?パラメータをつける代わりに指定ディレクトリ以下で挙動を変えるようにした
- 動的パスにしない
-
.scss?inline
などcssとしてinjectされたくないためにパラメータをつけざるを得ない場合 - 存在するファイル分だけ静的import宣言する
-
- こういう対策せずともなんとかなってほしい
root contextの取得
- 現状Vue v2からv3へ段階的に移行作業中で、compositionAPIでcontext.root(optionsAPIのthis相当、v3では廃止)を使用しているところがある
- injectされた
$store
や$route
、$t
などにアクセスするため
- injectされた
- しかしcomponentのsetup関数の引数からではなく、main関数から直接vue instanceを取得して使っていたところがあった
- viteでhmr時にこれが起因でエラーになってしまった
- composition化されたvue-i18nのvue2向けbackportで vue-i18n-composableというのがあった
- 実装されているコードを参考にして、正しくインスタンスを取得するようにした
- 最終的にはVue3化のタイミングでuseStore, useRouterを使うようにしてroot contextを使わないようにする
結果