Make a simple File Tree for Electron using ES6 and Node

Jake Lunn
5 min readMar 14, 2019

Bonus: Make it work with React, too.

Working in Electron can be a blast, but sometimes the functionality you want just isn’t fully there. Electron relies on you utilizing the ‘fs’ (File System) node module for interacting with the native file system — which lacks some of the expected depth that you might be used to if you’re coming from languages like C# or Java for interacting with local directories and files.

This article is going to focus on creating a simple ES6 class that you can use to have an object which contains a list of all files and subdirectories starting at a root path.

This implementation isn’t designed for performance, and will be a little slow for massive directories. It can easily be built upon and manipulated to be better for performance, though. The purpose is to show you a bare-bones implementation so that you can expand on it for your needs.

First, what would an ideal object of a directory look like? To keep things simple, your file tree object might look like:

The example above is pointing at a directory (C:\Documents) which contains a file and a subdirectory (which also has a file). The object is recursive, meaning it can contain infinite arrays of itself. We only have 3 simple properties which conveys enough information to navigate the file structure: path (the full path to the file), name (for easy display purposes), and an items array (in-case the item is a directory). This is your class, so feel free to add any extra information to it as you see fit. That’s the fun part of classes.

Before we start, if you’re wanting to code-along, go ahead and scaffold a new project. I’m going to scaffold a react app using the following command:

npx create-react-app electron-filetree-example

Next I’ll install Electron. Don’t forget to first cd into the new electron-filetree-example directory that our npx command created.

npm i --save electron

Once installed, create a new file called electron.js in your src directory. Inside of this file we’ll have the following:

Then we’ll update package.json and add 2 lines:

The added lines are line 11 and line 17. These allow node to launch our electron app.

Now to test it out, run these two commands:

npm start
npm run electron

You should now have a running electron app.

Our basic electron app.

Now we’ll make the class.

I created a folder in the src directory called Utilities, and in that folder I created the file FileTree.js.

-/ src
-/ Utilities
- FileTree.js

Our FileTree class will keep it simple. It’ll have a constructor in-which we pass the path to our local directory, and from there it’ll crawl the directory and list all of the files, subdirectories, and all of the subdirectories’ subdirectories and so on.

We’ll end up using FS, which we’ll need to import from Electron (which is getting it from Node). Here’s our simple starter class:

Our constructor will accept the path to the initial directory, and optionally its name (which we won’t use, yet).

Also take note of line 1:

var remote = window.require('electron').remote;

window.require is a workaround for an issue between browserify (which we use as the result of our scaffolding) and Electron. This issue is documented here.

We won’t need to add much to our class to get the basic functionality we’re looking for. Our class will need a recursive function that scans the directory — and then continues scanning all subdirectories until it runs out of subdirectories to scan. This is simpler than it sounds.

We’ll make this function static, as well, so it can be called without needing to instantiate the class.

  1. We start by creating an empty array to hold our list of FileTree objects.
  2. Using fs readdir, we read the directory and get the name of each item in the directory.
  3. We create a new FileTree object for each item we find in the directory. If this object is a directory itself, then we call our static readDir function recursively to read the subdirectory. If it’s a file, we just push it to the array and move along.
  4. By the end of this process we’ll have an array of FileTrees that drills all the way down until it can’t find any more subdirectories.

Last, we’ll simply add a function that calls our static function and starts building the tree. We’ll just call it build. Our finished class should end up looking like below.

To use our class, we’ll simply create a new FileTree and pass the directory path into the constructor. Then we can call the build() function to build the tree. This is also useful if we want to “refresh” the tree if a file has changed, by simply calling the build() function again we can update the entire tree.

I took the liberty of updating App.js so we can test the new FileTree class out.

I removed the default HTML and just added a simple button. The button’s onClick triggers a handleOpenFolder function which uses electron’s dialog API to open a file browser. The file browser will pull back the path to a directory that the user selects, and then we instantiate a new FileTree class using that path. I then call fileTree build and log the results.

If you’re running the electron app, you can hit ctrl+shift+i to open the dev tools. Navigate to the console window and give it a shot. You should get a nice little console output with a file tree, similar to below.

Happy little tree

Another cool thing: Since each of our FileTree instances has the build() function, we could refresh specific folders instead of entire folders if we want to save on performance. If the user saves a file in a subdirectory, just build() the subdirectory instead of the entire tree.

Using React, we can also display it using a little recursive action. Below I’ll go over creating a simple unordered list of our file tree.

Let’s return to FileTree.js and add a function for returning an unordered HTML list. In the spirit of recursion, we’ll make it recursive as well.

Simple enough, this function creates an unordered list with a list item for each file. If the file has items (meaning it’s a directory), it will call the function again to render another unordered list within the list item. As a result you get a nice file tree.

For ease of use, add a non-static renderUnorderedList function that calls our static one and passes the file list.

Don’t forget to add an import statement for React so we can return the new JSX we added. Your updated FileTree.js should look like this:

And from our App.js file, we’ll call our new function if our FileTree isn’t empty/null. We’ll also set the fileTree in our state instead of logging it to the console.

Now if you open a folder using the button, you should have a nice little unordered list appear.

--

--