ECMAScript의 해시뱅

ECMAScript 2023의 해시뱅 커맨트를 알아보자.
2024.02.04

ECMAScript 2023에서 추가된 문법 중에 썸네일에 나와 있는 해시뱅 커맨트(hashbang comment) 라는 게 존재한다.

이전부터 js 파일에 해시뱅을 써오던 프로젝트를 봐왔기 때문에 당연히 이전 버전의 ECMAScript에 편입되어 있는 줄 알았다. 하지만, 최근에 찾아보니 이게 ECMAScript 2023, 최신 스펙인 것을 알게되었다.

이미 해시뱅을 사용하던 프로젝트들은 어떻게 동작했던 것이고 왜 사용돼 왔던 것일까?

코드로 직접 해보자

index.js라는 파일을 아래와 같이 준비해 보자.

console.log("hello hashbang!");

그리고 실행시켜 보자 ./index.js가 실행이 될까?

안타깝게 아래와 같은 에러가 나올 것이다.

❯ ./index.js
./index.js: line 1: syntax error near unexpected token `"hello hashbang!"'
./index.js: line 1: `console.log("hello hashbang!");'

터미널에서 사용 중인 셸은 읽은 파일을 어떤 인터프리터를 사용해야 할 지 모른다. 그래서 셸 스크립트들에는 #!/usr/bin/env bash 와 같이 어떤 인터프리터를 사용할지 정하는 커맨트를 파일 맨 위에 두게 된다.

그러면 우리는 js 파일을 노드로 읽으면 동작할 것 같으니 #!/usr/bin/env node 라는 코드를 index.js 파일 맨 위에 추가해 보자.

#!/usr/bin/env node

console.log("hello hashbang!");

그러면 hello hashbang!이 잘 나오는 것을 확인할 수 있다.

이러한 동작은 js나 node의 동작이라기보다 셸이 스크립트를 어떻게 읽어 들이는지 해시뱅 (#!) 을 통해 실행시킬 인터프리터를 지정하는 동작이다.

#! 뒤에 /usr/bin/env 가 추가되는 이유는 인터프리터가 존재하는 절대 경로를 찾는게 아니라 환경 변수에 등록된 인터프리터를 찾게 되는 것이고, node 가 설치 되었다면 실행이 되게 된다.

위와 같은 연유로 사람들은 마치 js 파일을 CLI 처럼 동작시키기 위해 사용해 왔고, 이전 버전의 npx 코드를 살펴보면 실제로 이러한 해시뱅을 염두해 둔 것을 볼 수 있다.

}).then(() => {
  const re = /#!\s*(?:\/usr\/bin\/env\s*node|\/usr\/local\/bin\/node|\/usr\/bin\/node)\s*\r?\n/i
  return buf.toString('utf8').match(re) && existing
})

그리고 이러한 #!/usr/bin/env node 해시뱅을 사용하는 곳을 찾아보면 create-react-app 처럼 npx 로 바로 실행시키는 패키지들에서 사용되고 있다.

Proposal

해시뱅 커맨트 추가를 제안하는 내용을 보자.

This proposal is to match de-facto usage in some CLI JS hosts that allow for Shebangs / Hashbang. ... This would move the stripping to engines, it does unify and standardize how that is done.

제안에도 쓰여있듯이 해시뱅(혹은 셔뱅이라 불리는)은 CLI들에서 사실상 표준처럼 사용돼 왔기에, 스트리핑 과정을 엔진으로 옮겨 표준화 시키자는 제안이다.

셸 스크립트에서처럼 파일의 맨 위에서만 사용될 수 있는 형태로 기존의 해시뱅과 비슷한 형태를 가지게 된다.

이러한 해시뱅은 de-facto 라는 표현을 쓸 만큼 많은 사람들이 사용해 왔기 때문에 위의 제안은 받아들여지게 되고 ECMAScript 2023 스펙에 들어가게 된다!

실제로 최신 버전의 브라우저라면 콘솔에서 #! 입력한 뒤 코드를 작성해보면 주석처럼 동작하는 것을 확인할 수 있다.

마무리

개발 생태계를 보면 어쩔 때는 "어떻게 이런 게 이전부터 있었던 거지" 싶다가도 "여태까지 이런 것도 없었다고?" 싶은 것들도 있는 것 같다.

다 사람이 하는 일이다 보니 누군가가 나서서 변화시키지 않으면 생태계라는 건 자동으로 개선되지 않기에 자그마한 하나하나 개발 생태계를 통해 얻어가는 사람들이 기여를 해야 하는게 아닌가 싶다.

별거 아닐 수도 있는 내용이지만, js 파일에 있는 #!/usr/bin/env node 코드를 보고 의문을 품은 사람들에게 궁금증이 풀리는 글이 되었으면 좋겠다.