DEV
[React/React-native] Workspace
음대생개발자
2024. 11. 30. 16:06
Workspace
정의
workspace는 여러 패키지를 하나의 프로젝트에서 효율적으로 관리하기 위한 설정을 말한다.
특징
- workspace로 사용되는 패키지를 node_modules에 설치하여 관리한다.
- 공통되는 의존성과 설정 등이 프로젝트 Root에서부터 공유된다.
- Hoisting: 공통 의존성을 루트 수준에서 관리하여, 중복 설치를 줄이고 일관성을 유지한다.
- 개별 관리: 개별 패키지에서만 가지고 있는 의존성은 패키지 내부에서만 독립적으로 관리한다.
- 즉, 프로젝트 Root에서 npm 설치 시 공통의 모듈을 설치하며, 패키지 내부에서 독립적으로 필요한 모듈은 각 내부의 패키지에서 개별적으로 모듈을 설치한다.
// 폴더 구조
├── node_modules
│ ├── package1
│ ├── package2
│ ├── package3
├── package-lock.json
├── package.json
├── modules
├── package 1
│ ├── node_modules
│ ├── package.json
├── package 2
│ ├── package.json
├── package 3
│ ├── package.json
...
├── src
- 서로 다른 패키지 간의 참조도 가능하다. (패키지 간의 종속성 설정 가능)
// 예시 (package.json)
{
"dependencies": {
"ct-library-credential": "workspace:*", // 버전을 신경 쓰지 않고 워크스페이스 내부의 패키지를 사용
"ct-library-http-client": "workspace:1.0.0" // 워크스페이스 내부 패키지의 특정 버전을 사용
}
}
- workspace 사용시 자동으로 symbolic link (npm link)가 연결된다.
- symbolic link : node_modules 에 설치된 workspace의 패키지는 기존의 패키지가 존재하는 경로를 참조하여 node_modules에서 연결된다.
- 기존 패키지와 연결됨에 따라 패키지의 변경사항이 실시간으로 반영된다.
사용 목적
1. 각 패키지의 버전 관리 : 각 패키지의 종속성 버전을 자동으로 추적, 업데이트 가능
2. 공통 의존성 관리: 중복 설치를 줄임으로써 의존성 설치 및 빌드의 효율성 증가
3. 공통 설정 관리: 린트, 테스트, 빌드 스크립트 등을 중앙화 해 통합된 개발 환경 제공
생성 방법
1. 프로젝트 Root 설정
- 프로젝트에서 workspace로 사용하려고 하는 패키지의 경로를 Root의 package.json, workspace 속성에 추가
// package.json
{
"name" : "YOUR_PROJECT_NAME",
"version" : "1.0.0",
...
"workspace" : ["modules/package1", "modules/package2"] // "modules/*"
}
2. Typescript, ESlint 등 사용시 config 설정
- workspace 패키지 안에서 Root의 config 파일을 바라보기 때문에 ts, lint 등의 설정이 있는 경우에 충돌이 일어날 수 있다.
- 해당 패키지 안의 config 파일에서 추가 설정이 필요
- extends : 기본 설정을 공유
- 기본 설정을 공유 및 상속하면서 패키지 별 커스터마이징 가능
// typescript
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist", // 빌드 결과 경로
"baseUrl": "./src", // 경로 설정
"strict": false // 패키지별 개별 설정 덮어쓰기
},
"include": ["src/**/*"] // 포함 파일
}
// eslint 설정도 동일
{
"extends": "../../.eslintrc", // 루트 설정 상속
}
** React 추가 설정 : Babel-loader
React는 webpack에서 src 외부 경로를 기본적으로 읽지 못하므로, workspace 모듈 지원을 위한 추가 설정이 필요하다.
1. Webpack 설정 적용: 커스터마이징 된 설정을 덮어씌우기 위해 react-app-rewired 라이브러리 설치
npm install react-app-rewired
2. config-overrides.js 파일 추가
module.exports = function override(config, env) {
...
// src 외부 workspace 모듈 지원
config.module.rules.push({
test: /\.(js|jsx|ts|tsx)$/,
include: [
path.resolve(__dirname, "modules/package1"), // workspace 모듈 경로 (필요에 따라 수정)
path.resolve(__dirname, "modules/package2"),
],
loader: require.resolve("babel-loader"),
options: {
presets: ["react-app"],
plugins: ["react-refresh/babel"],
},
});
config.resolve.symlinks = true;
return config
}
3. Script 수정
// package.json
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
}
** React-native 추가 설정 : Metro bundler
React native가 사용하는 Metro 번들러는 심볼릭 링크를 기본적으로 지원하지 않기 때문에, 종종 workspace 모듈을 읽지 못해 추가 설정이 필요하다.
// metro.config.js
const path = require('path');
const { getDefaultConfig } = require('@react-native/metro-config');
const workspaceRoot = path.resolve(__dirname, 'module/package1');
const projectRoot = __dirname;
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = getDefaultConfig(projectRoot);
// 1. Watch all files within the monorepo
config.watchFolders = [workspaceRoot];
// 2. Let Metro know where to resolve packages, and in what order
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
];
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
config.resolver.disableHierarchicalLookup = true;
module.exports = config;
회사에서는 다른 레포에서 관리하는 패키지들을 서브모듈로서 관리하였는데,
그 때는 작업자마다 서브모듈 버전이 다른 경우가 생기기도 했었고 업데이트 되었는지도 잘 파악이 안되었다.
workspace를 사용하면서 버전에 종속성을 걸면, 이런 문제점들은 없어질 수 있어서 관리하기 편해질 것 같다.