Module, Package, Workspace

공명·2022년 1월 22일
post-thumbnail

Module이란

Node.js 에서 Module이란 하나의 파일입니다. 우리의 소스코드 개별 파일이 모두 모듈이죠.

자세히

JavaScript의 런타임이 브라우저가 유일했던 시절, Global scope를 더럽히지 않는 모듈 방식의 개발이 절실했고, 이를 구현한 몇가지 방식들이 인기를 끌었습니다. CJS(CommonJS), AMD(Asynchronous Module Definition)가 그랬고 훗날 ECMA 에서는 클라이언트 사이드의 모듈 명세를 ES6에서 밝히며 우리가 잘아는 import, export 방식의 ESM(ECMAScript modules)이 표준이 됩니다.

Node.js가 나올 때 채택한 것이 CommonJS 모듈입니다. 그래서 우리가 단순 Node.js 앱을 만들 땐 const something = require('something') 식으로 가져오는 것이죠. 상호운용(interoperation)을 할 수도 있습니다.

interoperation 익숙한 단어 아닌가요? tsconfig에서 많이 보셨을 옵션인 esModuleInterop 이 바로 그겁니다. CJS를 ESM방식으로 불러다 쓸 수 있게 하는겁니다. npm은 node package manager의 약자입니다. 때문에 Node.js의 채택 방식인 CJS가 기본이죠. npm 레지스트리에 있는 패키지들이 이런 CJS를 쓰는데 우리가 우리가 import 방식으로 선언할 수 있는 이유가 바로 이 상호운용성에 있습니다.

후에 Node.js는 ESM 도 기본 모듈로 사용할 수 있게 했습니다. 다만 ESM으로 구성한다는 몇가지 설정들이 필요합니다.

사실 정말 다를 내용이 많은데요. 이건 차츰 글로 작성해 공유하기로 하고, 오늘은 Module, Package, Workspace에 집중해봅시다.

Package란

Node.js 에서 Packagepackage.json으로 기술된, 하나의 폴더 트리입니다.

자세히

nested된 폴더, package.json이 있는 또 다른 패키지, node_modules 폴더 등을 아우릅니다. 이런 폴더트리의 최상위에 package.json가 이 패키지를 기술합니다.

Node.js는 다음과 같은 경우에 ESM 모듈방식으로 실행합니다. 여기서 실행시란 말은 node(CLI) 로 실행할 때를 말합니다.

  • .mjs 파일 실행시
  • .js 파일 실행시 가장 가까운 부모 package.jsontype 필드가 module 일 때
  • 실행시 --input-type=module 플래그가 붙은 채로 표준입력(STDIN) 혹은 --eval 플래그의 인수를 받을 때

그 외 모든 경우엔 CJS로 실행합니다. 다만 CJS와 ESM를 모두 지원하기 때문에 explicit 한 방식이 좋습니다.

다음과 같이 명시적으로 CJS 모듈 방식을 사용할 수도 있습니다.

  • .cjs 파일 실행시
  • .js 파일 실행시 가장 가까운 부모 package.jstype필드가 commonjs일 때
  • 실행시 --input-type=commonjs 플래그가 붙은 채로 표준입력(STDIN) 혹은 --eval 혹은 --print 플래그의 인수를 받을 때

npm은 Node.js의 패키지 매니져고 패키지 매니져이기 때문에 패키지들의 저장소인 registry도 가집니다. express, dayjs, reactpackage.json으로 기술된 하나의 패키지이고 registry에 해당 이름으로 publish된 것이죠.

Workspace란

Workspace란 로컬 에서 하위에 상호 가져다 쓸 수 있는 패키지를 둔 루트 패키지입니다.

자세히

npm을 통해 우리는 registry에 출시된 공개 패키지들을 마음껏 우리 패키지의 의존성 패키지로 설치할 수 있게 되었습니다. 개발을 하다보면 여러 프로젝트에서 자주 쓰는 본인/팀만의 함수, 모듈 셋이 생기는데요. 이를 npm registry에 등록하기는 껄끄럽고 private으로 쓰자니 유료고 또 등록하기 까지의 종합적 cost가 큽니다.

그래서 로컬에서 나만의 패키지 정의를 하고 여러 패키지에서 가져다 쓸 수 있게 하자는 아이디어가 나왔습니다. 이를 구현한 것이 Workspace입니다. 우리가 A라는 패키지를 만들고 그 A패키지 자체를 다른 패키지에서 마치 registry로 설치한 패키지들 처럼 불러다 쓸 수 있게 해줍니다.

npm, yarn v1 package manager의 module resolve 방식은 file system의 node_modules directory를 시스템의 root(/)에 닿을 때까지 recursive하게 찾는 방식입니다.

workspace에선 패키지 매니저로 install 명령을 하게 되면, 내가 만든 A, B, C라는 패키지가 workspace root의 node_modulessymlink로 추가되게 됩니다. 설치한 다른 패키지처럼 똑같이 node_modules에 존재하는 것이죠.

이를 통해 패키지간 서로를 불러오고 consume할 수 있습니다.

민간(yarn)이 주도, 공식(npm)이 후반영

사실은 yarn이 먼저 도입(yarn workspace)하기 시작했습니다. 후에 npm도 공식적으로 도입하게 되었죠.

내가 만든 패키지를 출시하지 않고 다른 패키지에서 사용하는 방법으로 yarn link도 있습니다. 다른 패키지를 symlink로 참조하는 방식은 같은데 workspace root 디렉토리의 node_modules가 아닌, consume하는 패키지의 node_modules에 불러올 패키지를 symlink 하는 것이죠.

yarn link를 하면 yarn 은 user의 홈 디렉토리밑에 설정 파일로 해당 link를 저장해두고, 사용하고 싶은 곳에서 해당 패키지를 yarn link [link했던 패키지]로 쓸 수 있게합니다. 이를 통해 consume 하는 패키지의 node_modules에 link한 패키지 폴더가 symlink로 생깁니다.

Summary

image

profile
더 나은 추상화로 더 아름답게

0개의 댓글