Skip to content

Commit

Permalink
chore(docs): installing external plugins and dynamic-plugins doc clea…
Browse files Browse the repository at this point in the history
…nup (#1895)

* chode(docs): installing external plugins

* chore(docs): cleanup, better wording

* chore(docs): improve wording and formatting in external plugins installation guide

* chore(docs): remove TOC, when rendered  using techdocs it is generated automaticaly

* docs: break dynamic-plugins.md file
  • Loading branch information
kadel authored Nov 15, 2024
1 parent 32c9e0b commit fdd1834
Show file tree
Hide file tree
Showing 8 changed files with 1,044 additions and 1,116 deletions.
60 changes: 60 additions & 0 deletions docs/dynamic-plugins/debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

# Debugging Dynamic Plugins

## Backend Dynamic Plugins Local Debug

For local debugging of Dynamic Plugins you need to clone `backstage-showcase`, run it with debugging enabled and attach your IDE debugger to the backend process. First it is required to build and copy the dynamic plugin:

* Build your plugin and export the dynamic package

```
cd ${pluginRootDir}
yarn build && yarn run export-dynamic
```

* Copy the resulting `dist-dynamic` directory to dynamic-plugins-root/${plugin-id}

Once the plugin is built and deployed, it is time to prepare the showcase to run it debug mode:

* Go to `backstage-showcase` root directory;
* Run `yarn workspace backend start --inspect`
* In logs you should see something like the following:

```
Debugger listening on ws://127.0.0.1:9229/9299bb26-3c32-4781-9488-7759b8781db5
```

* The application will be acessible from `http://localhost:7007`. You may start the front end by running the following command from the root directory: `yarn start --filter=app`. It will be available in `http://localhost:3000`
* Attach your IDE debugger to the backend process. This step may depend on the IDE that you are using. For example, if you are using VSCode you may want to check [Node.js debugging in VS Code](https://code.visualstudio.com/docs/nodejs/nodejs-debugging)
* Add Breakpoints to the files in folder `dynamic-plugins-root/${plugin-id}`. Optionally you can configure your IDE to add the source maps for the plugin so you can debug the TypeScript code directly and not the compiled Javascript files

## Backend Dynamic Plugins Container Debug

It is possible to run RHDH on a container and debug plugins that are running on it. In this case you don't need to clone the `backstage-showcase` code locally, instead you must make sure that the running container has the [Node JS debug](https://nodejs.org/en/learn/getting-started/debugging) port open and exposed to the host machine. These are the steps to debug backend dynamic plugins on a container:

* Create directory `dynamic-plugins-root`
* Build your plugin and copy the folder `dist-dynamic` to `dynamic-plugins-root`

```
$ yarn build && yarn export-dynamic
$ cp ${yourPluginRootDir}/dist-dynamic ./dynamic-plugins-root/${pluginID}
```

* Start the container and make sure to share the plugins directory with it, allow inspect and open the debug port. Here's a sample command tested on RHDH container image version 1.3:

```
podman run \
-v ./dynamic-plugins-root:/opt/app-root/src/dynamic-plugins-root:Z \
-v ./app-config.local.yaml:/opt/app-root/src/app-config.local.yaml:Z \
-p 7007:7007 \
-p 9229:9229 \
-e NODE_OPTIONS=--no-node-snapshot \
--entrypoint='["node", "--inspect=0.0.0.0:9229", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.example.yaml", "--config", "app-config.local.yaml"]' \
quay.io/rhdh/rhdh-hub-rhel9:1.3
```

You should be able to debug from your IDE by attaching it to the process running on port `9229` or selecting it from a list of processes detected by the IDE.

## Frontend Dynamic Plugins Debug

Front end plugins can be debugged directly on your browser, just make sure to export the sources map. When running the plugin on the browser open the Developer Tools and you should be able to visualize the source code and place breakpoints.
1,116 changes: 0 additions & 1,116 deletions docs/dynamic-plugins/dynamic-plugins.md

Large diffs are not rendered by default.

133 changes: 133 additions & 0 deletions docs/dynamic-plugins/export-derived-package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Export Derived Dynamic Plugin Package

In order to be able to use dynamic plugins in the RHDH, they need to be exported as a separate package. Which is than used by the RHDH to load the plugin.
Exporting a dynamic plugin package is a process of creating a new package that contains the plugin code and its dependencies, and is ready to be used as a dynamic plugin in the RHDH.

This document describes how to export a dynamic plugin package from an existing Backstage plugin.

The exporting is done using the `package export-dynamic-plugin` command from the `@janus-idp/cli` package.
The most convenient way to run the command is to use `npx`:

```bash
npx @janus-idp/cli@latest package export-dynamic-plugin
```

This command needs to be executed in the root folder of the JavaScript package (with `package.json`) of the plugin that you want to export as a dynamic plugin.

The resulting package will be located in the `dist-dynamic` sub-folder. The name of the exported packaged is modified by adding the `-dynamic` suffix to the plugin name.

This allows packing it with `npm pack`, or publishing it to npm registry. See [Packaging Dynamic Plugins](packaging-dynamic-plugins.md) for more information on how to package and distribute dynamic plugins.

> [!NOTE]
> The derived dynamic plugin JavaScript packages should **not** be pushed to the public npm registry. They should only be published to a private npm registry.
This documentation uses `@latest` tag to ensure that the latest version of the `@janus-idp/cli` package is used.
But you need to make sure that you are using the version of the `@janus-idp/cli` package that is compatible with your RHDH version.
You can find the compatible versions in the [Version Matrix](./versions.md).

If you are developing your own plugin that is going to be used as a dynamic plugin, it might be useful to add the `export-dynamic-plugin` command to the `package.json` file as a script:

```json
{
"scripts": {
"export-dynamic": "janus-cli package package export-dynamic-plugin"
},
"devDependencies": {
"@janus-idp/cli": "^1.18.0"
}
}
```

## Backend plugins

To be compatible with the showcase dynamic plugin support, and used as dynamic plugins, existing plugins must be based on, or compatible with, the new backend system, as well as rebuilt with a dedicated CLI command.

The new backend system standard entry point (created using `createBackendPlugin()` or `createBackendModule()`) should be exported as the default export of either the main package or of an `alpha` package (if the new backend support is still provided as `alpha` APIs). This doesn't add any additional requirement on top of the standard plugin development guidelines of the new backend system.
For a practical example of a dynamic plugin entry point built upon the new backend system, please refer to the [Janus plugins repository](https://github.com/janus-idp/backstage-plugins/blob/main/plugins/aap-backend/src/module.ts#L25).

The dynamic export mechanism identifies private, non-backstage dependencies, and sets the `bundleDependencies` field in the `package.json` file for them, so that the dynamic plugin package can be published as a self-contained package, along with its private dependencies bundled in a private `node_modules` folder.

### Shared dependencies

During the exporting process some dependencies are marked as shared dependencies, and are expected to be provided by the main Backstage application. These dependencies are not bundled in the dynamic plugin package, but are marked as `peerDependencies` in the `package.json` file.
By default all the `@backstage`-scoped packages are considered shared packages.

Using `--shared-package` flag you can control which packages are considered shared packages.
Shared packages are expected to be provided by the main Backstage application, and are not bundled in the dynamic plugin package.
The `--shared-package` flag can be used multiple times to specify multiple shared packages.

If plugin depends on a package that is in the `@backstage` scope, but is not provided by the main Backstage application, you can use the negation prefix `!` to specify that it should be considered as a private dependency of the dynamic plugin.

### Embedded dependencies

During the exporting process some dependencies are marked as embedded dependencies, and are bundled in the dynamic plugin package.
Embedded packages are merged into the dynamic plugin package, and their dependencies are hoisted to the top level of the dynamic plugin package.
By default, all packages with `-node` or `-common` suffix are automatically embedded in the exported plugin package.

Using `--embed-package` flag you can control which packages are embedded in the dynamic plugin package.
The `--embed-package` flag can be used multiple times to specify multiple embedded packages.

If plugin depends on another package that is in the same monorepo workspace and it doesn't follow stadart naming convention (`-node`, or `-common`), you can use the `--embed-package` flag to embed it in the dynamic plugin package.

Example of exporting a dynamic plugin with shared and embedded packages:

```bash
npx @janus-idp/cli@latest export-dynamic-plugin --shared-package '!/@backstage/plugin-notifications/' --embed-package @backstage/plugin-notifications-backend
```

In this example, the `@backstage/plugin-notifications` package is marked as a private dependency (not shared) and it will be bundled in the dynamic plugin package, even though it is in the `@backstage` scope.
The `@backstage/plugin-notifications-backend` package is marked as an embedded dependency, and it will be bundled in the dynamic plugin package.

## Frontend plugins

Our CLI can generate the default configuration for Scalprum on the fly. For generated defaults see logs when running `npx @janus-idp/cli@latest export-dynamic`. We default to the following configuration:

```json
...
"scalprum": {
"name": "<package_name>", // Webpack container name is the same as NPM package name without "@" symbol and "/" replaced with "."
"exposedModules": {
"PluginRoot": "./src/index.ts" // PluginRoot module name is the default, therefore it doesn't have to be explicitly specified later in the app-config.yaml file
}
},
...
```

//TODO document how to use a separate file for the Scalprum configuration which should be a preferred way to customize Scalprum's behavior.

However if you want to customize Scalprum's behavior, you can do so by including additional section to the `package.json` under `scalprum` key:

```json
...
"scalprum": {
"name": "custom-package-name",
"exposedModules": {
"FooModuleName": "./src/foo.ts",
"BarModuleName": "./src/bar.ts",
...
// You can export multiple modules here. Each module will be exposed as a separate entrypoint in the Webpack container.
}
},
...
```

Dynamic plugins may also need to adopt to specific Backstage needs like static JSX children for mountpoints and dynamic routes. These changes are strictly optional and exported symbols are incompatible with static plugins.

To include static JSX as element children with your dynamically imported component, please define an additional export as follows and use that as your dynamic plugin `importName`:

```tsx
// Used by a static plugin
export const EntityTechdocsContent = () => {...}

// Used by a dynamic plugin
export const DynamicEntityTechdocsContent = {
element: EntityTechdocsContent,
staticJSXContent: (
<TechDocsAddons>
<ReportIssue />
</TechDocsAddons>
),
};
```

Important part of the frontend dynamic plugins is its layout configuration (bindings and routes). For more information on how to configure bindings and routes, see [Layout Configuration](layoud-configuration.md).
Loading

0 comments on commit fdd1834

Please sign in to comment.