browser向けjsの環境構築中、環境によって変えたい値を.envで管理したいという事でdotenv-webpackをインストールしたのだが、bundle作成時にエラーが出てつまったので共有をしておく。
環境
Package | Ver |
---|---|
webpack | 4.41.0 |
webpack-cli | 3.3.9 |
webpack-dev-server | 3.8.1 |
dotenv-webpack | 1.7.0 |
経緯
他のプロジェクトでもdotenv-webpack
をブラウザ向けに使っていたこともあり、特に何も考えずにdotenv-webpackをインストールしてビルドした。
$ npm install dotenv-webpack
webpack.config.js
const path = require('path'); const Dotenv = require('dotenv-webpack'); module.exports = { // ... plugins: [ new Dotenv({ systemvars: true }) ], // ... };
package.json
{ // ... "script": { // ... "dev": "webpack-dev-server", // ... }, // ... }
$ npm run dev
すると以下のエラーが発生した。
ERROR in ./node_modules/dotenv/lib/main.js Module not found: Error: Can't resolve 'fs' in '/xxx/xxx/node_modules/dotenv/lib' @ ./node_modules/dotenv/lib/main.js 24:11-24 @ ./src/api/config.ts @ ./src/api/encode.ts @ ./src/api/index.ts @ ./src/index.ts
よくある間違った解法
Can't resolve 'fs'
などでググるとwebpack.config.js
のtargetをnodeに変更しましょうという記事が出てくるが、これはサーバーサイドの時の話である。
ブラウザ向けの場合はこの設定をしてしまうと動かない。ではどうすればいいかというと、fsモジュールを使わないようにするしかない。モジュール内で使われているのであれば代替モジュールを検討するほかなくなる。
しかしそれは非常に困る。だって他のプロジェクトではdotenv-webpack
ちゃんと動いてるし。
解決
css-loaderのissueに同じような問題が上がっていたので、それを参考にwebpack.config.js
にnode: { fs: 'empty'}
を追加した。
webpack.config.js
const path = require('path'); const Dotenv = require('dotenv-webpack'); module.exports = { // ... plugins: [ new Dotenv({ systemvars: true }) ], node: { fs: 'empty' }, // ... };
詳細は公式ドキュメントに記載されているが、要約するとNode用モジュールをポリフィルもしくはモックして、ブラウザーでも実行できるようにする!という事らしい。
そしてempty
は空のオブジェクトを提供するという意味なので、dotenv
内のfs
は何もしない空モジュールという事になる。
ブラウザ用ではfs
なんて使わないので、これで問題無。無事解決。良かった良かった。