Dr. Stefan Winkler
freier Softwareentwickler und IT-Berater

This article is part of a series to help newcomers to get started with Eclipse Theia development by setting up a local docker-based development environment for Theia.

After setting up a Theia Development environment (either with Docker Dev Environments or VS Code Remote Containers), the next step is to actually write some code.

This article provides a good description of the process of creating a first extension with the help of a yeoman code generator. This code generator actually takes care of creating both the extension code and a custom theia product. So we don’t even have to use the package.json from my previous articles. But since we have already a development container set up, we will just reuse the existing environment here.

So let’s just ignore the existing files, open a Terminal in our Docker workspace and create a new folder hello-world. Then we change into the new folder with and invoke the code generator:

$ mkdir hello-world
$ cd hello-world
$ yo theia-extension

In the dialog that follows, we select the Hello World extension and just accept the proposed name.

Now, first the code generator and then yarn will do their thing again to get the new Theia instance set up and resolved, and in the end, we can start theia by executing yarn start:browser.

In the Theia application that is running now, note that we have a new menu item Say Hello in the Edit Menu. When selecting this item, a message in the lower right says Hello World.

Let’s try to modify the message. But first, in order to have our our code changes be picked up, we need to tell the TypeScript compiler to watch the code. Watching means, that any change to the code in a .ts file is directly picked up and compiled to JavaScript. For developers being used to the Eclipse IDE, this is the equivalent of activating Project > Build Automatically. Open up a New Terminal, and–as we will only make changes to the hello-world extension–change to the folder of our hello-world extension and execute yarn watch from there. Restricting the watch to the extension folder will save resources, as only the files in that folder need to be watched.

Note: If yarn watch complains about insufficient file handles for watching ("System limit for number of file watchers reached“), then you need to adjust the number of available handles in /etc/sysctl.conf on your host system (e.g., for me it was the boot2docker vm in which I run my docker-machines). For details, see this StackOverflow answer.

Now find and open the hello-world-contribution.ts file in the VS Code editor and change the message in line 19 to Hello changed world!. Save the file, and you will briefly see the console blink as it picks up the changes and reports "Found 0 errors".

Finally, we need to reload the Theia page in the browser if it still open. The reason is that the code that produces the message was compiled from TypeScript to JavaScript, but as it is frontend code, it has actually been loaded and is executed in our web browser.

Debugging

Executing and changing code is one thing, but sooner or later, we will want to inspect what is going on at runtime by using a debugger. So, let us create a breakpoint at the line in which we have changed the message and try to hit it.

Note that, as stated above, this line is part of the frontend code, so we need to attach a debugger to the frontend, which means the browser. So, we could use the builtin development tooling that is part of all web browsers, nowadays. But the browser does not know about TypeScript and the TypeScript compiler; it only knows about JavaScript which it loads and executes. Consequently, we would not be able to hit the breakpoint set in VS Code. Instead, we would need to find out which line in JavaScript relates to the line in TypeScript, and set a breakpoint in this line in the browser’s development tools. In practice this seems to be cumbersome and error-prone. 

Correction: Actually, the typescript sources and source maps are included by webpack when assembling the assets to be downloaded to the browser. This means that in the browser development tools, there should be a webpack:// node visible which contains the .ts files; and it is actually possible to set breakpoints there and use the browser development tools to debug Theia in the browser directly. So if you are familiar with the browser development tools, or encounter issues when trying to attach VS Code to the browser as described below, this is a good alternative to debug the frontend.

Luckily, VS Code also has a frontend debugging feature that is able to attach to a debug server built into Google Chrome or Microsoft Edge browsers. The setup is quite simple: Switch to the Run and Debug view in the Activity Bar and click the Create launch.json File link. Then select the Chrome environment and adapt the file to contain

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "pwa-chrome",
      "request": "launch",
      "name": "Launch Chrome against localhost",
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}/hello-world/hello-world",
      "runtimeExecutable": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"      
    }
  ]
}

Note that the url property needs to set so it points to the port at localhost on which Theia is running. The webRoot property needs to point to the actual path in the workspace where the code of the extension is located. This is used to connect the breakpoint position to the browser’s debug server. If this property is set to a wrong location, you will see it marked as Unbound while the debugger is run.

Also note that the runtimeExecutable might not be necessary, but for me it was needed–otherwise launching the browser executable would fail without giving a specific error message.

Now, all we have to do is make sure that Theia (i.e., yarn start:browser) is still running and start the Launch Chrome against localhost Debug Configuration. Now click on the „Say Hello“ menu item again, and the execution should suspend and the debugger should show the stack, variables, etc. and we can use the debugger to step through the code as it is executed.

That’s it for today. As the hello-world extension does not include any backend code, we will postpone backend debugging to a future article.