Open10

既存Vue CLIプロジェクトのVite化

miyaokamiyaoka

現行のプロジェクトを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
miyaokamiyaoka

なぜvite化するか

  • devServerやHMRに時間がかかり開発体験が悪くなってきた
  • モダンなライブラリを導入しようとしてもエラーになってしまった(piniaが導入できなかった)
    • viteにすれば解決する問題なのかは分からなかったが、webpack@1の頃から5年以上開発してきたプロジェクトのせいでいろいろしがらみが増えてしまい、まずは足回りをシンプルにしたかった
    • 結果的にpiniaが導入できるようになった
  • これまでも改善したい要望はあったが、その場その場では「更新するコスト>そのまま開発するコスト」となりがちで手を付けにくかった(大局的には木こりのジレンマ)
    • しかしvite自体のメリットはそうした懸念を吹き飛ばすくらいのインパクトがある
    • 将来的な改善も進めていきやすそう
  • 今回のプロジェクトではSSRやes5対応が不要
    • vite化しても問題が無い

どうやってvite化していくか

  • 現行コードのままviteを入れたとしても、エラーが出まくるのでどこまでやったら動かせる状態になるか読めない
  • そのため新しくviteプロジェクトを作り、動いている環境に現行コードを段階的に移していくことにした
  • Webpack to Viteというツールもあるらしい
    • こちらの存在は作業後に知ったが、やってみたら途中でエラーになってしまった
    • 移行させる要点としては参考になるかも
miyaokamiyaoka

段階的に動作させる

  • mainファイルで動かなそうなところはいったんコメントアウト
  • route毎に動くか確認していく
  • packageは足りないとエラーになったものだけ入れていく

とにかくエラーが色々出る

  • import周り
  • env周り
  • firebase周り
  • node周り
  • ビルド時
  • HMR時
miyaokamiyaoka

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にあるように、. から始まる相対パスにする

動的アセット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になる
miyaokamiyaoka

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'だとなんか環境によってエラーになってしまったので、とりあえず空オブジェクトで回避するだけ
miyaokamiyaoka

firebase周り

firebase@9にアップグレード

  • firebase周りもimportでエラーが出てしまい、v7の古いものを使っていたので最新のv9に更新した
  • v8までは全部入りのnamespacedな形式で、v9からは必要な関数だけimportするmodular形式に変更された
  • ほぼ書き方が逆順になるので頑張って直す必要がある
miyaokamiyaoka

ビルド時の問題

import pathが解決しない

  • devServerでは大丈夫だったがbuild時には解決されないケースがある
  • import(`../../icons/${props.name}.svg?component` のような動的パス+?パラメータのケース

対策

  • ?パラメータをつけない
    • loader pluginを自作し、?パラメータをつける代わりに指定ディレクトリ以下で挙動を変えるようにした
  • 動的パスにしない
    • .scss?inlineなどcssとしてinjectされたくないためにパラメータをつけざるを得ない場合
    • 存在するファイル分だけ静的import宣言する
  • こういう対策せずともなんとかなってほしい
miyaokamiyaoka

root contextの取得

  • 現状Vue v2からv3へ段階的に移行作業中で、compositionAPIでcontext.root(optionsAPIのthis相当、v3では廃止)を使用しているところがある
    • injectされた$store$route$tなどにアクセスするため
  • しかしcomponentのsetup関数の引数からではなく、main関数から直接vue instanceを取得して使っていたところがあった
  • 最終的にはVue3化のタイミングでuseStore, useRouterを使うようにしてroot contextを使わないようにする