Patrick Desjardins Blog
Patrick Desjardins picture from a conference

Using TypeScript and React to create a Chrome Extension Developer Tool

Posted on: 2018-08-09

I recently have a side project that I am dogfooding at Netflix. It is a library that handles HTTP request by acting as a proxy to cache requests. The goal is to avoid redundant parallel call and to avoid requesting data that is still valid while being as simple as possible. It has few configurations, just enough to make be able to customize the level of cache per request if required. The goal of this article is not to sell the library but to expose information about how I created a Chrome's extension that listens to every action and collects insight to help the developer understanding what is going on underneath the UI. This article will explain how I used TypeScript and React to build the UI. For information about how the communication is executed behind the scene, from the library to Chrome, you should refer to this previous article.

Chrome's extension for developer tool requires a panel which is an HTML file. React with Creat-React-App generate a static HTML file that bootstrap React. There is a flavor of create-react-app with TypeScript that works similarly, but with TypeScript. In both case, it generates a build in a folder that can be published as a Chrome's extension.

The build folder content can be copied and pasted into your distribution folder along with the manifest.json, the contentScript.js, and background.js files that has been discussed in the communication article between your code and Chrome extension.

What is very interesting is, you can develop your Chrome's extension without being inside the developer tool. By staying outside, it increases your development velocity because you do not need to build which use Webpack -- this is slow. It also requires to close and open the extension which at the end consume time for every little change. Instead, you can mock the data and leverage the hot-reload mechanism of create-react-app by starting the server (npm run start) and run the Chrome's extension as we independent website until you are ready to test the full fledge extension with communication coming from outside your extension.

Running the website with creat-react-app is a matter of running a single command (start), however, you need to indicate to the panel's code that you do not expect to receive a message from Chrome's runtime. I handle the two modes by passing an environment variable in the command line. In the package.json file I added the following code:

 "start": "REACT_APP_RUNENV=web react-scripts-ts start", 

Inside the React, app.tsx file, I added a check that decides whether to subscribe to Chrome's runtime message listener or to be injected with fake data for the purpose of web development.

if (process.env.REACT_APP_RUNENV === "web") { 
  // Inject fake data in the state 
} 
else { 
  // Subscribe to postMessage event 
} 

Finally, using TypeScript and React is a great combination. It clarifies the message that is expected at every point in the communication but also simplifies the code by removing any potential confusion about what is required. Also, React is great in term of simplification of the UI and the state. While the Data Access Gateway Chrome's extension is small and does not use Redux or another state management, it can leverage the React's state at the app.tsx. It means that to save and load the user's data is a matter of simply dumping the state in the Chrome's localstorage and to restore it -- that is it. Nothing more.

public persistState(): void { 
   const state = this.state; 
   chrome.storage.local.set({ [SAVE_KEY]: state }); 
} 
   
public loadState(): void { 
  chrome.storage.local.get([SAVE_KEY], (result) => { 
    if (result !== undefined && result[SAVE_KEY] !== undefined) { 
      const state = result[SAVE_KEY] as AppState; 
      this.setState(state); 
    } 
  }); 
} 

To summarize, a Chrome extension can be developed with any front-end framework. The key is to bring the build result along with the required file and make sure you connect in the manifest.json the index generated. React works well, not only because it generates for you the entry point as a simple HTML file which is the format required by Chrome's extension. TypeScript is not a hurdle because the file generated by the build is JavaScript, hence no difference. React and TypeScript is a great combination. With the ability of developing the extension outside Chrome's extension you can gain velocity and have a product rapidly in a shape that can be used by your user.