vue-cliで環境ごとに異なる静的ファイルをコピーする


 最近地味に困ってあれこれ調べたことの記録です。

public配下においた静的ファイルをビルド対象によって切り替えたい

 vue-cliのプロジェクトで静的ファイルをpublic配下に置いていたのですが、productionで切り替えたい事案が発生しました。具体的にはvue-routerでhistoryモードを使っていたがために.htaccessを置いていたのですが、開発環境ではサブディレクトリでデプロイ先が切られていたために、ルートディレクトリを指定したかったのです。

public/.htaccess
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /test/ [L] <-- 本番では / にしたい…
</IfModule>

 最初ここに<%= PUBLIC_PATH %>とか書いてみたのですが、そのまま文字列として出力されてしまいました。どのみちAPIのスタブJSONとかも置いていたので、これらが出力されるのも困るのでこの方法は早々に諦めました。手動でビルドしたファイルを毎回編集したり削除したりするのは死んでも嫌だったので、vue-cli先生にはそのくらいの気は利かせてくれるようにしたいと思います。

 「そもそもここに.htaccess置くな」と言われれば最もだとは思います。スタブもjsonじゃなくてexpressとかでやった方がスマートではあるのですが、まぁそれはそれとして…。

ビルドモードごとに異なる静的ファイルを参照させる

 public配下に静的ファイルを置くのではなくて、ビルド時に環境ごとに用意したディレクトリから静的ファイルを配置するように変えてみます。

ディレクトリを用意する

 特に指定された箇所があるわけではないので、自分で src/static/ディレクトリを作成し、その中で環境ごとにそれぞれサブディレクトリを掘ります。今回は本番環境とそれ以外の環境で分けたかったので、src配下に以下のようにディレクトリを切りました(不要なところは省略)。

% tree -d  
.
├── static
│   ├── develop
│   └── production

 各ディレクトリに、それぞれビルド時にコピーしたいファイルを配置していきます。

プロダクションと開発環境のビルドを分ける

 npm run buildだとproductionでビルドされるので、develop用のビルドコマンドを追記してそれぞれにビルド出来るようにします。

package.json(抜粋)
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build:develop": "vue-cli-service build --mode develop", <--追加
    "lint": "vue-cli-service lint"
  },

 .envもそれぞれ用意しておきます。

.env.production(抜粋)
NODE_ENV=production
.env.develop(抜粋)
NODE_ENV=development

 これでnpm run build:developを打ったときには、developmentでビルドしてくれるようになっているかと思います。

ビルドモードに応じたディレクトリ内容をdistへコピーする

 vue-cliはデフォルトでpublicからコピーするようになっているようですが、先程追加したディレクトリからビルドモードに応じたファイルをコピーするように追記します。前述のようにproductionかそれ以外かで分けられれば今回はOKだったので、以下のように追記しました。

vue.config.js(抜粋)
const isProduction = process.env.NODE_ENV === "production"; // <-- productionビルドかどうかを判定
const path = require("path"); // <-- ディレクトリ操作をしてなければ追記

module.exports = {
  assetsDir: "assets",
  lintOnSave: false,
  chainWebpack: config => {
    // 静的ファイルのコピー処理
    config.plugin("copy").tap(args => {
      args[0].push({
        from: path.resolve(
          __dirname,
          isProduction ? "src/static/production" : "src/static/develop" <--先程作成したディレクトリをそれぞれ指定
        ),
        to: path.resolve(__dirname, "dist"),
        toType: "dir",
        ignore: [".DS_Store"]
      });
      return args;
    });
  },
};

コピー処理は以下を参照して記述しました。
https://stackoverflow.com/questions/60304092/how-to-copy-assets-with-vue-cli-service-build-command

ビルドしてみる

 npm run build時にはsrc/static/production内が出力され、npm run build:developではsrc/static/developが出力されるようになっているのが確認出来ればOKです。今回はproductionか否かしか判定していませんが、環境がもっと増えた場合は判定を追加すればコピー元ディレクトリもそれぞれに用意出来るかと思います。