"Electron 앱과 웹 앱을 동시에 개발한다면 모노레포로 코드를 공유하세요" — 비즈니스 로직, 타입, 유틸리티를 한 곳에서 관리할 수 있습니다.


모노레포 구조

PLAINTEXT
my-project/
├── pnpm-workspace.yaml
├── package.json
├── packages/
│   ├── shared/              # 공유 코드
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── types.ts
│   │   │   ├── utils.ts
│   │   │   └── api.ts
│   │   └── tsconfig.json
│   ├── desktop/             # Electron 앱
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── main/
│   │   │   ├── preload/
│   │   │   └── renderer/
│   │   └── electron.vite.config.ts
│   └── web/                 # 웹 앱
│       ├── package.json
│       └── src/
└── tsconfig.base.json

pnpm workspace 설정

YAML
# pnpm-workspace.yaml
packages:
  - 'packages/*'
JSON
// packages/shared/package.json
{
  "name": "@myapp/shared",
  "version": "1.0.0",
  "main": "src/index.ts",
  "types": "src/index.ts"
}
JSON
// packages/desktop/package.json
{
  "name": "@myapp/desktop",
  "version": "1.0.0",
  "dependencies": {
    "@myapp/shared": "workspace:*"
  }
}
JSON
// packages/web/package.json
{
  "name": "@myapp/web",
  "version": "1.0.0",
  "dependencies": {
    "@myapp/shared": "workspace:*"
  }
}

공유 코드 설계

TYPESCRIPT
// packages/shared/src/types.ts
export interface User {
  id: string;
  name: string;
  email: string;
}

export interface Note {
  id: string;
  title: string;
  content: string;
  createdAt: Date;
  updatedAt: Date;
}
TYPESCRIPT
// packages/shared/src/utils.ts
export function formatDate(date: Date): string {
  return new Intl.DateTimeFormat('ko-KR').format(date);
}

export function slugify(text: string): string {
  return text.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
}
TYPESCRIPT
// packages/shared/src/api.ts
// HTTP 클라이언트는 환경(브라우저/Node.js)에 따라 다를 수 있으므로
// 인터페이스만 공유
export interface ApiClient {
  get<T>(path: string): Promise<T>;
  post<T>(path: string, data: unknown): Promise<T>;
}

export class NoteService {
  constructor(private api: ApiClient) {}

  async getAll(): Promise<Note[]> {
    return this.api.get('/notes');
  }

  async create(title: string, content: string): Promise<Note> {
    return this.api.post('/notes', { title, content });
  }
}

Electron 앱에서 공유 코드 사용

TYPESCRIPT
// packages/desktop/src/renderer/App.tsx
import { formatDate, type Note } from '@myapp/shared';

function NoteList({ notes }: { notes: Note[] }) {
  return (
    <ul>
      {notes.map(note => (
        <li key={note.id}>
          <h3>{note.title}</h3>
          <span>{formatDate(note.updatedAt)}</span>
        </li>
      ))}
    </ul>
  );
}

루트 스크립트

JSON
// 루트 package.json
{
  "scripts": {
    "dev:desktop": "pnpm --filter @myapp/desktop dev",
    "dev:web": "pnpm --filter @myapp/web dev",
    "build:desktop": "pnpm --filter @myapp/desktop build",
    "build:web": "pnpm --filter @myapp/web build",
    "build:all": "pnpm -r build",
    "test:all": "pnpm -r test"
  }
}

면접 포인트 정리

  • 모노레포로 Electron/웹 앱 간 타입, 유틸리티, 비즈니스 로직 공유
  • workspace:*로 로컬 패키지를 의존성으로 연결
  • 공유 코드는 환경 독립적으로 설계 (Node.js/브라우저 모두 동작)
  • pnpm의 --filter 옵션으로 특정 패키지만 빌드/실행

모노레포를 다뤘으면, 다음은 Electron Fiddle을 알아봅시다.

댓글 로딩 중...