Node.js初心者・Angular初心者でありつつAngularアプリの動作確認を行う必要があったとき。ng serve
するとExpressというウェブサーバがローカル起動されますが、このサーバのファイル名の大文字小文字の扱いに関して、いわゆる“おま環”と思われる現象に遭遇しました。この現象は他の人の環境 (macOS環境) では再現できず、私のメイン環境 (Ubuntu環境) では再現できてしまう。また、私の別環境 (macOS環境) では再現できない。ウェブ検索しても原因がわからなかったのですが、どうやら実行環境の「ファイルシステム」の仕様に関係するような気がして頭を捻った結果、再現手順が作れましたので、下記に掲載します。
具体的にはこれは、記事タイトルに挙げている「case-sensitiveなファイルシステム (例: ext4) でのng serve時にファイル名が大文字小文字違いのファイルが同居していると小文字のファイルが404 Not Foundになる?」という仮説を検証する問題になります。再現手順で用いるAngularアプリとしてはng serve
が試せればおそらくなんでも良いわけで、Angular公式リポジトリ https://github.com/angular/examples にある「walk-my-dog」を用いています。
本記事に辿り着いた方のなにかの参考になりましたら幸いです。
$ npm version | grep -E 'npm|node'
npm: '8.19.2',
node: '16.17.1',
v8: '9.4.146.26-node.22',
$ cd <ext4領域の適当なディレクトリ>
$ df -Th .
Filesystem Type Size Used Avail Use% Mounted on
/dev/nvme0n1p2 ext4 457G 322G 112G 75% /
$ git clone https://github.com/angular/examples
$ cd ./examples/walk-my-dog/
$ ls -al ./src/assets/dog-walker-logo.*
-rw-r--r-- 1 mah mah 2976 3月 25 23:03 ./src/assets/dog-walker-logo.svg
$ cp -ip ./src/assets/dog-walker-logo.{svg,SVG}
$ ls -al ./src/assets/dog-walker-logo.*
-rw-rw-r-- 1 mah mah 2976 3月 25 23:21 ./src/assets/dog-walker-logo.SVG
-rw-rw-r-- 1 mah mah 2976 3月 25 23:21 ./src/assets/dog-walker-logo.svg
$ npm install
$ ng serve
$ curl -I http://localhost:4200/assets/dog-walker-logo.svg
HTTP/1.1 404 Not Found
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 166
Date: Mon, 25 Mar 2024 14:27:49 GMT
Connection: keep-alive
Keep-Alive: timeout=5
$ curl -I http://localhost:4200/assets/dog-walker-logo.SVG
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: image/svg+xml
Accept-Ranges: bytes
Content-Length: 2976
ETag: W/"ba0-06SevQUxlDl5sFFmZNn8+H9NSZE"
Date: Mon, 25 Mar 2024 14:28:14 GMT
Connection: keep-alive
Keep-Alive: timeout=5
(Ctrl+C でng serveを停止する)
$ rm ./src/assets/dog-walker-logo.SVG
$ ls -al ./src/assets/dog-walker-logo.*
-rw-rw-r-- 1 mah mah 2976 3月 25 23:21 ./src/assets/dog-walker-logo.svg
$ ng serve
$ curl -I http://localhost:4200/assets/dog-walker-logo.svg
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: image/svg+xml
Accept-Ranges: bytes
Content-Length: 2976
ETag: W/"ba0-06SevQUxlDl5sFFmZNn8+H9NSZE"
Date: Mon, 25 Mar 2024 14:30:30 GMT
Connection: keep-alive
Keep-Alive: timeout=5
謎です。まるで「ファイル名小文字のファイルへのgetリクエストに、ファイル名大文字のファイルの存在が影響する (ファイル名小文字のファイルへのgetを邪魔する)」かのよう。どうしてこのような挙動をするのだろう?
$ df -Th .
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda1 ntfs3 233G 72M 233G 1% /media/mah/TEST_NTFS
Ubuntuのext4領域での再現手順と同じ結果になる。
$ npm version | grep -E 'npm|node'
npm: '10.2.3',
node: '20.10.0',
v8: '11.3.244.8-node.25',
$ cd ~/tmp/
$ diskutil info / | grep 'File System'
File System Personality: APFS
cp
時にファイル名の大文字小文字違いが同一視されるためエラーになる$ cp -ip ./src/assets/dog-walker-logo.{svg,SVG}
cp: ./src/assets/dog-walker-logo.SVG and ./src/assets/dog-walker-logo.svg are identical (not copied).
cp
をpassして進めた場合、npm install
, ng serve
はノーマルな操作であって特に問題ない$ df -Th .
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda1 vfat 233G 28M 233G 1% /media/mah/TEST_FAT
cp
時にファイル名の大文字小文字違いが同一視されるためエラーになる$ cp -ip ./src/assets/dog-walker-logo.{svg,SVG}
cp: './src/assets/dog-walker-logo.svg' と './src/assets/dog-walker-logo.SVG' は同じファイルです
cp
をpassして進めると、npm install
でsymlinkが使用できない旨のエラーが発生してng serve
まで進めない$ npm install
(途中省略)
npm ERR! code EPERM
npm ERR! syscall symlink
npm ERR! path ../@angular/cli/bin/ng.js
npm ERR! dest /media/mah/TEST_FAT/examples/walk-my-dog/node_modules/.bin/ng
npm ERR! errno -1
npm ERR! Error: EPERM: operation not permitted, symlink '../@angular/cli/bin/ng.js' -> '/media/mah/TEST_FAT/examples/walk-my-dog/node_modules/.bin/ng'
npm ERR! [Error: EPERM: operation not permitted, symlink '../@angular/cli/bin/ng.js' -> '/media/mah/TEST_FAT/examples/walk-my-dog/node_modules/.bin/ng'] {
npm ERR! errno: -1,
npm ERR! code: 'EPERM',
npm ERR! syscall: 'symlink',
npm ERR! path: '../@angular/cli/bin/ng.js',
npm ERR! dest: '/media/mah/TEST_FAT/examples/walk-my-dog/node_modules/.bin/ng'
npm ERR! }
npm ERR!
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.