Frontend Development 14 min read

How Alibaba’s IDE Co‑Development Revamped Tree Components for Lightning‑Fast Performance

This article details the evolution of Alibaba’s IDE co‑development project, focusing on the design, data structures, event model, rendering, and performance optimizations of a high‑performance Tree component used for file navigation and other hierarchical views within the KAITIAN framework.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
How Alibaba’s IDE Co‑Development Revamped Tree Components for Lightning‑Fast Performance

IDE Co‑Development Deep Dive

In early 2019 the author joined Alibaba’s IDE co‑development project to build a public IDE core for the ecosystem. The Tree component, a core UI element for file, debug, and other views, was refactored twice; this article explains the latest high‑performance implementation in the KAITIAN framework.

What does a Tree component look like?

Typical Tree components consist of regular and collapsible nodes, with various decorations such as selection state and icons.

All examples below use a file‑tree as the reference.

Expected Data Structure

The basic data structure for a Tree is a flattened two‑dimensional array (FlattenedBranch) that stores each node’s position (index) and a unique identifier (node ID).

Event‑Driven Model

Parent‑child communication is handled through an event‑watcher interface, allowing the root to listen to any change in the tree.

<code>export interface ITreeWatcher {
  // Listen to watchEvent such as node move, create, delete
  onWatchEvent(path: string, callback: IWatcherCallback): IWatchTerminator;
  // Listen to all events
  on(event: TreeNodeEvent, callback: any);
  // Notify parent will change
  notifyWillChangeParent(target: ITreeNodeOrCompositeTreeNode, prevParent: ICompositeTreeNode, newParent: ICompositeTreeNode);
  // Notify parent changed
  notifyDidChangeParent(target: ITreeNodeOrCompositeTreeNode, prevParent: ICompositeTreeNode, newParent: ICompositeTreeNode);
  // Notify node will be disposed
  notifyWillDispose(target: ITreeNodeOrCompositeTreeNode);
  // Notify node disposed
  notifyDidDispose(target: ITreeNodeOrCompositeTreeNode);
  // Notify node will process watch event (used in file tree)
  notifyWillProcessWatchEvent(target: ICompositeTreeNode, event: IWatcherEvent);
  // Notify node did process watch event
  notifyDidProcessWatchEvent(target: ICompositeTreeNode, event: IWatcherEvent);
  // Notify expansion state will change
  notifyWillChangeExpansionState(target: ICompositeTreeNode, nowExpanded: boolean);
  // Notify expansion state did change
  notifyDidChangeExpansionState(target: ICompositeTreeNode, nowExpanded: boolean);
  // Notify children will resolve
  notifyWillResolveChildren(target: ICompositeTreeNode, nowExpanded: boolean);
  // Notify children resolved
  notifyDidResolveChildren(target: ICompositeTreeNode, nowExpanded: boolean);
  // Notify path changed
  notifyDidChangePath(target: ITreeNodeOrCompositeTreeNode);
  // Notify metadata changed
  notifyDidChangeMetadata(target: ITreeNodeOrCompositeTreeNode, change: IMetadataChange);
  // Notify branch updated
  notifyDidUpdateBranch();
  // Dispose function
  dispose: IDisposable;
}
</code>

All nodes hold a reference to this watcher, so a single

on

call at the root can capture changes across the entire tree, enabling features such as snapshots and undo/redo.

Node Rendering Model

The Tree is essentially a long list; each node renders with indentation to appear hierarchical. Hardware acceleration can be triggered by using

transform: translateY(0)

in CSS.

For large trees (thousands of nodes) only a subset of nodes is rendered at any time, with pre‑rendered buffers before and after the visible range to improve scrolling.

When the scroll reaches a boundary, the start index is updated and React’s diff algorithm re‑uses DOM nodes, achieving node recycling.

Data Service Layer

Each collapsible node must be able to fetch its children, which is provided by a

TreeService

implementation.

File‑tree nodes are defined by extending

CompositeTreeNode

(for directories) and

TreeNode

(for files):

<code>export class Directory extends CompositeTreeNode {
  constructor(
    tree: ITree,
    public readonly parent: CompositeTreeNode | undefined,
    public uri: URI = new URI(''),
    public name: string = '',
    public filestat: FileStat = { children: [], isDirectory: false, uri: '', lastModification: 0 },
    public tooltip: string,
  ) {
    super(tree, parent);
    if (!parent) {
      // Root node expands by default
      this.setExpanded();
    }
  }
}

export class File extends TreeNode {
  constructor(
    tree: ITree,
    public readonly parent: CompositeTreeNode | undefined,
    public uri: URI = new URI(''),
    public name: string = '',
    public filestat: FileStat = { children: [], isDirectory: false, uri: '', lastModification: 0 },
    public tooltip: string,
  ) {
    super(tree, parent);
  }
}
</code>

The service that resolves children and sorts nodes:

<code>export class FileTreeService extends Tree {
  async resolveChildren(parent?: Directory) {
    // ... fetch child nodes logic
  }
  sortComparator(a: ITreeNodeOrCompositeTreeNode, b: ITreeNodeOrCompositeTreeNode) {
    // ... node sorting logic
  }
}
</code>

The model separates data from rendering, allowing pre‑processing before the view consumes it.

<code>export class FileTreeModel extends TreeModel {
  constructor(@Optional() root: Directory) {
    super();
    // additional initialization if needed
  }
}
</code>

Rendering Function Example

<code>const renderFileTree = () => {
  if (isReady) {
    return (
      <RecycleTree
        height={filterMode ? height - FILTER_AREA_HEIGHT : height}
        width={width}
        itemHeight={FILE_TREE_NODE_HEIGHT}
        onReady={handleTreeReady}
        model={fileTreeModelService.treeModel}
        filter={filter}
      >
        {(props: INodeRendererProps) => (
          <FileTreeNode
            item={props.item}
            itemType={props.itemType}
            decorationService={decorationService}
            labelService={labelService}
            dndService={fileTreeModelService.dndService}
            decorations={fileTreeModelService.decorations.getDecorations(props.item)}
            onClick={handleItemClicked}
            onTwistierClick={handleTwistierClick}
            onContextMenu={handlerContextMenu}
          />
        )}
      </RecycleTree>
    );
  }
};
</code>

Performance Comparison

New file tree vs. old file tree performance.

New file tree vs. VS Code file tree performance.

After the second refactor, the new implementation outperforms both the previous version and VS Code’s tree component.

Key reasons for the performance gap:

React’s virtual DOM diff provides advantages over direct DOM manipulation in large‑file scenarios.

Flattened, non‑recursive data model reduces traversal cost.

Rendering model defined in the parent allows on‑demand allocation without redundant checks in the core tree.

Beyond Performance

The redesigned Tree component also offers extensibility: developers can quickly create SearchTree, GitTree, TodoTree, etc., by defining a model, node data, and rendering logic. Data‑model separation enables pre‑loading data before the page renders, improving first‑paint times. Combined with dependency injection, multiple tree instances can be generated from a single token.

Conclusion

The current KAITIAN framework’s Tree component has only undergone the first phase (file‑tree) of refactoring. Ongoing optimizations will eventually replace all tree‑like views in the framework, providing a more reusable and high‑performance foundation for future scenarios.

frontendperformance optimizationTypeScriptReacttree component
Taobao Frontend Technology
Written by

Taobao Frontend Technology

The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.