로컬에서 브라우저싱크를 돌리는데 아래와 같은 에러가 발생하면서 작동을 하지 않았다.

[Browsersync] Proxying: http://localhost
[Browsersync] Access URLs:
 -------------------------------------
       Local: http://localhost:3000
    External: http://192.168.1.16:3000
 -------------------------------------
          UI: http://localhost:3001
 UI External: http://localhost:3001
 -------------------------------------
[Browsersync] Watching files...
node:internal/errors:464
    ErrorCaptureStackTrace(err);
    ^

Error: ENOSPC: System limit for number of file watchers reached, watch '/my-project-folder/vendor/myclabs/deep-copy/.github'
    at FSWatcher.<computed> (node:internal/fs/watchers:244:19)
    at Object.watch (node:fs:2247:34)
    at createFsWatchInstance (/my-project-folder/node_modules/chokidar/lib/nodefs-handler.js:119:15)
    at setFsWatchListener (/my-project-folder/node_modules/chokidar/lib/nodefs-handler.js:166:15)
    at NodeFsHandler._watchWithNodeFs (/my-project-folder/node_modules/chokidar/lib/nodefs-handler.js:331:14)
    at NodeFsHandler._handleDir (/my-project-folder/node_modules/chokidar/lib/nodefs-handler.js:559:19)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async NodeFsHandler._addToNodeFs (/my-project-folder/node_modules/chokidar/lib/nodefs-handler.js:609:16)
Emitted 'error' event on FSWatcher instance at:
    at FSWatcher._handleError (/my-project-folder/node_modules/chokidar/index.js:647:10)
    at NodeFsHandler._addToNodeFs (/my-project-folder/node_modules/chokidar/lib/nodefs-handler.js:637:18)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  errno: -28,
  syscall: 'watch',
  code: 'ENOSPC',
  path: '/my-project-folder/vendor/myclabs/deep-copy/.github',
  filename: '/my-project-folder/vendor/myclabs/deep-copy/.github'
}

핵심 에러 문장은 Error: ENOSPC: System limit for number of file watchers reached인데, 파일 변경 감시자가 최대치까지 가서 더이상 파일을 감시할 수 없다는 말이다. ENOSPC는 nodejs에서 드라이브에 공간이 없다는 의미로 사용되는 에러 코드라고 한다. 이 경우는 드라이브는 아니니, 뭔가 공간이 없으면 그냥 저 에러 코드를 사용하곤 하나보다.

브라우저싱크는 파일이 변경되는지를 감시하고 있다가 파일 변경이 감지되면 브라우저를 새로고침하는 역할을 하는데, 감시할 파일이 너무 많아서 뻗어 버린 것이다.

단순한 해결책

이 에러로 검색을 해 보면 아래 명령으로 파일 감시 숫자를 최대치까지 키워 해결하라고 한다.

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

fs는 file system의 약자다. tee -a는 파일 끝에 문자열을 더하는 명령이다.

그런데 이게 능사일까? 내 심지어 경우에 이미 저 조처를 취해둔 뒤였다.

감시 대상을 제한하라

라라벨에서도 브라우저싱크를 사용하는데, 최근엔 이런 에러를 만난 적이 없다. 그런데 지금 이런 에러를 만난 프로젝트는 라라벨이 아니라 워드프레스였다. 브라우저싱크가 너무 많은 파일을 감시하도록 설정한 게 아닐까 하는 생각이 들었다. 불필요한 파일을 너무 많이 감시하면 메모리도 많이 든다.

설정을 살펴 보니 웬걸, 내가 손댈 일이 없는 node_modulesvendor까지 감시를 하게 설정이 돼 있었다. 아래가 감시 대상을 규정한 브라우저싱크 설정이다.

mix.browserSync({
   proxy: 'ws-dev.localhost',
   files: [
      '**/*.php',
      '**/*.js',
      '**/*.css',
   ]
});

이걸 아래처럼 고쳐서 감시 대상을 제한했다. PHP 파일은 테마 폴더로 제한했고, js는 컴파일 결과 폴더와 구 js만 감시하게 제한했다. 그리고 CSS도 컴파일 결과만 감시하게 제한했다.

mix.browserSync({
   proxy: 'ws-dev.localhost',
   files: [
      'wp-content/themes/ws/**/*.php',
      'wp-content/themes/ws/build/*.js',
      'wp-content/themes/ws/js/*.js',
      'wp-content/themes/ws/build/*.css',
   ]
});

이렇게 하니 문제가 해결됐다.

기타 - 메모리 사용량, 프로세서 확인

max_user_watches=524288이 최댓값인데, 감시자 하나당 사용하는 메모리가 1080바이트(64비트 시스템에서)라서 최댓값까지 감시자를 사용하면 메모리를 540MB 사용하게 된다. 32비트 시스템이라면 270MB.

어떤 프로세스가 파일 감시자를 사용하고 있는지 확인하려면 아래 명령을 사용한다. root 사용자로 들어가서 실행해야 한다.

find /proc/*/fd -lname anon_inode:inotify |
cut -d/ -f3 |
xargs -I '{}' -- ps --no-headers -o '%p %U %c' -p '{}' |
uniq -c |
sort -nr

참고

How To Fix – Error “ENOSPC: System Limit for Number of File Watchers Reached”?