Vue.js で非SPAのサイトもホットリロードで開発したい

更新日
2017.06.15
作成日
2017.04.30

一度だけなら…とホットリロードを体験してしまうと依存スパイラルに陥り数秒のビルドにもイライラしはじめそれなしではいられない体になります。

Vue のホットリロードいいよね♥

単純にブラウザをリロードするわけじゃなくてシームレスに更新される開発モードがあるじゃないですか。他の言語やフレームワークでもホットデプロイとして多分同じような機能はあると思うんですけど初めて使った時私は感動しました。

SPA にはしない

多ページサイトで所々 Vue を使いたいとか API が無い自分の好きな CMS を使ってるなど理由があって SPA にはしないけど開発モードのホットリロードだけ使いたい人向けです。

Vue-cli でセットアップする

対象のプロジェクトフォルダに vue-cli の webpack テンプレートでもろもろインストールします。webpack-simple でも出来たけど反映が遅い気がする…。

既存の package.json に追加する場合

既にモジュールを沢山使っていて新規でインストールしたくない場合は別途作成して build、config フォルダをコピーして、依存モジュールを追加します。package.json に追加して npm install するか、スペースで区切って npm install -D ...  で一括インストールなどします。多分この辺。

  • babel 関連
  • loader 関連
  • autoprefixer
  • connect-history-api-fallback
  • cross-env
  • express
  • friendly-errors-webpack-plugin
  • html-webpack-plugin
  • opn
  • ora
  • semver
  • webpack-dev-middleware
  • webpack-dev-server

既に Webpack を使っていれば babel や loader は入っていると思うので足りないモジュールがあれば補充します。

エイリアスなどプロジェクトに必要な設定は build にある webpack.config.xxx.js を編集します。

プロキシを設定

config/index.js に空のプロキシテーブルがあるので XAMPP などで動作させてる URL を追加します。

config/index.js

    proxyTable: {
      '*': {
        target: 'http://project.localhost',
        changeOrigin: true,
        filter: function (pathname) {
          if (pathname.match('hot-update.(js|json)$') ||
              pathname.match('^/app.js$') ||
              pathname.match('^/__webpack_hmr$') ||
/* Devモードで動的に読み込みたいものを追加する */
pathname.match('^/dist/static/img')) {
            return false
          }
          return true
        }
      }
    },

ルートに http://project.localhost が吊り下がる感じになります。

開発するときは npm run dev を実行して http://localhost:8080 の URL を使います。

ファイルを移動させた場合は scripts 部分をコピー。engines の部分も必要です。

package.json

"dev": "node build/dev-server.js",
"build": "node build/build.js"

ビルド時にハッシュを付けないようにする

ドキュメントが動的に作成されないのでビルドするたびにハッシュ付きのパスに書き換えるのは大変なので生成ファイルにハッシュを付けないように設定します。

build/webpack.prod.conf.js にある [chunkhash] と [contenthash] を削除。

スクリプトパスを同じにする

開発中の JavaScript の読み込みは /app.js を使うようにしますが、 Dev モードの output.filename と dev.proxyTable.filter 部分で /app.js のパスを修正して開発と本番で同じパスにしておくと変更しなくていいので楽です。

config/index.js

dev:{
assetsPublicPath: '/dist/'
}

build/webpack.dev.config.js

output: {
filename: 'static/js/[name].js'
}

これだと開発中と本番でパスを修正しなくてもOK。

<script src="/dist/static/js/manifest.js"></script>
<script src="/dist/static/js/vendor.js"></script>
<script src="/dist/static/js/app.js"></script>

自分の環境がプロジェクトルートとドキュメントルートが同じでデフォルトのパスのままなのでこの設定なんですが dist 以下がドキュメントルートになる場合は、同じように dist を除いて dev のパスを修正して、出力する index.html のファイル名部分も邪魔にならないように変更とかしてください。このファイルが不要なら HtmlWebpackPlugin 部分を削除してしまっても平気そう。

例えば HTML には書いているけどビルドされた CSS を読み込まないようにするとか、Dev モードでは特定のファイルの読み込み先を別にしたい、動的パスを読み込みたいとかあれば pathRewrite や filter でパスを設定して動的ファイルや空のファイルに誘導してしまうと良いです!

pathRewrite: {
  '^/dist/static/css/.*?\.css': '/dist/dummy/dummy.css',
  '^/dist/static/js/.*?\.js': '/dist/dummy/dummy.js'
},

デモ

ディレイ付きのアニメーションなのでちょっと分かりにくいですが、SVGアニメを作っているコンポーネント部分だけがリロードされてサクッと確認できます。特にこういう部品のアニメーションとかはいちいちビルドするのが面倒なので別のフォルダで作り込んで上手く行ったらコピペとかしてたけどこの速度だったら直接編集してもストレスにならなさそうです!

まとめ

すごいストレスフリーになりました\(*⁰▿⁰*)/

最初は webpac-dev-derver + vue-hot-reload-api を試してみましたがブラウザ自体がリロードされてしまって vue-cli のようにスルっとさせるのにゼロから設定するのとても面倒くさそうなのでやめました。今のところ Webpack を必要以上に勉強する気はあんまりないので(´ . .̫ . `)

さて、次回は Vue-router を使ったページの構成&遷移エフェクトについてやります。