diff --git a/src/docs/authoring_extensions.md b/src/docs/authoring_extensions.md index 1863735..176db2a 100644 --- a/src/docs/authoring_extensions.md +++ b/src/docs/authoring_extensions.md @@ -4,83 +4,31 @@ title: Authoring an Extension # Authoring Theia Extensions -This guide will walk you through the process of creating Theia extensions and deploying them in your Theia-based application. Please make sure to be aware of the [different available extension mechanisms](/docs/extensions/) of Theia (Plugins vs. Extensions) before you continue reading. +This guide will walk you through the process of creating Theia extensions and deploying them in your Theia-based application. Please make sure to be aware of [how to create a Theia based application](/docs/composing_applications/) and the [different available extension mechanisms](/docs/extensions/) of Theia (Plugins vs. Extensions) before you continue reading. As an example, we are going to add a menu item _Say hello_ that displays a notification "Hello world!". This article is guiding you through all the necessary steps. -## Theia’s Architecture - -A Theia app is composed of so-called _extensions_. An extension provides a set of widgets, commands, handlers, etc. for a specific functionality. Theia itself ships a number of extensions, e.g. for editors, terminals, the project view etc. Each extension resides in its own npm package. - -Theia defines a plethora of contribution interfaces that allow extensions to add their behaviour to various aspects of the application. Just search for interfaces with the name `*Contribution` to get an idea. An extension implements the contribution interfaces belonging to the functionality it wants to deliver. In this example, we are going to implement a `CommandContribution` and a `MenuContribution`. Other ways for extensions to interact with a Theia application are via one of the various _services_ or _managers_. - -In Theia, everything is wired up via [dependency injection](/docs/services_and_contributions#dependency-injection-di). An extension defines one or more dependency injection modules. This is where it binds its contribution implementations to the respective contribution interface. The modules are listed in the `package.json` of the extension package. An extension can contribute to the frontend, e.g. providing a UI extension, as well as to the backend, e.g. contributing a language server. When the application starts, the union of all these modules is used to configure a single, global dependency injection container on each, the frontend and the backend. The runtime will then collect all contributions of a specific kind by means of a multi-inject. - ## Prerequisites Prerequisites information are available from the [Theia repository](https://github.com/eclipse-theia/theia/blob/master/doc/Developing.md#prerequisites). ## Project Layout -We are going to create a monorepo (a repository containing multiple npm packages) named `theia-hello-world-extension` containing three packages: `hello-world-extension`, `browser-app` and `electron-app`. The first contains our extension, the latter two the Theia applications to run our extension in browser and electron mode. We are going to use `yarn` instead of `npm`, because it allows to structure such monorepos into workspaces. In our case, each workspace contains its own `npm` package. Common dependencies of these packages are 'hoisted' by `yarn` to their common root directory. We are also going to use `lerna` to run scripts across workspaces. - -To ease the setup of such a repository we have created a [code generator](https://www.npmjs.com/package/generator-theia-extension) to scaffold the project. It will also generate the `hello-world` example. Run it using - -```bash -npm install -g yo generator-theia-extension -mkdir theia-hello-world-extension -cd theia-hello-world-extension -yo theia-extension # select the 'Hello World' option and complete the prompts -``` - -Let's have look at the generated code now. The root `package.json` defines the workspaces, the dependency to `lerna` and some scripts to rebuild the native packages for browser or electron. - -```json -{ - "private": true, - "scripts": { - "prepare": "lerna run prepare", - "rebuild:browser": "theia rebuild:browser", - "rebuild:electron": "theia rebuild:electron" - }, - "devDependencies": { - "lerna": "2.4.0" - }, - "workspaces": [ - "hello-world-extension", "browser-app", "electron-app" - ] -} -``` - -We also got a `lerna.json` file to configure `lerna`: - -```json -{ - "lerna": "2.4.0", - "version": "0.1.0", - "useWorkspaces": true, - "npmClient": "yarn", - "command": { - "run": { - "stream": true - } - } -} -``` +Please refer to the [guide to create Theia applications](/docs/composing_applications/) to get familiar with the default project layout and generate a Theia project with the example 'hello world' extension using our [Yeoman Generator](https://github.com/eclipse-theia/generator-theia-extension) -## Implementing the Extension +## A Custom Theia Extension -Next let's look at the generated code for our extension in the `hello-world-extension` folder. Let’s start with the `package.json`. It specifies the package’s metadata, its dependencies to the (bleeding edge) Theia core package, a few scripts and dev dependencies, and the theia-extensions. +Let's look at the generated code for our extension in the `hello-world` folder. Let’s start with the `package.json`. It specifies the package’s metadata, its dependencies to the Theia core package, a few scripts and dev dependencies, and the theia-extension itself. Please note that the following listing might be outdated, please always refer to the generated examples from our [Yeoman Generator](https://github.com/eclipse-theia/generator-theia-extension) The keyword `theia-extension` is important: It allows a Theia app to identify and install Theia extensions from `npm`. ```json { - "name": "hello-world-extension", + "name": "hello-world", "keywords": [ "theia-extension" ], - "version": "0.1.0", + "version": "0.0.0", "files": [ "lib", "src" @@ -90,7 +38,7 @@ The keyword `theia-extension` is important: It allows a Theia app to identify an }, "devDependencies": { "rimraf": "latest", - "typescript": "latest" + "typescript": "~5.4.5" }, "scripts": { "prepare": "yarn run clean && yarn run build", @@ -105,10 +53,13 @@ The keyword `theia-extension` is important: It allows a Theia app to identify an ] } ``` +As you can see, the extension is a dedciated package that just depends on Theia. However, as the extension contributes features to our application, it needs to be wired a runtime. To achive this in a modular way, in Theia, everything is wired up via [dependency injection](/docs/services_and_contributions#dependency-injection-di). An extension defines one or more dependency injection modules. This is where it binds its contribution implementations to the respective contribution interface. The modules are listed in the `package.json` of the extension package. An extension can contribute to the frontend, e.g. providing a UI extension, as well as to the backend, e.g. contributing a language server. When the application starts, the union of all these modules is used to configure a single, global dependency injection container on each, the frontend and the backend. The runtime will then collect all contributions of a specific kind by means of a multi-inject. + +The last property `theiaExtensions` in the packahe.json above is where we list the JavaScript modules that export the DI modules defining the contribution bindings of our extension. In our case, we only provide a frontend capability (a command and a menu entry). Analogously, you could also define contributions to the backend, e.g. a language contribution with a language server. -The last property `theiaExtensions` is where we list the JavaScript modules that export the DI modules defining the contribution bindings of our extension. In our case, we only provide a frontend capability (a command and a menu entry). Analogously, you could also define contributions to the backend, e.g. a language contribution with a language server. +Theia defines a plethora of contribution interfaces that allow extensions to add their behaviour to various aspects of the application. Browse the documentation section 'Platform Concepts & APIs' or search for interfaces with the name `*Contribution` to get an idea. An extension implements the contribution interfaces belonging to the functionality it wants to deliver. In this example, we are going to implement a `CommandContribution` and a `MenuContribution`. Other ways for extensions to interact with a Theia application are via one of the various _services_ or _managers_. -In the frontend module we export a default object that is a [InversifyJS `ContainerModule`](https://github.com/inversify/InversifyJS/blob/master/wiki/container_modules.md) with bindings for a command contribution and a menu contribution. +In the frontend module we export a default object that is a [InversifyJS `ContainerModule`](https://github.com/inversify/InversifyJS/blob/master/wiki/container_modules.md) with bindings for a command contribution and a menu contribution. Please see our [dependency injection guide](/docs/services_and_contributions/) for more details. ```typescript export default new ContainerModule(bind => { @@ -160,36 +111,28 @@ export class HelloWorldMenuContribution implements MenuContribution { } ``` -## Executing the Extension In the Browser +## Adding Extensions to a Theia application -Now we want to see our extension in action. For this purpose, the generator has created a `package.json` in the folder `browser-app`. It defines a Theia browser application with a couple of statically included extensions, including our `hello-world-extension`. All remaining files in this directory have been auto-generated by `yarn` calling the `theia-cli` tool during the build, as defined in the scripts section. +To make sure your extension is included in your Theia application, list it as a dependency in your browser or electron app, e.g. like this: ```json { + "private": true, "name": "browser-app", - "version": "0.1.0", + "version": "0.0.0", "dependencies": { "@theia/core": "latest", - "@theia/filesystem": "latest", - "@theia/workspace": "latest", - "@theia/preferences": "latest", - "@theia/navigator": "latest", - "@theia/process": "latest", - "@theia/terminal": "latest", - "@theia/editor": "latest", - "@theia/languages": "latest", - "@theia/markers": "latest", - "@theia/monaco": "latest", - "@theia/messages": "latest", - "hello-world-extension": "0.1.0" + ... + "hello-world": "0.0.0" }, "devDependencies": { "@theia/cli": "latest" }, "scripts": { - "prepare": "theia build", + "bundle": "yarn rebuild && theia build --mode development", + "rebuild": "theia rebuild:browser --cacheRoot ..", "start": "theia start", - "watch": "theia build --watch" + "watch": "yarn rebuild && theia build --watch --mode development" }, "theia": { "target": "browser" @@ -197,38 +140,10 @@ Now we want to see our extension in action. For this purpose, the generator has } ``` -Now we have all pieces together to build and run the application. -To run the browser app, enter: - -```bash -cd browser-app -yarn start -``` - -Point your browser to . Then choose _Edit > Say Hello_ from the menu: A message "Hello World!" should pop up. - -## Executing the Extension In Electron - -The `package.json` for the Electron app looks almost the same, except for the name and the target property. - -```json -{ - "name": "electron-app", - ... - "theia": { - "target": "electron" - } -} -``` - -Before running the electron app, you additionally have to rebuild some native modules: - -```bash -yarn rebuild:electron -cd electron-app -yarn start -``` - ## Deploying the Extension -If you want to make your extension publicly available, we recommend publishing it to npm. This can be achieved by calling `yarn publish` from the extension package's directory. Of course, you need a valid account for that. +To run the extension, you have two options: +1. Have your extension as part of a monorepo containing a Theia-based application importing your extension (like the structure created by the Yeoman Generator) +2. Publish the extension with `yarn publish` and consume it from your Theia-based application + +See [*Executing the Browser Application*](/docs/composing_applications/#executing-the-browser-application) and [*Executing the Extension in Electron* for more details*](/docs/composing_applications/#executing-the-extension-in-electron) for adding extensions to the dependencies of a Theia-based application and running it. diff --git a/src/docs/authoring_vscode_extensions.md b/src/docs/authoring_vscode_extensions.md index a78b9c2..2c5d448 100644 --- a/src/docs/authoring_vscode_extensions.md +++ b/src/docs/authoring_vscode_extensions.md @@ -244,3 +244,13 @@ To also enable debugging from your development IDE (VS Code), you need to setup ] } ``` + +## Troubleshooting + +### Plugins not appearing + +If no plugins are available in the running Theia instance, it may be that you need to tell Theia where to find the downloaded plugins. +The example above sets the `--plugins` switch in the `start` command which should be sufficient. +However, if running `theia start` directly, you can alternatively set an environment variable to achieve the same thing: + + export THEIA_DEFAULT_PLUGINS=local-dir:plugins \ No newline at end of file diff --git a/src/docs/composing_applications.md b/src/docs/composing_applications.md index db70ef8..67b80bd 100644 --- a/src/docs/composing_applications.md +++ b/src/docs/composing_applications.md @@ -5,13 +5,13 @@ title: Build your own IDE/Tool # Build your own IDE/Tool -This guide will teach you how to build your own Theia-based application. The guide will demonstrate how to configure your own application composed of existing or new Theia extensions, and any VS Code extensions you want bundled in your application by default. Please get familiar with the [extension mechanisms of Theia](/docs/extensions/) in case you are not already. -This guide describes the manual steps to build a Theia-based product, there are two ways to avoid this manual set-up: +This guide will teach you how to create your own Theia-based application. The guide will demonstrate how to configure your own application composed of existing or new Theia extensions, and any VS Code extensions you want bundled in your application by default. Please get familiar with the [extension mechanisms of Theia](/docs/extensions/) in case you are not already. +We provide two entry points for creating your own Theia-based application. -- [Theia Extension Yeoman generator](https://github.com/eclipse-theia/generator-theia-extension): Generates Theia-based products along with example extensions. -- [Theia IDE](/#theiaide): A tool based on the Theia Platform that can be used as a template for creating installable desktop applications based on Theia. [Learn how to extend and adapt the Theia IDE](/docs/blueprint_documentation/). +- [Theia Yeoman generator](https://github.com/eclipse-theia/generator-theia-extension): Generates Theia-based applications along with example extensions. +- [Theia IDE](/#theiaide): A tool based on the Theia Platform that can be used as a template for creating installable desktop applications based on Theia with additional features such as automatic updates, branding, etc.. [Learn how to extend and adapt the Theia IDE](/docs/blueprint_documentation/). -We still recommend reading the manual guide first, it allows you to understand the structure of a Theia-based project. +If you are new to Theia, we recommend starting with the first option, as it is quicker and simpler to get started with. If you want to create a full product based on Theia, you can later on switch to using the Theia IDE without loosing your existing work by integrating your extensions into your custom version of the Theia IDE. In this guide, we will demonstrate how to get started with the [Yeoman Generator](https://github.com/eclipse-theia/generator-theia-extension). ## Requirements @@ -19,154 +19,141 @@ The detailed list of prerequisites is located at the main Theia repository: - [Prerequisites](https://github.com/eclipse-theia/theia/blob/master/doc/Developing.md#prerequisites) -## Setup +## Theia’s Architecture -Start with creating a new empty directory and moving into it: +A Theia app is composed of so-called Theia extensions. Each extension resides in its own npm package. +An extension provides a set of features, e.g. widgets, commands, handlers, etc. for a specific functionality. The Theia project itself ships a number of extensions for common features, e.g. for editors, terminals, the project view etc. You can resue these existing extensions by just adding them to you custom Theia application. Additionally, you can add arbitrary VS Code extensions to your application, again for reusing existing features already available, such as Git support. Finally, you can then extend and customize your Theia application with your own features, which you can implement as [Theia extensions or VS Code extensions](/docs/extensions). +In this guide, we will create a Theia application with a number of existing Theia extensions and one (generated) custom Theia extension. Please also refer to our [documentation on how to create custom Theia extensions](/docs/authoring_extensions) to learn more on how to create your own Theia extensions. Finally, also see [our guide on how to add VS Code extensions to your custom Theia application](/docs/authoring_vscode_extensions). - mkdir my-app - cd my-app +## Project Layout -Create `package.json` in this directory: +We are going to create a monorepo (a repository containing multiple npm packages) named `my-theia-app` containing three packages: `browser-app`, `electron-app` and `hello-world-extension`. The first two contain the custom Theia applications to run in browser and electron mode. The 'hello-world' package contains a generated example extension, that adds a feature to our custom Theia application. This extension can serve as a starting point for you to add your own custom features via Theia extensions. + +We are going to use `yarn` instead of `npm` (Theia default). We are also going to use `lerna` to run scripts across workspaces. + +To ease the setup of such a repository we have created a [Yeoman generator](https://github.com/eclipse-theia/generator-theia-extension) to scaffold the project. It will also generate the `hello-world` example extension. Run it using + +```bash +npm install -g yo generator-theia-extension +mkdir my-theia-app +cd my-theia-app +yo theia-extension # select the 'Hello World' option and complete the prompts +``` + +After creating the project structure, the Yeoman generator will also install the required dependencies, so it might take a minute to complete. +Let's have look at the generated code now. The root `package.json` defines the workspaces, the dependency to `lerna` and some scripts to build, start and watch the project for browser or electron. Please note that the excerpt on this page might be outdated, please use the Yeoman generator to generate the files listed below to get the latest version. ```json { "private": true, - "dependencies": { - "@theia/callhierarchy": "latest", - "@theia/file-search": "latest", - "@theia/git": "latest", - "@theia/markers": "latest", - "@theia/messages": "latest", - "@theia/mini-browser": "latest", - "@theia/navigator": "latest", - "@theia/outline-view": "latest", - "@theia/plugin-ext-vscode": "latest", - "@theia/preferences": "latest", - "@theia/preview": "latest", - "@theia/search-in-workspace": "latest", - "@theia/terminal": "latest" + "engines": { + "yarn": ">=1.7.0 <2", + "node": ">=18" + }, + "scripts": { + "build:browser": "yarn --cwd browser-app bundle", + "build:electron": "yarn --cwd electron-app bundle", + "prepare": "lerna run prepare", + "postinstall": "theia check:theia-version", + "start:browser": "yarn --cwd browser-app start", + "start:electron": "yarn --cwd electron-app start", + "watch:browser": "lerna run --parallel watch --ignore electron-app", + "watch:electron": "lerna run --parallel watch --ignore browser-app" }, "devDependencies": { - "@theia/cli": "latest" - } + "lerna": "2.4.0" + }, + "workspaces": [ + "hello-world", "browser-app", "electron-app" + ] } ``` +Besides the root level artifacts, you will have three directories in your project: -In a nutshell, Theia applications and extensions are [Node.js packages](https://nodesource.com/blog/the-basics-of-package-json-in-node-js-and-npm/). Each package has a `package.json` file that manifests package metadata, -like `name`, `version`, its runtime and build time dependencies and so on. - -Let's have a look at the created package: - -- Its `name` and `version` are omitted since we are not going to use it as a dependency, and - it's marked as `private` since it is not going to be published as a Node.js package on its own. -- We've listed required extensions as runtime dependencies, e.g. `@theia/navigator`. - - Some extensions require additional tooling installed, in such cases, please consult the corresponding extension documentation. - - Use [this link](https://www.npmjs.com/search?q=keywords:theia-extension) to see all published extensions. -- We've listed [@theia/cli](https://www.npmjs.com/package/@theia/cli) as a build-time dependency. It provides scripts to build and run the application. +- browser-app: The definitions of your custom Theia application running in the browser +- electron-app: The definitions of your custom Theia application running on the desktop (via Electron) +- hello-world: The generated example extensions, see [this guide](/docs/authoring_extensions) for more details -## Consuming VS Code Extensions +## Executing the Browser Application -As part of your application, it is also possible to consume (and package) VS Code extensions. -The [Theia repository](https://github.com/eclipse-theia/theia/wiki/Consuming-Builtin-and-External-VS-Code-Extensions) contains a guide on how to -include such extensions as part of the application's `package.json`. - -An example `package.json` may look like the following (please replace ${downloadURL}, see explaination below the example): +Now we want to see our Theia application in action. For this purpose, the generator has created a `package.json` in the folder `browser-app`, which defines your Theia app. It defines a Theia browser application with a couple of statically included extensions, including our `hello-world`. These extensions are the features, that will be part of our Theia application. The generated project contains a minimalistic set-up, **you can add additional features by adding more existing (or custom) extensions to this list**. The example also does not contain any VS Code extensions, see [here](authoring_vscode_extensions) on how to add them. ```json { "private": true, + "name": "browser-app", + "version": "0.0.0", "dependencies": { - "@theia/callhierarchy": "latest", - "@theia/file-search": "latest", - "@theia/git": "latest", + "@theia/core": "latest", + "@theia/editor": "latest", + "@theia/filesystem": "latest", "@theia/markers": "latest", "@theia/messages": "latest", + "@theia/monaco": "latest", "@theia/navigator": "latest", - "@theia/outline-view": "latest", - "@theia/plugin-ext-vscode": "latest", "@theia/preferences": "latest", - "@theia/preview": "latest", - "@theia/search-in-workspace": "latest", + "@theia/process": "latest", "@theia/terminal": "latest", - "@theia/vsx-registry": "latest" + "@theia/workspace": "latest", + "hello-world": "0.0.0" }, "devDependencies": { "@theia/cli": "latest" }, "scripts": { - "prepare": "yarn run clean && yarn build && yarn run download:plugins", - "clean": "theia clean", - "build": "theia build --mode development", - "start": "theia start --plugins=local-dir:plugins", - "download:plugins": "theia download:plugins" - }, - "theiaPluginsDir": "plugins", - "theiaPlugins": { - "vscode-builtin-extensions-pack": "${downloadURL}" + "bundle": "yarn rebuild && theia build --mode development", + "rebuild": "theia rebuild:browser --cacheRoot ..", + "start": "theia start", + "watch": "yarn rebuild && theia build --watch --mode development" }, - "theiaPluginsExcludeIds": [ - "ms-vscode.js-debug-companion", - "vscode.extension-editing", - "vscode.github", - "vscode.github-authentication", - "vscode.microsoft-authentication" - ] + "theia": { + "target": "browser" + } } ``` -The following properties are used to consume built-in plugins (bundled extensions): - -- `theiaPluginsDir`: the relative path to deploy plugins into -- `theiaPlugins`: the collection of plugins to download (individual plugins or extension-packs) - can point to any valid download URL (ex: Open VSX, GitHub Releases, etc.). **In the example above, replace ${downloadURL} with a link to the latest builtins pack that can be found [on openVSX](https://open-vsx.org/extension/eclipse-theia/builtin-extension-pack) (copy the link on the download button). See also the respective section [in this file](https://github.com/eclipse-theia/theia/blob/master/package.json) for an example** -- `theiaPluginsExcludeIds`: the list of plugin `ids` to exclude when resolving extension-packs - -## Building - -First, install all dependencies. +Now we have all pieces together to build and run the application. +To run the browser app, enter: - yarn - -Second, use Theia CLI to build the application. - - yarn theia build - -`yarn` looks up `theia` executable provided by `@theia/cli` in the context of our application -and then executes the `build` command with `theia`. -This can take a while since the application is built in production mode by default, -i.e. obfuscated and minified. - -## Running +```bash +yarn build:browser +yarn start:browser +``` -After the build is finished, we can start the application: +Point your browser to , you will see a minimalistic custom Theia App. +As this Theia app contains the generated 'hello world' extension, you can try out the custom feature. Open the quick access bar by pressing 'F1' and enter 'say hello' and 'ENTER': A message "Hello World!" should pop up. This command is contributed by the 'hello-world' extension, see [this guide](/docs/authoring_extensions) to learn more. - yarn theia start --plugins=local-dir:plugins +## Executing the Extension In Electron -or rely on the `start` script from `package.json`: +The `package.json` for the Electron app looks almost the same, except for the name and the target property. - yarn start +```json +{ + "name": "electron-app", + ... + "theia": { + "target": "electron" + } +} +``` -You can provide a workspace path to open as a first argument -and `--hostname`, `--port` options to deploy the application on specific network interfaces and ports, -e.g. to open `/workspace` on all interfaces and port `8080`: +Before running the electron app, you have to rebuild some native modules: - yarn start /my-workspace --hostname 0.0.0.0 --port 8080 +```bash +yarn build:electron +yarn start:electron +``` -In the terminal, you should see that Theia application is up and listening: +## Conclusion -Terminal +In this guide, we have demonstrated how to set-up your own custom Theia application. The next typical steps are: -Open the application by entering the printed address in a new browser page. +- Extend your application with additional [Theia extensions](/docs/authoring_extensions/) (existing ones or developed by yourself) +- Extend your application with [VS Code Extensions](/docs/authoring_vscode_extensions/) (existing ones or developed by yourself) +- Create a deployable product for desktop, browser or both (see the [Theia IDE](/docs/blueprint_documentation/) as an example) ## Troubleshooting -### Plugins not appearing - -If no plugins are available in the running Theia instance, it may be that you need to tell Theia where to find the downloaded plugins. -The example above sets the `--plugins` switch in the `start` command which should be sufficient. -However, if running `theia start` directly, you can alternatively set an environment variable to achieve the same thing: - - export THEIA_DEFAULT_PLUGINS=local-dir:plugins - ### Building native dependencies behind a proxy If you run the `yarn` command behind a proxy you may encounter issues in building native dependencies (like `oniguruma`), in the last part of the build, with the following error stack: