[Monoepo] Symlink

2024-01-23 hit count image

JavaScript로 개발할 프로젝트에서 모노레포(Monorepo)를 사용하기 위한 지식인 Symlink(Symbolic Link)에 대해서 알아보도록 하겠습니다.

개요

모노레포에서 여러 모듈들의 의존성을 연결할 때, Symlink를 활용하게 됩니다. 이번 블로그 포스트에서는 모노레포를 이해하기 위한 기본 지식인 Symlink(Symbolic Link)에 대해서 알아보도록 하겠습니다.

블로그 시리즈

이 블로그는 시리즈로 제작되었습니다. 다음 링크를 통해 다른 블로그 포스트도 확인해 보시기 바랍니다.

SymlinkSymbolic Link의 줄임말로, 파일 또는 디렉토리에 대한 바로가기(System shortcut)라고 생각하시면 됩니다.

Symlink는 주요 OS(macOS, Windows, Linux)에서 지원하는 기본 기능입니다. 또한 NodeJS의 패키지 매니저인 npmyarn에서도 지원하고 있습니다.

예제

npmyarn이 제공하는 Symlink 기능을 확인하기 위한 예제를 만들어 봅시다. 우선, 다음과 같이 폴더와 파일 구조를 생성합니다.

.
└── src/
    ├── module-a/
    │   ├── index.js
    │   └── package.json
    └── module-b/
        ├── index.js
        └── package.json

module-apackage.json은 다음과 같습니다.

// src/module-a/package.json
{
  "name": "module-a",
  "version": "1.0.0",
  "main": "index.js"
}

module-bpackage.json은 다음과 같습니다.

// src/module-b/package.json
{
  "name": "module-b",
  "version": "1.0.0",
  "main": "index.js"
}

그리고 module-bindex.js는 다음과 같습니다.

// src/module-b/index.js
console.log('module-b');

마지막으로 module-aindex.js는 다음과 같습니다.

// src/module-a/index.js
console.log('module-a');

require('module-b');

이렇게 파일을 구성한 후, 다음 명령어를 실행하여 모듈을 잘 불러오는지 확인합니다.

node src/module-a/index.js

그럼 다음과 같이 에러가 발생하는 것을 확인할 수 있습니다.

module-a
node:internal/modules/cjs/loader:1073
  throw err;
  ^

Error: Cannot find module 'module-b'
Require stack:
- /Users/deku/temp/temp/src/module-a/index.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1070:15)
    at Module._load (node:internal/modules/cjs/loader:923:27)
    at Module.require (node:internal/modules/cjs/loader:1137:19)
    at require (node:internal/modules/helpers:121:18)
    at Object.<anonymous> (/Users/deku/temp/temp/src/module-a/index.js:3:1)
    at Module._compile (node:internal/modules/cjs/loader:1255:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1309:10)
    at Module.load (node:internal/modules/cjs/loader:1113:32)
    at Module._load (node:internal/modules/cjs/loader:960:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/Users/deku/temp/temp/src/module-a/index.js' ]
}

Symlink 기능을 확인하기 위해 module-b 폴더로 이동합니다.

cd src/module-b

이동한 후, 다음 명령어를 실행하여 Symlink를 사용할 준비를 합니다.

npm link
# yarn link

이후, module-b를 사용하는 module-a 폴더로 이동합니다.

cd ..
cd module-a

module-a 폴더로 이동하였다면, 다음 명령어를 사용하여 module-b에 대한 Symlink를 생성합니다.

npm link module-b

이렇게 link 명령어를 실행하면 다음과 같이 module-a 폴더의 node_modules 폴더가 생성되고 modules-bSymlink가 생성된 것을 확인할 수 있습니다.

.
├── index.js
├── node_modules
│   └── module-b -> ../../module-b
└── package.json

Symlink 폴더는 module-b를 복사한 것이 아니라 module-b 자체와 연동이 되어 있습니다. 따라서 src/module-b/index.js 파일을 수정하면 src/module-a/node_modules/module-b/index.js 파일도 같이 수정이 되며, 반대로 src/module-a/node_modules/module-b/index.js 파일을 수정하면 src/module-b/index.js 파일도 같이 수정이 됩니다.

이제 프로젝트의 루트 폴더(/)로 이동한 후, 다음 명령어를 실행하여 모듈을 잘 불러오는지 확인합니다.

# cd ../..
node src/module-a/index.js

그럼 다음과 같이 문제없이 잘 실행되는 것을 확인할 수 있습니다.

module-a
module-b

이제 src/module-b/index.js 파일 내용을 다음과 같이 수정합니다.

console.log('module-b!!!!');

수정후, src/module-a/node_modules/module-b/index.js 파일을 열어보면 위에서 수정한 내용이 반영되어 있는 것을 확인할 수 있습니다. 물론, 다음 명령어를 실행하면, 변경된 내용이 잘 출력되는 것을 확인할 수 있습니다.

node src/module-a/index.js

module-a
module-b!!!!

완료

이것으로 모노레포를 사용하기 위한 기초 지식인 Symlink에 대해서 알아보았습니다. 모노레포에서 여러 모듈들의 의존성을 연결할 때, Symlink를 활용하므로 이번 블로그 포스트를 통해 Symlink를 이해해 두면 모노레포를 사용하는데 도움이 될 것입니다.

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통
Posts