Skip to Content
DevPlugin플러그인 생성하기

플러그인 생성하기

본 문서에서는 plop 명령어를 사용하여 플러그인을 생성하는 방법을 설명합니다.

# cwd: root pnpm gen

CLI에서 plugin 제너레이터를 선택하면 아래 항목을 순서대로 입력합니다.

1) 기본 입력값

  • name: 플러그인 패키지 이름 (예: settings-store)
  • parent: 생성 위치 (기본값: plugins)
  • platform: 플랫폼 suffix
    • none(공통), web, tauri, desktop, mobile
    • windows, macos, linux, android, ios

생성 폴더명은 아래 규칙을 따릅니다.

  • 플랫폼이 없는 경우: {dashCase(name)}
  • 플랫폼이 있는 경우: {dashCase(name)}.{platform}

예: name=drpc, platform=desktop -> plugins/drpc.desktop

2) 템플릿 기능(features)

  • UI 패키지 (react, chakra-ui, react-icons): React 기반 UI 작성에 필요한 의존성과 기본 템플릿을 추가합니다.
  • 플러그인 설정: 설정 스키마/스토어/설정 UI 등록 템플릿을 추가합니다.
  • Tauri Core API: Tauri 환경에서 Core API를 사용할 수 있는 템플릿을 추가합니다.

플러그인 설정을 선택하면 내부적으로 UI 패키지도 자동 활성화됩니다.

3) 생성 후 자동 실행 작업

플러그인 파일 생성 후 아래 작업이 자동으로 실행됩니다.

pnpm install pnpm prettier -w {parent}/{folderName} cd apps/client && pnpm add --workspace @muvel-plugins/{folderName}
  • 루트 의존성 설치
  • 생성된 플러그인 폴더 코드 포맷팅
  • apps/client에 생성 플러그인을 워크스페이스 의존성으로 자동 연결

플러그인 기본 구조

  • plugin.ts
import { definePlugin } from "@muvel/core" import { pluginId } from "./constants" const plugin = definePlugin(pluginId, { // npm package name과 동일한 kebab-case 권장 name: "my-plugin", // 빌드 시 주입되는 플러그인 버전 version: __VERSION__, // 실행 순서/로딩 보장을 위해 의존 플러그인 ID를 명시 dependencies: [], // 다른 플러그인 또는 메인 앱이 사용할 API를 노출할 때 사용 api: {}, setup: async (mgr, ctx) => { // 초기화 로직 }, dispose: async () => { // 정리(cleanup) 로직 }, }) export default plugin
  • definePlugin(pluginId, config)로 플러그인 객체를 정의합니다.
  • name은 플러그인 식별용 문자열이며 템플릿 기본값처럼 kebab-case를 권장합니다.
  • version__VERSION__를 사용해 패키지 버전과 동기화합니다.
  • dependencies런타임 의존 플러그인 ID 목록입니다. 설정/슬롯/에디터 확장 등 다른 플러그인 API를 쓸 때 반드시 추가하세요.
  • api는 이 플러그인이 외부에 제공할 기능을 공개하는 영역입니다.
  • setup은 플러그인 로딩 시점 초기화, dispose는 언로드 시점 자원 해제를 담당합니다.

설정 플러그인 연동 예시

템플릿에서 enableSettings를 켜면 아래 흐름이 자동으로 들어갑니다.

import { settingsPluginId } from "@muvel-plugins/settings" import { settingsStorePluginId } from "@muvel-plugins/settings-store" import { settingsSchemaPluginId } from "@muvel-plugins/settings-schema" setup: async (mgr, ctx) => { const settingsApi = mgr.use(ctx, settingsPluginId) const storesApi = mgr.use(ctx, settingsStorePluginId) await storesApi.register(settings) settingsApi.register((data) => { // 설정 탭/아이템 등록 }) }
  • mgr.use(ctx, pluginId)로 의존 플러그인의 API를 가져옵니다.
  • settings-store에 스키마/기본값을 등록하고, settings에서 UI 항목을 주입합니다.
  • 이때 plugin.tsdependencies에 설정 관련 플러그인 ID 3개를 반드시 함께 선언해야 합니다.

플랫폼 분기

pnpm gen에서 플랫폼 suffix를 선택하면 대부분의 생성 작업은 자동으로 처리됩니다. 아래 내용은 동작 원리를 이해하기 위한 참고용입니다.

  • 플러그인 패키지는 @muvel-plugins/{id} 또는 @muvel-plugins/{id}.{platform} 형태로 존재할 수 있습니다.
  • 클라이언트는 실행 환경에 따라 suffix 후보를 만들고, 존재하는 패키지 중 가장 구체적인 것을 우선 선택합니다.
  • 후보가 없으면 공통 패키지(@muvel-plugins/{id})로 fallback 됩니다.

클라이언트 로더 기준 후보 우선순위 (apps/client/vite.config.ts)

  • 웹 환경: web -> 공통
  • Tauri 환경:
    • windows/darwin/linux 실행 시: {os} -> desktop -> tauri -> 공통
    • android/ios 실행 시: {os} -> mobile -> tauri -> 공통

예를 들어 drpc 플러그인이 아래처럼 존재한다면:

  • @muvel-plugins/drpc
  • @muvel-plugins/drpc.tauri
  • @muvel-plugins/drpc.desktop

데스크탑 Tauri에서는 drpc.desktop이 우선 선택되고, 없으면 drpc.tauri, 그다음 공통 버전을 사용합니다.

실무 팁

  • 특별한 플랫폼 코드가 필요 없으면 공통 플러그인 하나만 유지하는 것이 가장 단순합니다.
  • 플랫폼별 API(Tauri 네이티브, 모바일/데스크탑 전용 기능)를 쓸 때만 suffix 패키지를 추가하세요.
  • 분기 패키지를 추가한 경우에도 공통 패키지는 타입/공통 로직 공유용으로 유지하면 관리가 편합니다.
Last updated on