Back to Intellij Community

Remote Development

.agents/skills/remote-dev/SKILL.md

2025.3-rc-26.6 KB
Original Source

Remote Development

Basics

  • Structure modules using proper suffixes:
    • .frontend - UI code that runs on client side
    • .backend - computation code that runs on server side
    • .shared - code common to both frontend and backend
  • Use RPC for frontend-backend communication:
    • Create interfaces with @Rpc annotation in shared module
    • Implement interfaces on backend side
    • Use RemoteApiProvider to register implementations
    • All RPC methods must be suspend functions
    • All parameters and return values must be @Serializable
  • When working with backend objects on frontend:
    • Use ID serialization (e.g., VirtualFile.rpcId() and VirtualFileId.virtualFile())
    • For state synchronization, use StateFlow and Flow
  • Don't access on frontend:
    • PSI, indexes, file system (directly), VCS
    • Debugger, build systems, modules
    • Any backend-only services and APIs

Documentation

Detailed documentation in docs/IntelliJ-Platform/4_man/Remote-Development/:

External: Remote Development Overview (user documentation)

Creating Remote Development Modules

Module Types and Naming Conventions

  • Standard Module: intellij.<pluginGroup>.<frameworkName> Example: intellij.java.dsm, intellij.cidr.debugger

  • Remote Development Modules (split architecture):

    • Shared Module: intellij.<feature>
    • RPC Module: intellij.<feature>.rpc (for RPC interfaces)
    • Backend Module: intellij.<feature>.backend
    • Frontend Module: intellij.<feature>.frontend
    • Split Modules: intellij.<feature>.frontend.split, intellij.<feature>.backend.split

For Platform Modules

  1. Shared Module:
  • If working with existing module: Keep as is
  • For new module: Create in platform/feature/ following V2 plugin format
  1. RPC Module (if needed):
  • Create in platform/feature-rpc/ for RPC interfaces
  • Extract all @Rpc interfaces, DTOs, and supporting classes
  • Add dependencies on required serialization libraries
  • This module should have no implementation logic
  1. Backend Module:
  • Create in platform/feature/backend/
  • Include intellij.platform.feature.backend.xml in resources
  • Add dependency on intellij.platform.backend
  • Add to essential-modules.xml
  1. Frontend Module:
  • Create in platform/feature/frontend/
  • Include intellij.platform.feature.frontend.xml in resources
  • Add dependency on intellij.platform.frontend
  • Add to essential-modules.xml and intellij.platform.frontend.main.iml
  • Add to JetBrains Client's product-modules.xml
  1. Frontend Split Module (if needed):
  • Create in remote-dev/feature/frontend.split
  • Configure as V2 plugin module
  • Add to product-modules.xml and JetBrainsClientPlugin.xml

For Plugins in Monorepo

  1. Shared Module:
  • Keep shared code in main plugin module
  • Register in appropriate product-modules.xml for bundling
  1. RPC Module:
  • Create with .rpc suffix for RPC interfaces
  • Contains only RPC interfaces, DTOs, and supporting classes
  • Register in plugin.xml
  • Both frontend and backend modules depend on this
  1. Backend Module:
  • Create with .backend suffix as V2 plugin module
  • Add dependency on intellij.platform.backend and .rpc module
  • Register in plugin.xml
  1. Frontend Module:
  • Create with .frontend suffix as V2 plugin module
  • Add dependency on intellij.platform.frontend and .rpc module
  • Register in plugin.xml
  1. Frontend Split Module:
  • Create with .frontend.split suffix in appropriate location
  • Add dependency on intellij.platform.frontend.split
  • Register in plugin.xml

Reactive Programming Patterns for Remote Development

Key Patterns for Reactive State in Remote Development

The following patterns are essential when implementing reactive UI components for Remote Development:

  1. Backend StateFlow with Initial Value Transfer:
  • Use StateFlow for all mutable state on the backend
  • Add initial values in DTOs to avoid blocking calls on the frontend
  • Use .toRpc() extension to convert StateFlow to RpcFlow for RPC transfer
  1. Converting RpcFlow to StateFlow on Frontend:
  • Use toFlow().stateIn() pattern to convert RpcFlow to StateFlow
  • Always provide initial values from DTO to ensure immediate UI feedback
  • Use SharingStarted.Eagerly for UI components that need immediate updates
  1. Example: Reactive Breakpoint DTO

    kotlin
    // Flow-based DTO with initial values
    @Serializable
    data class XBreakpointDto(
      // Static properties
      val displayText: String,
      val iconId: IconId,
      val sourcePosition: XSourcePositionDto?,
      
      // Initial values for immediate use
      val initialEnabled: Boolean,
      val initialSuspendPolicy: SuspendPolicy,
      
      // Reactive flow fields
      val enabledState: RpcFlow<Boolean>,
      val suspendPolicyState: RpcFlow<SuspendPolicy>,
    )
    
  2. Example: Frontend Component with Reactive State

    kotlin
    class FrontendXBreakpointProxy(
      private val project: Project,
      private val cs: CoroutineScope,
      private val dto: XBreakpointDto
    ) {
      // Convert RpcFlow to StateFlow with initial values
      val enabled: StateFlow<Boolean> = dto.enabledState.toFlow()
        .stateIn(cs, SharingStarted.Eagerly, dto.initialEnabled)
        
      // Access current value from StateFlow
      fun isEnabled(): Boolean = enabled.value
    }