Appearance
First Steps
설치
모노레포 내에서 workspace:*로 참조한다:
json
{
"dependencies": {
"@repo/electron-ipc": "workspace:*"
}
}Peer dependency로 electron이 필요하다:
json
{
"devDependencies": {
"electron": ">=28"
}
}최소 예제
서비스 하나와 컨트롤러 하나로 구성된 최소 앱을 만든다.
1단계: Contract 정의
ts
// greeting/contract.ts
import { contract, handle } from '@repo/electron-ipc/contract';
export const greetingContract = contract({
handles: {
greet: handle<[string], string>('greet'),
},
});2단계: 서비스 정의
ts
// greeting/service.ts
import { Injectable } from '@repo/electron-ipc';
@Injectable()
class GreetingService {
greet(name: string): string {
return `Hello, ${name}!`;
}
}3단계: 컨트롤러 정의
메서드 이름을 contract 키와 동일하게 정의하면 @Controller(contract)가 자동으로 IPC 채널에 바인딩한다.
ts
// greeting/controller.ts
import { Controller, inject } from '@repo/electron-ipc';
import { greetingContract } from './contract';
import { GreetingService } from './service';
@Controller(greetingContract)
class GreetingController {
private readonly greeting = inject(GreetingService);
// contract.handles.greet 키 → 'greet' 채널 자동 바인딩
greet(name: string): string {
return this.greeting.greet(name);
}
}TS가 @Controller(greetingContract)를 통해 클래스 형태를 자동으로 검사한다. greet 메서드를 누락하거나 시그니처가 contract와 어긋나면 IDE에서 빨간 줄로 잡힌다.
4단계: 모듈 구성
ts
// greeting/module.ts
import { Module } from '@repo/electron-ipc';
import { GreetingService } from './service';
import { GreetingController } from './controller';
@Module({
providers: [GreetingService],
controllers: [GreetingController],
})
class GreetingModule {}5단계: 메인 윈도우 Provider
ts
// window/service.ts
import { BrowserWindow } from 'electron';
import {
Injectable,
type OnMainWindowCreate,
} from '@repo/electron-ipc';
@Injectable()
export class WindowService implements OnMainWindowCreate {
onMainWindowCreate(): BrowserWindow {
return new BrowserWindow({
width: 800,
height: 600,
webPreferences: { preload: '/path/to/preload.js' },
});
}
}
// window/module.ts
import { Module } from '@repo/electron-ipc';
import { WindowService } from './service';
@Module({ providers: [WindowService], controllers: [] })
export class WindowModule {}6단계: 앱 부트스트랩
ts
// main.ts
import { createApp, SenderGuard } from '@repo/electron-ipc';
import { GreetingModule } from './greeting/module';
import { WindowModule } from './window/module';
const app = createApp({
modules: [WindowModule, GreetingModule],
guards: [new SenderGuard()],
});
app.start();7단계: Preload Bridge
ts
// preload.ts
import { contextBridge } from 'electron';
import { createBridge } from '@repo/electron-ipc/bridge';
import { greetingContract } from './greeting/contract';
const contracts = { greeting: greetingContract } as const;
const api = createBridge(contracts);
contextBridge.exposeInMainWorld('api', api);8단계: 렌더러에서 호출
ts
// renderer.ts
import { createService } from '@repo/electron-ipc/service';
import { greetingContract } from './greeting/contract';
const contracts = { greeting: greetingContract } as const;
const service = createService(window.api, contracts);
const result = await service.greeting.greet('World');
console.log(result); // "Hello, World!"파일 구조
src/
├── greeting/
│ ├── contract.ts
│ ├── service.ts
│ ├── controller.ts
│ ├── module.ts
│ └── index.ts
├── main.ts
├── preload.ts
└── renderer.ts다음 단계
- Modules — 모듈로 기능을 구성하는 방법
- Providers — DI 컨테이너와 inject() 상세
- Controllers — IPC 핸들러 정의
- Contract System — contract 시스템 상세