Building your own Custom Editors with Kogito Tooling NPM packages

Tiago Bento
kie-tooling
Published in
7 min readNov 22, 2019

With the first alpha release of kogito-tooling published to NPM, we’re happy to announce that you can too build VSCode and Chrome extensions that feature a custom editor. If you haven’t seen them in action take a look at this blog post announcing the VSCode extension and this other one announcing the GitHub Chrome extension.

To leverage what we’ve built and create your own custom extensions, you should know the three basic packages we’ll need:

  1. @kogito-tooling/vscode-extension — to configure the VSCode extension itself.
  2. @kogito-tooling/chrome-extension — to configure the GitHub Chrome extension itself.
  3. @kogito-tooling/microeditor-envelope — to configure the iframe in which your custom editor will live.

Before we begin, you should know that we have a Template repository on GitHub to help your get started. Simply click the green button saying “Use this template” and a copy of this repository will be created for you. You can clone it on your machine and start browsing the files. To help you navigate, here’s an overview:

  • /packages/chrome-extension-pack-simple-react — Configures and builds a GitHub Chrome extension using @kogito-tooling/chrome-extension and @kogito-tooling/microeditor-envelope.
  • /packages/vscode-extension-pack-simple-react — Configures and builds a VSCode extension using @kogito-tooling/vscode-extension and @kogito-tooling/microeditor-envelope.
  • /packages/simple-react-editors — Exports a simple React-based editor to be used by both of the extensions.

The simple-react-editors package is the most important one, since that’s where your editor lives. By implementing the interfaces from @kogito-tooling/core-api , this editor can be used by both extensions without any adaptations. Since here’s what’s interesting, we’ll begin explaining what’s inside simple-react-editors.

Building and running

Go to kogito-tooling-examples root dir on a terminal window and run yarn run init && yarn run build:prod, You can now open the chrome-extension-pack-simple-react/dist folder as an unpacked Chrome Extension (see instructions here and install the .vsix file from dist/vscode-extension-pack-simple-react on VSCode. This editor is for .txt files, so open one to see it in action!

Chrome Extension with a simple React-based custom editor
VSCode Extension with a simple React-based custom editor

Customizing the editor

Now that you have seen it work, let’s make some changes. We’ve previously built it with yarn run build:prod command because we wanted to generate the final artifacts. Now that we’re in a development workflow, we should use yarn run build:fast, this will generate source-maps and speed up the build.

Let’s start with the VSCode extension. Open packages/vscode-extension-pack-simple-react on VSCode and go to Debug > Start without debugging on the menu. This will open a new VSCode instance with the extension installed. On SimpleReactEditor.tsx, add a “color: red” property to the style prop and rebuild the project. Re-run VSCode and open a .txt file. You’ll that the text on the editor is now red. That’s it, the editor is a standard React component.

Understanding the programming model

But how does this React component communicate with the VSCode extension? How does VSCode know that when opening a .txt file, this editor should open? You can answer the first question by looking at the props that this React component receives. One is a method that exposes the React component instance so that VSCode can imperatively call methods, and the messageBus parameter, which is used to send messages to VSCode. The communication goes both ways. Check the autocompletion for methods you can call on messageBus.

Now for the second question, we have to look at other classes. The API defined in @kogito-tooling/core-api is implemented on SimpleReactEditorInterface.tsx. This is the class that holds an instance of the React component of our editor. Creating an instance of this class is a job for a Factory, implemented in SimpleReactEditorsFactory.tsx. Here there’s another concept. The LanguageData. This is a “initialisation” parameter that VSCode passes to Editor. Since our example is very simple, we don’t use it, but we could. Notice that the LanguageData interface has a type property. This is used to switch between editors when you have more than one type on the same extension.

This is all important for VSCode to know how to create editors, but the first question is still unanswered. To tell VSCode that a certain extension should open a certain editor, we define our Routes. See SimpleReactEditorsRoutes.ts. We define a Map of string to LanguageData and this LanguageData will be passed to the Factory so that we can use its values to open our editor. Since our example is very simple (and it should be like this for the most extensions), we don’t really have much there. There are some properties on the SimpleReactEditorsRoutes.ts class just to illustrate.

Ok! Now we know everything about defining our own Editor classes. Let’s see how to configure a VSCode extension to use this editor.

Configuring and packing VSCode extensions

Open packages/vscode-extension-pack-simple-react on VSCode. On the src folder, you’re going to see two directories. They are very important, since they separate the extension “backend” from its “frontend”. Before we talk about them, let’s take a look at the package.json first. There, you’ll see a “contributes” property. This property tells VSCode that this extension will provide features for the defined languages. In the case of our example extension, .txt. The “activationElements” is also very important, since we’ll perform a check to see if we should run the extension at any event.

Detail of the VSCode extension ‘package.json’ file

When we tell VSCode that we’ll provide features for the .txt language, we can now configure this extension to actually open the editor we built on simple-react-editors. To do that, we have to configure the extension “backend”. Go to src/extension/extension.ts. There you’ll see an activate method. That’s part of the VSCode extension lifecycle and it gets called when an activation event happens. Since we’re “listening” to any activation event, this method will be called right away. Everything we have to do is in this file. We’ve done all the hard work for you on the @kogito-tooling/vscode-extension package. You just have to configure it!

Detail of the VSCode extension ‘extension.ts’ file

The extensionName parameter should have the same values that are on the package.json, on the format “{publisher}.{name}”. The webviewLocation parameter is a relative path from where we’re going to load the JavaScript of the editor will be. That’s where the @kogito-tooling/microeditor-envelope does its job. It wraps the editor we built and abstracts the communication complexity for us, so that we can talk to VSCode without having to worry how (more on that later). The context parameter should be exactly your extension’s context and the router parameter must be a Router implementation. You can use the DefaultVsCodeRouter for almost everything. If you need a more complex setup, you can take a look at the documentation. See how we passed our Routes to the Router? Everything is starting to connect.

Now for the “frontend”. The way that VSCode enables us to build a custom editor is by WebViews. It’s essentially like a tab on a browser, but inside VSCode. For every file that we open, a WebView will be created. That’s why we have to create an index file for this WebView. We want it to open our editor! Go to src/webview/index.ts. That’s where we’re going to configure our MicroEditorEnvelope. Just like with the @kogito-tooling/vscode-extension package, all the complexity is hidden from us, we just have to pass some parameters. In this case, the container and busApi parameters are always going to be the same. We just need to configure the editorFactory, in this case, our SimpleReactEditorsFactory. And that’s it. Everything is connected.

Detail of the VSCode extension ‘envelope/index.ts’ file

Configuring and packing GitHub Chrome extensions

The exact same concepts we learned for VSCode applies to Chrome extensions as well. We have a “backend” defined on src/contentscript.ts and a “frontend” defined on envelope/index.ts. Keep in mind that the background.ts is necessary, so you must have it in order for the extension to work properly. The static/index.html file is also needed. You can customize it, although we don’t recommend that. In VSCode, the extension properties are defined on package.json, but on Chrome Extensions you must have a manifest.json file. There you can change the extension name, version etc.

Conclusion

@kogito-tooling/* packages help you build extensions for VSCode and Chrome that will improve the experience of editing complex files. We built it primarily for BPMN and DMN files, but you can extend our programming model to provide editor for any file formats you’d like. I hope you enjoy building extensions and stay tuned, we have more news coming soon!

--

--