Vueのbundleが遅くて辛いのでviteに乗り換える
Posted at: 2020-08-16
Vueを使用したプロジェクトの開発時のbundleが遅すぎて非常に辛い。
chunkやらなんやら高速化するための対応は色々しているのだが、それでも遅くて開発時に困っていたので解消方法を探してたらviteというものを発見し、導入してみたのでそのメモ。
viteとは
開発中にbundleを行わず、ES Module importを使用するビルドツール。Vueの開発者であるEvan You氏が開発している。
bundleしないので当然非常に早い。
.vueファイルなどは読み込んだタイミングでコンパイルされる。画面で実際にimportされたコードのみがコンパイルされるので、アプリケーション全体のbundleやコンパイルを待つ必要がない。
なお、2020/8/16時点でのステータスはbeta。1.0が近々リリースされるらしい。
とりあえずvite使ってみる
Getting started
$ npm init vite-app <project-name>
$ cd <project-name>
作られるpackage.jsonは以下
{
"name": "sample",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"dependencies": {
"vue": "^3.0.0-rc.1"
},
"devDependencies": {
"vite": "^1.0.0-rc.1",
"@vue/compiler-sfc": "^3.0.0-rc.1"
}
}
開発サーバを起動させてみる
$ npm install
$ npm run dev
> project-name@0.0.0 dev /your/project/path
> vite
vite v1.0.0-rc.4
Dev server running at:
> Local: http://localhost:3000/
> Network: http://192.168.3.9:3000/
大体1秒程度で立ち上がる。非常に小規模なサンプルプロジェクトなのでbundleしてもそこまでの差は出ないかもしれないが、なかなか速そう。
portの変更
--port
オプションを使う。
$ npx vite --port 8080
vite v1.0.0-rc.4
Dev server running at:
> Local: http://localhost:8080/
> Network: http://192.168.3.9:8080/
これで8080番portでDev serverが立ち上がった。
configファイルに記載することでもportを変更できる。viteでは vite.config.js
というファイルで設定する。
module.exports = {
port: 8080,
}
HTTPS/2化
ドキュメントにある通り--https
オプションを使えば勝手にself-signed cert を作ってくれてHTTP/2も有効になる。
$ npx vite --https
vite v1.0.0-rc.4
Dev server running at:
> Local: https://localhost:3000/
> Network: https://192.168.3.9:3000/
大抵の場合これで事足りる気がするが、何らかの理由で自前の証明書を使いたい場合は設定できる。
const fs = require('fs')
module.exports = {
https: true,
httpsOptions: {
key: fs.readFileSync('./cert/key.pem'),
cert: fs.readFileSync('./cert/cert.pem')
}
}
CSSプリプロセッサ
CSSにscssを使用する場合はモジュールの追加が必要。
$ npm i sass --save-dev
これでVueのSFCのstyleに対してscssが使用できる。
<style lang="scss" scoped>
.hoge {
color: red;
.fuga {
color: blue;
}
}
</style>
vue-cliを使用した既存プロジェクトからの乗り換え
vue2.xへの対応
既存プロジェクトはVue2系を使用しているが、そもそもviteは2系に対応していない。
3系はまだbeta版なのですぐにプロダクトに導入するのは難しいのでなにか方法がないかと探したらありがたいことに2系に対応するためのpluginを作っている方がいた。
内容の精査はできていないが、開発時にしか使わない想定だし最悪なにかあれば現状通りvue-cliによるbuildに戻せばいいだけなのでとりあえず使わせていただく。
$ npm i vite-plugin-vue2 --save-dev
私が試したタイミングではviteの最新版は 1.0.0-rc.3
、npm上のvite-plugin-vue2の最新版は 0.0.3
だったが、微妙にバージョンの互換性がなく、Vueのtemplate内を変更した時にHMRがうまくいかずエラーが出てしまう。
vite-plugin-vue2の最新のソースを落としてきて自前でbuildするか、viteの 1.0.0-rc.1
を使用すれば解消する。
たぶん近いうちに最新版も対応されると思うが一応メモ。
→ 追記: vite-plugin-vue2が 0.1.3
にupdateされて解消した。
configファイルでvite-plugin-vue2を使用する。
const { createVuePlugin } = require('vite-plugin-vue2')
module.exports = {
plugins: [createVuePlugin()],
}
これでVue2系が使用できた。
aliasの対応
vue-cliでは src
ディレクトリに対して @
をaliasとして使っていたのでviteでもそのaliasが使えるようにする。
importが import HelloWorld from '/@/components/HelloWorld.vue'
のような形であれば、configファイルに以下のようにaliasを設定すれば対応できる。
import path from 'path'
module.exports = {
alias: {
'/@/': path.resolve(__dirname, '/src'),
},
}
ただし、vite/config.ts at master · vitejs/vite · GitHub あたりを読んだところfsディレクトリへのaliasは /
で開始/終了していないといけないらしい。
つまり import HelloWorld from '@/components/HelloWorld.vue'
などのように記述していた場合aliasが使用できないのでresolverを書くことで対応する必要がある。
import path from 'path'
const aliasRegx = /^@\//
const myResolver = {
alias (id) {
if (id.match(aliasRegx)) {
return path.resolve('/src', id.replace(aliasRegx, ''))
}
},
}
module.exports = {
resolvers: [myResolver],
}
拡張子の省略に対応する
既存プロジェクトではimportにおいて .vue
や .scss
を省略している。
viteでは省略がサポートされている拡張子は '.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'
のみのようなので、configファイルのresolverで対応する。
(vite/resolver.ts at master · vitejs/vite · GitHub)
import path from 'path'
import fs from "fs"
const aliasRegx = /^@\//
const supportedExts = ['.vue', '.scss']
const isFile = file => {
try {
return fs.statSync(file).isFile()
} catch (e) {
return false
}
}
const resolveExt = _path => {
let resolvedPath = _path
if (!isFile(path.join(__dirname, resolvedPath))) {
for (const ext of supportedExts) {
if (isFile(path.join(__dirname, `${resolvedPath}${ext}`))) {
resolvedPath += ext
break
}
if (isFile(path.join(__dirname, `${resolvedPath}/index${ext}`))) {
resolvedPath += `/index${ext}`
break
}
}
}
return resolvedPath
}
const myResolver = {
alias (id) {
if (id.match(aliasRegx)) {
return path.resolve('/src', id.replace(aliasRegx, ''))
}
},
requestToFile (req) {
if (resolveExt(req) !== req) {
return path.resolve(__dirname, resolveExt(req))
}
},
}
module.exports = {
resolvers: [myResolver],
}
CORSへの対応
viteの開発サーバ(koa)がデフォルトだとCORSに対応していないので、必要がある場合は対応しておく。
$ npm install @koa/cors --save-dev
import cors from '@koa/cors'
module.exports = {
configureServer: ({ app }) => {
app.use(cors({ origin: '*' }))
},
}
感想など
個人的なプロジェクトで使ってみた限りでは非常に速くなって快適。
業務のプロダクトの方に導入してみようとしたところ、使っているライブラリがESModule importに対応していなかったりでクリアできていない部分が残っている。
個人的なプロジェクトやこれから始める小規模なプロジェクトで使ってみるにはいいんじゃないですかね。もうすぐVue3系もリリースされるはずだし。
いずれにしても開発時のみと考えればとりあえずあまり考えずに導入してみても良さそう。