Vuetify+Vue CLIで構築したプロジェクトで、
Vuetify2.xにアップグレードしたらnpm run serve
の開始時間が著しく長くなってしまったので改善します。
原因
Vuetify2.0よりデフォルトで有効となったA-la-carte(treeshaking)が原因です。
A-la-carteとは
Vuetifyの数多くのコンポーネントのうち、「プログラム中で使われているもの」だけを成果物に含める機能です。使っていないコンポーネントをimportしないので、ビルドサイズが減少します。
しかしながら、これはビルド時間を増大させます。
A-la-carteを使わない場合、vuetifyの全てのコンポーネントはnode_modules/vuetify/dist/vuetify.min.js
から読み込まれます。これは既にimportの解決やminifyが済んでいるプリコンパイル済みソースであるため、これをビルド成果物に含めるための処理は極めて軽いです。
ところが、A-la-carteを用いる場合、node_modules/vuetify/lib/*
(要するにVuetifyのビルド前のソースそのもの)からコンポーネントが読み込まれます。これは、Vuetify内部のimportの解決もこちらのコンパイルタイムで行わなければならないことを意味します。Vuetifyはソース数が非常に多く、これは大変な処理負荷となります。
さらに、scssなどもトランスパイルしなければならないため、これも少なからずビルド時間が増大する原因となります。A-la-carteを用いなければcssはnode_modules/vuetify/dist/vuetify.min.css
より読み込まれるので負荷はありません。
npm run serve
がなぜ重いか
ところが、実際のnpm run build
時にはそこまで大きくコンパイル時間が伸びることはありません(当然伸びるのは伸びるのですが)。これは、vuetify-loader
と呼ばれるWebpackプラグインによって、不要なものが削ぎ落とされているからです。必要なものだけビルドするので、使っているコンポーネント数に比例してしかビルド時間は伸びないはずです。
しかし、npm run serve
においてはそれがうまくいかず、非常にビルド時間が伸びてしまいます。これは、Webpack4のtreeshaking(vuetify-loader
はこの機能に依存しています)がproductionビルドでしか有効にならないためです。そのため、developmentビルドでは使っているコンポーネント数に関係なく全てのコンポーネントがビルドされ、非常に時間がかかります(特に開始時)。
解決策
解決策の方針としては以下のようになります。
- developmentビルド時は、ビルド時間を削減するためにA-la-carte(treeshaking)を利用しないようにする
- productionビルド時は、ビルドサイズを削減するために
vuetify-loader
を用いたA-la-carteを利用する
ソースの変更
以下はVue CLI3の例ですが、Webpackを生で使っている場合でも大きくは変わらないと思います。
vue-cli-plugin-vuetifyの無効化
package.json
より、vue-cli-plugin-vuetify
とvue-cli-plugin-vuetify-essentials
の削除
"devDependencies": {
...,
- "vue-cli-plugin-vuetify": "^1.1.2",
- "vue-cli-plugin-vuetify-essentials": "^0.8.3",
...
}
vuetifyのインポートの変更
Vue CLIインストールであればplugins/vuetify.js
でvuetifyを以下のようにインポートしていると思います。
import Vue from 'vue';
import Vuetify, { VList } from 'vuetify/lib';
Vue.use(Vuetify);
export default new Vuetify({ /* vuetifyのオプション */ });
これと同様にして、plugins/vuetify-dev.js
を以下の内容で作成します。
import Vue from 'vue';
import Vuetify from 'vuetify';
import 'vuetify/dist/vuetify.min.css';
Vue.use(Vuetify);
export default new Vuetify({ /* vuetifyのオプション */ });
さらに、main.js
でVuetifyをインポートしている部分を変更します。
import Vue from 'vue';
- import vuetify from './plugins/vuetify';
+ const vuetify = process.env.NODE_ENV === "production"
+ ? require('./plugins/vuetify').default
+ : require('./plugins/vuetify-dev').default;
import ...
/* (中略) */
new Vue({
vuetify,
render: h => h(App)
}).$mount('#app');
vuetify-loader
の手動ロード
vue-cli-plugin-vuetify
を消してしまったので、vuetify-loader
を手動でWebpackに読み込ませます。
vue.config.js
を以下のように編集します。
+ const vuetifyOptional = process.env.NODE_ENV === "production"
+ ? [new (require('vuetify-loader/lib/plugin'))()]
+ : [];
module.exports = {
...,
+ configureWebpack: {
+ plugins: [
+ ...vuetifyOptional,
+ ],
+ },
- transpileDependencies: ["vuetify"],
+ transpileDependencies: vuetifyOptional.length > 0 ? ["vuetify"] : [],
...,
}
動作確認
npm run serve
とnpm run build
をして正しくビルドできることを確認して下さい。
参考文献
https://vuetifyjs.com/ja/getting-started/quick-start/
https://vuetifyjs.com/ja/customization/a-la-carte/