Platform logo

JetBrains Platform

Plugin and extension development for JetBrains products.

JetBrains IDE 中 WSL 支持的演进

Read this post in other languages:

JetBrains IDE 对 WSL 的支持已有多年历史。随着时间推移,我们的各款产品逐渐形成了多种 WSL 使用方式。不同入口可能采用不同的底层架构,带来的使用体验也各不相同。

从 2026.2 版本开始,我们推荐统一使用一种入口。在 IntelliJ IDEA、WebStorm 和 PhpStorm 中,打开位于 WSL 内的项目时,IDE 会以我们所称的原生模式运行。IDE 仍是 Windows 应用程序,而 WSL 内的一个轻量级代理会代其处理文件和进程。

下文将介绍原生模式的工作原理、我们的 WSL 集成方案如何演进至今,以及在先后尝试过另外三种方案后,我们为何确信它是承载您工作的正确基础。

在 IDE 中支持 WSL 需要什么

我们先设想一种理想状态:用户在 Windows 上操作 IDE,而 IDE 能在 WSL 内无缝工作。实际而言,“无缝”意味着您可以针对 Linux 环境中的项目使用 IDE 的任何功能,包括终端、运行和调试配置、性能分析等。不仅如此,整个过程还必须尽量减少延迟,让编码体验快速而自然,就像项目文件和 IDE 本身位于同一个操作系统环境中一样。

我们将回顾应对这一挑战的历程:从最早由 IDE 通过 9P 传输协议与 WSL 交互的实现开始,随后介绍远程开发和 WSLg,最后探讨目前 IDE 使用 WSL 的首选方式——原生模式。

迈向在 WSL 中原生运行 IDE

9P 文件系统访问与 GeneralCommandLine

IDE 要正常工作,首先需要访问项目最基本的组成部分——普通文件。这正是 9P 文件系统协议发挥作用的地方。它提供了一种机制,让 Windows 端的进程能够访问 WSL 内的文件。实际上,IDE 针对项目执行的文件 I/O(扫描、索引、归档访问及类似操作)都会通过基于 9P 的文件系统层路由到 Linux 虚拟机。

解决文件访问后,下一个挑战是进程执行。IDE 在 Windows 上运行时,必须能够使用正确的 Linux 路径、工作目录、可执行文件、环境变量和实参来调用 WSL 内的工具。IDE 内部的 GeneralCommandLine 类通过规范化 WSL 环境中的命令执行来完成这项工作。

这种架构虽然使 IDE 能够操作 WSL 环境,却在文件访问和进程执行两方面引入了显著的取舍。

众所周知,9P 协议存在一些问题,主要原因如下:

  • 符号链接处理受限 – 9P 无法通过 \\wsl$ 向 Windows 正确公开 Linux 符号链接。因此,IDE 可能检测到某个条目,却无法解析或索引其链接的目录树。这会影响 pnpm 工作区、Python 虚拟环境、PHP Composer 路径仓库以及其他依赖符号链接的环境。
  • Microsoft Defender 扫描 – 通过 9P 进行实时访问扫描,可能会让 WSL 文件读取延长数十秒。
  • 延迟和吞吐量下降 – 基于 9P 的文件系统访问会增加延迟,吞吐量也可能显著下降,尤其是在涉及大量小文件的工作流中。索引等 IDE 核心操作正属于这种模式:它们会生成大量独立请求,经由 9P 跨越 Windows 与 WSL 虚拟机的边界。

GeneralCommandLine 方面同样面临挑战。由于开发者必须在整个代码库中处理 WSL 特有的执行语义,这条处理管线带来了额外的维护负担。

因此,这种方案越来越难以扩展和维护,并持续暴露出符号链接处理和性能方面的问题。

使用 WSLg 在 WSL 内运行 IDE

如果反过来,让 IDE 本身位于 WSL 内、靠近它所处理的项目,会怎样?这正是 WSLg 的用武之地。它可以运行 Linux GUI 应用程序,并将其图形输出直接集成到 Windows 桌面。

我们不推荐 WSLg 方案,原因如下:

  • 从产品角度看,如果 IDE 显示在 Windows 上,最好让它表现为 Windows 原生应用,而不是投射到 Windows 桌面中的 Linux GUI 应用。这样可以更好地掌控 IDE 体验,并避免依赖额外的 GUI 远程层。
  • 在 WSLg 配置中,IDE 可能通过原生 Wayland 路径运行,JetBrains Runtime 会使用 WLToolkit 对接 WSLg 的 Wayland 合成器。该路径在渲染、弹出窗口、窗口管理、输入法和桌面集成方面存在已知限制。

我们从未围绕这种配置打造一流的产品体验。尽管从技术上讲可以通过 WSLg 运行 IDE,但它从未被视为首选方向,也没有专门提供开箱即用的安装或引导流程。它仍然是一种临时变通方法,而不是受支持的 IDE 工作流。

远程开发方案

另一种方案是远程开发,它从不同角度应对文件访问和进程执行这两个根本挑战。它没有将基于 Windows 的 IDE 跨越 WSL 边界扩展,而是把 IDE 后端移入 WSL,仅将客户端保留在 Windows 上。这种架构更直接地解决了底层集成问题,但也带来了另一组取舍。

这种配置的主要技术挑战,是在建立并维持两部分通信的同时,确保 UI 准确反映用户操作,并让 IDE 继续作为一个协调一致的整体运行。与此同时,将后端置于 WSL 内也有明显优势:可以直接访问 Linux 文件和进程。

在这种配置中,IDE 的两个部分通过 JetBrains RD 协议通信。该协议以结构化、双向的方式传输 IDE 模型和事件,使瘦客户端与 IDE 后端在逻辑上保持同步;索引、分析、构建、调试、VCS 操作等所有繁重工作均在后端完成。

客户端则负责:

  • 渲染所有窗口和编辑器,并处理用户输入。
  • 镜像通过 RD 协议从后端接收的项目和编辑器状态,并将编辑、光标移动、重构命令、调试操作等发送回后端。
  • 加载 UI 级插件。

然而,这种拆分架构不容忽视的问题是成本。IDE 后端本身就是一个重量级组件,需要额外约 2 GB 磁盘空间,还需要时间在 WSL 内下载和安装。拆分也会带来固有的性能损耗,因为 UI 事件状态、用户输入和其他交互数据必须在本地客户端与后端之间持续传输。

它还增加了开发开销,因为代码必须拆分为客户端和服务器两部分。如果某些模块未被拆分,就可能导致高度动态的 UI 出现延迟和冻结。因此,相关工程工作会成为一项持续且不可避免的成本。

原生模式与 IJent 代理

目前的设计已集成到我们的大多数 IDE 中,它汇聚了这项工作的成果,并解决了早期 WSL 方案的许多不足。

为了在不依赖 9P、GeneralCommandLine 或其他次优通信机制的情况下访问 Linux 文件系统、进程和其他环境资源,我们开发了名为 IJent 的轻量级代理。由于它专为 IDE 场景设计,我们可以根据自身需求塑造其行为、协议和能力。

IDE 与 IJent 共同组成一对客户端–服务器。它看起来与远程开发模型相似,但服务器组件要轻量得多,同时也更加通用。将 IJent 安装到 WSL 环境只是多种可选配置之一;同一模型也适用于 Docker 和 Dev Container。

选择这一技术栈后,我们得以解决一系列问题:

  • Rust 实现 – Rust 可以保持可执行文件轻量。代理不使用 Java/Kotlin,从而避免在容器或 WSL 内引入额外的运行时依赖项。
  • 传输层 – Stdio 为所有环境提供了可移植且防火墙友好的传输方式。WSL 上的 Hyper-V 套接字提供了更快的路径,对于大型或大量文件系统传输尤其有利。
  • 正确的文件系统语义 – IJent 在目标环境内代表 IDE 执行文件系统操作。因此,包括符号链接在内的路径解析会遵循正确的 Linux 语义,而不是由 9P 中转。第三方插件也能受益于该模型,因为它们的文件操作同样通过 IJent 路由。

EelApi:面向任何环境的统一接口

要让 IDE 充分受益于 IJent,IDE 端也需要做出改变。EelAPI 由此登场。

EelApi 是一个 API,旨在为所有编写 IDE 相关代码的人(包括插件作者和平台贡献者)抽象掉本地环境与远程环境之间的差异。有了 EelApi,IDE 所操作的底层环境将不再重要,也无需在代码中显式处理这些问题。从这个意义上说,EelApi 与平台无关,IDE 无需感知自己是在本地、WSL、Docker 还是 Dev Container 中工作。

总体而言,IJent 实现了 EelApi 接口,为 EelApi 向 IDE 和插件公开的能力提供实际功能。

如果您想详细了解 EelApi,并阅读相关实践入门,请参阅文章Dev Container 的故事:面向插件作者介绍 EelApi.

这在实际使用中意味着什么

目前有两种方式可以打开 WSL 项目:

  • 在 IntelliJ IDEA、WebStorm 和 PhpStorm 中直接打开项目即可使用原生模式。目前,越来越多 IDE 正在采用 IJent 和 EelApi 架构。
  • 欢迎屏幕上的远程开发入口仍然可用,但已不再是打开 WSL 项目的推荐方式。

我们进行了性能测试,对比 9P 模式与原生模式。结果显示,新方案具有明显的性能优势:

冷启动基准测试

IJent 将大型 WSL 项目的等待时间缩短 38%

9P IJent
可开始工作
18.5 s
11.5 s

减少 38%

扫描项目树
8.1 s
3.7 s

减少 54%

索引文件
10.8 s
8.4 s

减少 22%

读取文件内容
12.2 s
5.7 s

减少 53%

适用场景:首次冷启动打开 spring-framework,其中包含 23 个子项目和 8,191 个源文件。对于源文件较少的小型项目,未观察到可测量的差异。

测试配置:Windows 11、WSL 2、Ubuntu 24.04 和 IntelliJ IDEA Ultimate 263.SNAPSHOT 环境下五次测量运行的中位数。

除了性能之外,这种架构还将 WSL 开发纳入非本地环境开发这一更广泛的语境,使它们能够采用相同的底层模型。我们在 Docker 和 Dev Container 方面的工作已经由同一个 IJent 代理提供支持。

感谢阅读,也感谢所有帮助我们走到今天的反馈。欢迎在下方评论区告诉我们,原生模式在您的项目中表现如何。


本博文英文原作者:Kristina Pchelintseva

本文由 AI 辅助翻译,并经人工审校。如发现任何问题,欢迎在评论区留言指正。

Discover more