DEV Community

Cover image for Introducing Sapling, A VS Code Extension For Traversing Your React Component Hierarchy
Jordan H
Jordan H

Posted on

Introducing Sapling, A VS Code Extension For Traversing Your React Component Hierarchy

React is a powerful tool for building your frontend applications, but at scale navigating the hierarchy of your components may be painful. Sapling aims to change that.

Modern React applications are huge. Facebook is built with more than 50,000 components. Even the parent-child relationships and the passed-down props of fairly simple apps can become unintuitive to manage. Good file organization can help, but it doesn't reflect the component structure that stands at the core of your application's functionality.
When you need to determine which props are available to the component you're working on, you need to navigate to that component's parent file. Even when your organizational paradigm clusters similar components together, the hierarchical relationships remain unclear, and you still have to find the exact source of any props you've passed down. The industry standard to this problem is great file organization, but there is still no simple way to remind yourself of the big picture at a glance. We built Sapling to change that.

Sapling is a VS Code Extension that creates an interactive component dependency tree embedded within the VS Code sidebar. Each node on the tree provides a summary of available props and a nav button to quickly open the corresponding file. Its straightforward UI makes it easy to read and intuitive to use, and its highly responsive behavior immediately updates every time you save. Sapling's visual cues are also easy to follow: the node that corresponds to your workspace's active file will have bold text, and if Sapling finds a Javascript syntax error or faulty import statement, it highlights the broken component with a warning color. There is even a convenient icon that will tell you which components you've connected to the Redux store.

An image showing a hierarchy tree of React components in the VS Code sidebar.

Sapling was designed with the user in mind. Sapling has a powerful memory, and will retain its expanded state even between workspace sessions; when your application is a couple hundred components large, you don't have to manually expand the tree to your current working component. Moreover, if your application uses third-party components like Material-UI or React-Router, you can choose whether Sapling should display them by toggling them on and off in VS Code's Extension settings. For added convenience, Sapling can be built from any React file in your client, and if you'd prefer to simplify the current display, Sapling provides a helpful status bar button called "Build Tree" that will rebuild the tree with the active file as the root.

So how does Sapling do all this? Sapling is built using the VS Code Extension API, along with the VS Code Webview API, integrating it seamlessly into your VS Code IDE.

When you select the root file for your component hierarchy, Sapling reads it and uses @babel/parser to create an abstract syntax tree (AST) from the file contents. Sapling then processes the AST, detecting the child React components of the root file, the files these components are defined in, their props etc. Sapling then recursively parses the child component files, generating a node tree data structure that represents the component hierarchy of your React application.

From there, the node tree is handed to the Sapling Webview - a web application that is itself built using React components. The Webview generates the interactive hierarchy tree in the VS Code sidebar, allowing you to navigate your React application in a much more intuitive way than the traditional VS Code file browser.

An image showing the user hovering over an icon to display a list of props available at that component.

Sapling uses the same transcompiler used by companies like Discord and Kickstarter to parse React components written with ES6 imports, JSX tags, Typescript and TSX tags, and elements invoked using the 'component' or 'child' property of React Router components. This gives it both flexibility and robustness, necessary attributes of an open source product that has even more features in mind for the future. Sapling is planning on accommodating components imported and invoked as arrays, and on providing an indication of prop inheritance to help developers keep track of attributes passed down with changed labels. We also know that using path aliases, for example in a bundler like webpack, is very useful for large and complex codebases, so we are looking to have Sapling resolve these paths.

More generally, although the VS Code IDE is one of the most popular IDEs among developers, those who prefer other IDEs shouldn't be left out. Similarly, while React is certainly the most popular front end library, frameworks such as Angular and Vue are also used extensively. We would love to be able to provide intuitive component hierarchy navigation for developers using other popular frameworks.

If you want to install the extension, search for Sapling in your VS Code Extensions side panel, or go directly to the Sapling page on the VS Code Marketplace.

If you are interested in contributing to this open source product, visit our Sapling GitHub page to get started!

Follow the members of Team Sapling at the links below:
Charles Gutwirth
Jordan Hisel
Lindsay Baird
Paul Coster

Cover photo by Jan Huber on Unsplash.

Top comments (3)

Collapse
 
pengeszikra profile image
Peter Vivo

Nice idea, but in my complex case this is failed. Even when I try a minimal react app I just saw the main component, the dynamical created Item is missing from tree.

import React, {useReducer} from 'react';

const init = {
  foo: 42
}

const reducer = (state,{type, props}) => {
  switch(type) {
    case 'foo': return {...state, foo:payload};
    default: return state;
  }
}

const Item = ({content}) => <div>{content}</div>;

export default () => {

  const [state, dispatch] = useReducer(reducer, init)

  const {foo} = state;


  return (
    <pre>-- basic Sapling ::{foo}--
    {['alfa','beta','epsilon'].map((content, key) => <Item content={content} key={key}/>)}
    </pre>
  );
}
Enter fullscreen mode Exit fullscreen mode

But in my complex react program this extension seems useful if it is works, but I don't get too much information about error, just I saw my main component red. Maybe I use frequently unorthodox pipeline operator in my codebase, and useReducer is behind useSagaReducer ?

Collapse
 
jocella profile image
Jordan H

Hi Peter! Thanks for checking out Sapling! Sapling currently works best when only one React component is defined in each file, since we originally envisioned it for file navigation. For your more complex program, please open an issue on our GitHub with an example of the files you are trying to parse and we will take a look!

Collapse
 
klvenky profile image
Venkatesh KL

That's some thing of pretty good use. Really a wonderful idea.
I don't work on react much these days, but will check it out & share with my peers.
Cheers 🙌🙌🙌🙌