|
| 1 | +# Sourcegraph Backstage Common library plugin |
| 2 | + |
| 3 | +Welcome to the Sourcegraph Backstage common plugin! |
| 4 | + |
| 5 | +## How this plugin was generated. |
| 6 | + |
| 7 | +Backstage has a cli named `backstage-cli` which performs a bunch of operations relating to Backstage maintenance and developing, including generating scaffolding for plugins. |
| 8 | + |
| 9 | +There are a few plugin types but we're only interested in the following types for now: |
| 10 | + |
| 11 | +- frontend-plugin: a plugin that adds components and integration with the Backstage frontend. The generated scaffolding allows running the plugin on its own without Backstage, as long as there is an `app-config.yaml` for configuration. |
| 12 | +- backend-plugin: a plugin that integrates with the Backstage backend. Typically does not contain any visual components. The generated scaffolding allows you to run the plugin on its own as a backend application, meaning there won't be a web page to visit. |
| 13 | +- common-plugin: a plugin that is more a library, with common functionality you want to share across plugins. Unlike the other plugin types, this plugin cannot be run on its own. |
| 14 | + |
| 15 | +### How to generate plugin scaffolding. |
| 16 | + |
| 17 | +1. Make sure you're in the Backstage repo generated with `@backstage/create-app` (Not a hard requirement, but the rest of the points assume this directory). |
| 18 | +2. Run `backstage-cli new`, where a mini wizard will ask you questions about your plugin. |
| 19 | +3. Once the command completes, the generated plugin scaffolding can be found under `plugins/`. |
| 20 | + |
| 21 | +The plugin scaffolding now has been generated but the scaffolding assumes the plugin will stay in the Backstage repo which it won't. To make the plugin 'workable' outside of the Backstage repository we have make some additional changes. |
| 22 | + |
| 23 | +1. Add the following `tsconfig.json` to the plugin directory. |
| 24 | + |
| 25 | +```json |
| 26 | +{ |
| 27 | + "extends": "../../tsconfig.json", |
| 28 | + "compilerOptions": { |
| 29 | + "module": "commonjs", |
| 30 | + "target": "es2020", |
| 31 | + "lib": ["esnext", "DOM", "DOM.Iterable"], |
| 32 | + "sourceMap": true, |
| 33 | + "sourceRoot": "src", |
| 34 | + "baseUrl": "./src", |
| 35 | + "paths": { |
| 36 | + "@sourcegraph/*": ["../*"], |
| 37 | + "*": ["types/*", "../../shared/src/types/*", "../../common/src/types/*", "*"] |
| 38 | + }, |
| 39 | + "esModuleInterop": true, |
| 40 | + "resolveJsonModule": true, |
| 41 | + "strict": true, |
| 42 | + "jsx": "react-jsx" |
| 43 | + }, |
| 44 | + "references": [ |
| 45 | + { |
| 46 | + "path": "../shared" |
| 47 | + } |
| 48 | + ], |
| 49 | + "include": ["./package.json", "**/*", ".*", "**/*.d.ts"], |
| 50 | + "exclude": ["node_modules", "../../node_modules", "dist"] |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +The above `tsconfig` was copied from `client/jetbrains` and adapted to fit our usecase. |
| 55 | + |
| 56 | +2. Take note of the plugin directory structure. |
| 57 | + |
| 58 | +```console |
| 59 | + |
| 60 | +. |
| 61 | +├── README.md |
| 62 | +├── dist |
| 63 | +│ ├── index.cjs.js |
| 64 | +│ ├── index.cjs.js.map |
| 65 | +│ ├── index.d.ts |
| 66 | +│ ├── index.esm.js |
| 67 | +│ └── index.esm.js.map |
| 68 | +├── dist-types |
| 69 | +│ ├── src |
| 70 | +│ │ ├── catalog |
| 71 | +│ │ │ ├── index.d.ts |
| 72 | +│ │ │ └── parsers.d.ts |
| 73 | +│ │ ├── client |
| 74 | +│ │ │ ├── SourcegraphClient.d.ts |
| 75 | +│ │ │ ├── SourcegraphClient.test.d.ts |
| 76 | +│ │ │ └── index.d.ts |
| 77 | +│ │ ├── index.d.ts |
| 78 | +│ │ ├── providers |
| 79 | +│ │ │ ├── SourcegraphEntityProvider.d.ts |
| 80 | +│ │ │ └── index.d.ts |
| 81 | +│ │ └── setupTests.d.ts |
| 82 | +│ └── tsconfig.tsbuildinfo |
| 83 | +├── node_modules |
| 84 | +├── package.json |
| 85 | +├── src |
| 86 | +│ ├── catalog |
| 87 | +│ │ ├── index.ts |
| 88 | +│ │ └── parsers.ts |
| 89 | +│ ├── client |
| 90 | +│ │ ├── SourcegraphClient.test.ts |
| 91 | +│ │ ├── SourcegraphClient.ts |
| 92 | +│ │ └── index.ts |
| 93 | +│ ├── index.ts |
| 94 | +│ ├── providers |
| 95 | +│ │ ├── SourcegraphEntityProvider.ts |
| 96 | +│ │ └── index.ts |
| 97 | +│ └── setupTests.ts |
| 98 | +└── tsconfig.json |
| 99 | + |
| 100 | +17 directories, 27 files |
| 101 | +``` |
| 102 | + |
| 103 | +3. The plugin will use libraries and components from the Sourcegraph repo, which are all private and not available on the npm registry. Which means, when this plugin is installed into Backstage, it will try to look for any dependencies defined in the `package.json` on the npm registry. It will find some, but any Sourcegraph referenced projects, it won't be able to find anything. We thus need to make some changes to the `package.json` and also look into using a bundler like `esbuild`. |
| 104 | + |
| 105 | +4. The notable changes we make in the `package.json` are that: |
| 106 | + |
| 107 | +- change the `main` attribute to have the `dist/index.js` - note no `cjs`. This is due to use using a bundler, which bundles everything into a `js` file. |
| 108 | +- add a script `es` which invokes `esbuild` with a particular config and we copy `package.dist.json` to `dist/package.json`. `package.dist.json` is a slimmed down version of our root package.json and defines how one should install the bundled artefact of our plugin, namely `index.js`. |
| 109 | + |
| 110 | +```json |
| 111 | +{ |
| 112 | + "name": "backstage-plugin-sourcegraph-common", |
| 113 | + "description": "Common functionalities for the Sourcegraph plugin", |
| 114 | + "version": "0.1.0", |
| 115 | + "main": "dist/index.js", |
| 116 | + "types": "dist/index.d.ts", |
| 117 | + "license": "Apache-2.0", |
| 118 | + "private": true, |
| 119 | + "publishConfig": { |
| 120 | + "access": "public", |
| 121 | + "main": "dist/index.js", |
| 122 | + "module": "dist/index.esm.js", |
| 123 | + "types": "dist/index.d.ts" |
| 124 | + }, |
| 125 | + "backstage": { |
| 126 | + "role": "common-library" |
| 127 | + }, |
| 128 | + "scripts": { |
| 129 | + "es": "ts-node --transpile-only ./scripts/esbuild.ts && cp package.dist.json dist/", |
| 130 | + "build": "backstage-cli package build", |
| 131 | + "lint": "backstage-cli package lint", |
| 132 | + "test": "backstage-cli package test", |
| 133 | + "clean": "backstage-cli package clean", |
| 134 | + "prepack": "backstage-cli package prepack", |
| 135 | + "postpack": "backstage-cli package postpack" |
| 136 | + }, |
| 137 | + "devDependencies": { |
| 138 | + "@backstage/cli": "^0.22.1", |
| 139 | + "@jest/globals": "^29.4.0", |
| 140 | + "@sourcegraph/tsconfig": "^4.0.1", |
| 141 | + "@types/jest": "^29.4.0", |
| 142 | + "ts-jest": "^29.0.5" |
| 143 | + }, |
| 144 | + "dependencies": { |
| 145 | + "@backstage/catalog-model": "^1.1.5", |
| 146 | + "@backstage/config": "^1.0.6", |
| 147 | + "@backstage/plugin-catalog-backend": "^1.7.1", |
| 148 | + "@sourcegraph/shared": "workspace:^1.0.0" |
| 149 | + }, |
| 150 | + "files": ["dist"] |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +5. If we take a look at the `esbuild` config defined in `scripts/esbuild.ts` there are a few options to take note of: |
| 155 | + |
| 156 | +- we use `external` and define most of our dependencies except the Sourcegraph related ones. External tells `esbuild` that it shouldn't bundle these dependencies into the final artefact. We set it to the values we defined in our `package.json` because they can be found on the npm registry. This also explains why we don't have `@sourcegraph/*` defined there, since we **do** want them bundled. Unfortunately, some transitive dependencies will also be bundled as they're imported, which why `lodash` and `apollo` are defined. It is a bit of a cat and mouse game, to get the right dependencies excluded. |
| 157 | + |
| 158 | +6. We can now copy the directory to wherever we want, like the Sourcgraph repo `cp plugins/backstage-plugin-test ~/sourcegraph/client/backstage/test`. |
| 159 | + |
| 160 | +7. Depending on the type of plugin that was generated, a dependency entry was added to either the `packages/app/package.json or `packages/backend/packages.json`. Now that the plugin has been 'moved' we don't want Backstage to still refer to these locations, so remove the plugin with `yarn workspace backend remove <name>`or`yarn workspace app remove <name>`. |
| 161 | + |
| 162 | +### Run the plugin with Backstage / Local Development |
| 163 | + |
| 164 | +Since we copied the plugin to a different directory we need to tell Backstage where to find the plugin. |
| 165 | + |
| 166 | +1. Make sure the plugin is built. Note that we use pnpm here and not yarn, which is because Sourcegraph uses pnpm. Both yarn and pnpm work with the command defined in the `package.json` which just executes `backstage-cli` with some args. |
| 167 | + |
| 168 | +```console |
| 169 | +$ cd sourcegraph/client/backstage/plugin |
| 170 | +$ pnpm es |
| 171 | +``` |
| 172 | + |
| 173 | +2. There should now be a dist directory in `sourcegraph/client/backstage/plugin`. |
| 174 | +3. We're now ready to show Backstage where the plugin is. Move to the Backstage root directory and execute: |
| 175 | + For a plugin that integrates with the backend: |
| 176 | + |
| 177 | +```console |
| 178 | +$ yarn workspace backend add link:~/sourcegraph/client/backstage/plugin/dist |
| 179 | +``` |
| 180 | + |
| 181 | +For a plugin that integrates with the frontend: |
| 182 | + |
| 183 | +```console |
| 184 | +$ yarn workspace app add link:~/sourcegraph/client/backstage/plugin/dist |
| 185 | +``` |
| 186 | + |
| 187 | +4. You should be able to start the Backstage app now with `yarn dev` |
0 commit comments