状況説明
実行するbrowserifyコマンドです。
browserify src/js/client.js -o public/js/client.js
ソースファイルはsrc/js/client.js
です。出力先はpublic/js/
配下です。
例えば
const viewModel = require('./view-model')
と書くべきところを
const viewModel = require('./view-Model')
とtypoしてしまった時に、browserify
を実行してもエラーは起きません。
macOSのファイルシステムではview-model.js
とview-Model.js
は同一のファイルです。
Linuxでは違うファイルとして扱われます。
Linux上でbrowserify
を実行すると./view-Model
モジュールは見つかりません。失敗します。
実行環境
- Node.js v8.3.0
- browserify 14.4.0
- eslint 4.3.0
- eslint-plugin-import 2.7.0
- Docker version 17.06.0-ce, build 02c1d87
- node/alpine 8.3.0
作戦1 ESLint
ESLintでチェックできれば、Linuxに持っていく前に見つからないモジュールを検出できます。
eslint-plugin-import/no-unresolved.md at master · benmosher/eslint-plugin-importというESLintプラグインを使います。
eslint-plugin-import
にはno-unresolved
というルールがあります。
このプラグインはimport構文用のプラグインですが、オプションでrequire
関数にも対応します。
npm i -D eslint-plugin-import
を実行してプラグインをインストールし、.eslintrc
に
"import/no-unresolved": [
2,
{ commonjs: true }
]
な、ルール定義と
"plugins": ["import"]
な、plugin定義を足してください。
npx eslint src/js
を実行すれば、解決不能なモジュール名が含まれていないかチェックできます。
エディタがESLintに対応していれば、編集時点でエラーを検出できます。
Atomの場合は、AtomLinter/linter-eslint: ESLint plugin for Atom Linterを使います。
注意点: 定数以外のrequire関数の引数
次のように書いた場合は、エラーは検出されません。
const path = './view-Model'
const viewModel = require(path)
require
関数の引数に式や変数を入れるのはやめましょう。
ESLintで、require
関数の引数が定数でないことを検出するには、import/no-dynamic-requireを使います。
"import/no-dynamic-require": [2]
の、ルール定義を追加してください。
作戦2 Docker
ESLintの実行環境がない場合でも、Dockerを使えば、開発OS上にcase-sensitiveな環境を構築できます。
この例では、package.json
の以下の設定がしてあります。
-
devDependencies
ブロックでbrowserify
が指定 -
scprits
ブロックでbrowserify src/js/client.js -o public/js/client.js
が指定
FROM node:alpine
RUN mkdir -p /app
COPY ./package.json /app/
WORKDIR /app
RUN npm install
COPY src /app/src
RUN mkdir -p ./public/js
RUN npm start
時間のかかる、依存npmパッケージのインストールと、npm start
を分離するためにCOPYを2つに分けています。
実行頻度が低い時は、1つにした方がイメージサイズが小さくなると思います。
docker build .
で実行します。
成功すれば、正しくモジュール解決できています。
ハマりやすい罠:Volume mountsではcase-sensitiveな環境は作れない
Volume mountsが使えれば、次のコマンドでビルドするより早く実行できるはすです。
docker run -it -v (PWD):/app node:alpine -c `cd app && npm start`
残念ながらVolume mountsを使うと、ファイルシステムはホストOSのままなのでcase-insensitiveになってしまいます。
Volume mounts case insensitive - Docker for Mac - Docker Forums
「ハマりやすい罠」というか、一番最初に試してハマりました。