【webpack】envデータを埋め込む

初書：2021/10/16
mac : 11.6
electron : 15.1.2
webpack : 5.58.1

# きっかけ

Electronでアプリバージョンを取得しようと試みたときに、
どうしてもうまいこといかないので埋め込んでしまえ！となった。

# (余談)nodeでアプリバージョンを取得する。できなかった

記事にするほどでもないけどどこかに書いておきたかったので簡単にメモ。
飛ばしてもらっていいです。

地味にどう調べたらいいかわからないこれ。
簡単に説明すると、nodeで作成しているアプリケーションのバージョンが、
`package.json`の`versions`に保存されているが、
これを取得したい。

参考サイト：[node.js — Nodejsコードでpackage.jsonからバージョンを取得する方法はありますか？](https://www.webdevqa.jp.net/ja/node.js/nodejs%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7packagejson%E3%81%8B%E3%82%89%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B%EF%BC%9F/942350539/)

それっぽい回答のページ。色々と方法は載っている。

`process.env.npm_package_version`や`project-version`パッケージを使用する、など。

開発中はこれで一応できるのだが、これを`electron_builder`でビルドし、
アプリケーションとしてしまうと、undefinedを返す(`project-version`に関しては起動できなくなった)

仕方ないので、コード内に直接バージョン情報を埋め込めばいいのではないか、となった。

# cross-envを使ってみる

webpackでビルドする際、`cross-env`を使用している。

```json:package.json
    "build": "cross-env NODE_ENV=\"development\" webpack --progress",
```

これ、２つ以上の環境変数をセットすることが出来るらしい。
なのでこれを増やす。

```json:package.json
    "build": "cross-env NODE_ENV=\"development\" VERSION_ENV=\"v1.0.0\" webpack --progress",
```

ここで問題点が一つ。バージョン情報をここで埋め込んでしまう。
(ここで失敗することに気づけばこれ以降のことをする必要がなかったのだが、上の問題点に先に気づいてしまったためにやった。)

ということで受け取るようにする。
上の余談の回答の一つに、

```
% node -p "require('./package.json').version"
```
でバージョン情報が取得できるとの情報を得た。これを渡せばいいのでは。

## 変数を使って情報を渡す

参考サイト：[bashでパイプ(標準入力)から受け付けた内容を変数に代入する | 俺的備忘録 〜なんかいろいろ〜](https://orebibou.com/ja/home/201708/20170806_001/)

`echo ABC | { read v ;echo -e "$v"_TEST; }`という書き方で上手いこと渡せるらしい。
ということで組み合わせる。


```json:package.json
    "build": "node -p \"require('./package.json').version\" | { read v ;cross-env NODE_ENV=\"development\" VERSION_ENV=\"$v\" webpack --progress; }",
```

はい。これで失敗しました。
後に気づくとあることに対応すればこれでいけるかもしれないが。

## cross-env-shellを使う

`cross-env`に`cross-env-shell`が存在しているのを知る。(どこを見て気づいたか忘れました。。)

これは、変数にシェルコマンドを書き込むことで`cross-env-shell`が勝手に書き換えてくれる拡張版。

ということで先程のを書き換える。

```json:package.json
    "build": "cross-env NODE_ENV=development VERSION_ENV=\"node -p \"require(\'./package.json\').version\" webpack --progress",
```

記録残すの忘れました。これでエラーが出たらエスケープの数適当に増やすなり消すなりしてください。

そしてこれも無事に失敗する。原因が他のところにあるからなのだが。。

## env-cmdを使う

cross-env側の問題だと思っているので、他のライブラリを使ってみます。

参考サイト：[環境変数設定は基本cross-envだけどたまにenv-cmdも使う - Qiita](https://qiita.com/noonworks/items/179c71deaf3280fa5a1e)

これは、`cross-env`ではコマンドに直接書いていた変数を、別途ファイルに書き込んでそれを読み込む形式のもの。

ということで設定ファイルを用意し、

```js:cmd.js
exports.NODE_ENV = "development";
exports.VERSION_ENV="v1.0.0";
```

コマンドを書き換え、

```json:package.json
    "build": "env-cmd -f cmd.js webpack --progress",
```

実行するが意味なし。

# webpackから直接envファイルに埋め込めないかを調べる。

そして調べているうちに察する。

`cross-env`が書き換えているわけではなく、webpackが書き換えていることに。

今まで渡していたのは、webpackとして実行されるjavascriptファイルに、
`development`で変換するか`production`で変換するかを渡していた。
変換後の`process.env.NODE_ENV`が書き変わっているのはおそらくwebpackが勝手にやってるから。

なので、それ以外の`process.env`は、手動で指定しなければいけなかった。
そして辿り着いたのがここ。

参考サイト：[webpackで環境変数をモジュールに渡す - Qiita](https://qiita.com/hal9188/items/ae4302412c179a1034cb)

手動で書かないといけないんですねー。
ということでwebpackを書き換える。いや追記する。

# webpack.config.tsを編集する

tsと書いてるがjsでも特に変わらない。

デフォルトで存在している`DefinePlugin`クラスを使用することで、変換時に該当するコードを置き換えてくれる。
今回は`process.env.VERSION_ENV`なのでこれだけ指定する。
(process.envも指定する必要がある。)

```ts:webpack.config.ts
  plugins : [
    new DefinePlugin({
      'process.env.VERSION_ENV': `"${require('./package.json').version}"`,
    })
  ]
```

右辺は余談の時に出てきた参考サイトにあったコード。埋め込むならローカルで動くコードでいいやという感じで。

ちなみに`変数を使って情報を渡す`のところにあったこれで、右辺を`process.env.VERSION_ENV`にするか
`EnvironmentPlugin`というクラスにすれば動いたのかもしれない。

あと、`webpack`の方で指定するため、`package.json`側はデフォルトのままでいい。

# 終わりに

書き換える場所さえ気づけば大回りする必要がなかったなあと思う今日この頃。

あと記事の書き方がどうでもいい失敗談→結果という書き方は果たしてみやすいのだろうか。少し気になる。