From 7d7abd50c8befe18f86dab1ba5cb6982539ca5aa Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Nov 2020 19:45:32 +0100 Subject: [PATCH] create-app: add app-backend plugin to template --- .changeset/add-app-backend.md | 104 ++++++++++++++++++ packages/create-app/package.json | 1 + packages/create-app/src/lib/versions.ts | 2 + .../default-app/app-config.production.yaml | 8 ++ .../templates/default-app/package.json.hbs | 1 + .../default-app/packages/backend/Dockerfile | 2 +- .../packages/backend/package.json.hbs | 4 +- .../default-app/packages/backend/src/index.ts | 5 +- .../packages/backend/src/plugins/app.ts | 13 +++ 9 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 .changeset/add-app-backend.md create mode 100644 packages/create-app/templates/default-app/app-config.production.yaml create mode 100644 packages/create-app/templates/default-app/packages/backend/src/plugins/app.ts diff --git a/.changeset/add-app-backend.md b/.changeset/add-app-backend.md new file mode 100644 index 0000000000..e44a56c885 --- /dev/null +++ b/.changeset/add-app-backend.md @@ -0,0 +1,104 @@ +--- +'@backstage/create-app': patch +--- + +Add `app-backend` as a backend plugin, and make a single docker build of the backend the default way to deploy backstage. + +Note that the `app-backend` currently only is a solution for deployments of the app, it's not a dev server and is not intended for local development. + +## Template changes + +As a part of installing the `app-backend` plugin, the below changes where made. The changes are grouped into two steps, installing the plugin, and updating the Docker build and configuration. + +### Installing the `app-backend` plugin in the backend + +First, install the `@backstage/plugin-app-backend` plugin package in your backend. These changes where made for `v0.3.0` of the plugin, and the installation process might change in the future. Run the following from the root of the repo: + +```bash +cd packages/backend +yarn add @backstage/plugin-app-backend +``` + +For the `app-backend` to get access to the static content in the frontend we also need to add the local `app` package as a dependency. Add the following to your `"dependencies"` in `packages/backend/package.json`, assuming your app package is still named `app` and on version `0.0.0`: + +```json +"app": "0.0.0", +``` + +Don't worry, this will not cause your entire frontend dependency tree to be added to the app, just double check that `packages/app/package.json` has a `"bundled": true` field at top-level. This signals to the backend build process that the package is bundled and that no transitive dependencies should be included. + +Next, create `packages/backend/src/plugins/app.ts` with the following: + +```ts +import { createRouter } from '@backstage/plugin-app-backend'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin({ + logger, + config, +}: PluginEnvironment) { + return await createRouter({ + logger, + config, + appPackageName: 'app', + }); +} +``` + +In `packages/backend/src/index.ts`, make the following changes: + +Add an import for the newly created plugin setup file: + +```ts +import app from './plugins/app'; +``` + +Setup the following plugin env. + +```ts +const appEnv = useHotMemoize(module, () => createEnv('app')); +``` + +Change service builder setup to include the `app` plugin as follows. Note that the `app` plugin is not installed on the `/api` route with most other plugins. + +```ts +const service = createServiceBuilder(module) + .loadConfig(config) + .addRouter('/api', apiRouter) + .addRouter('', await app(appEnv)); +``` + +You should now have the `app-backend` plugin installed in your backend, ready to serve the frontend bundle! + +### Docker build setup + +Since the backend image is now the only one needed for a simple Backstage deployment, the image tag name in the `build-image` script inside `packages/backend/package.json` was changed to the following: + +```json +"build-image": "backstage-cli backend:build-image --build --tag backstage", +``` + +For convenience, a `build-image` script was also added to the root `package.json` with the following: + +```json +"build-image": "yarn workspace backend build-image", +``` + +In the root of the repo, a new `app-config.production.yaml` file was added. This is used to set the appropriate `app.baseUrl` now that the frontend is served directly by the backend in the production deployment. It has the following contents: + +```yaml +app: + # Should be the same as backend.baseUrl when using the `app-backend` plugin + baseUrl: http://localhost:7000 + +backend: + baseUrl: http://localhost:7000 + listen: + port: 7000 +``` + +In order to load in the new configuration at runtime, the command in the `Dockerfile` at the repo root was changed to the following: + +```dockerfile +CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] +``` diff --git a/packages/create-app/package.json b/packages/create-app/package.json index bd1d8d1bd1..55cdcb1a2a 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -43,6 +43,7 @@ "@backstage/config": "^0.1.1", "@backstage/core": "^0.3.0", "@backstage/plugin-api-docs": "^0.2.1", + "@backstage/plugin-app-backend": "^0.2.0", "@backstage/plugin-auth-backend": "^0.2.1", "@backstage/plugin-catalog": "^0.2.1", "@backstage/plugin-catalog-backend": "^0.2.0", diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 196e0004c1..84f015509c 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -35,6 +35,7 @@ import { version as cli } from '@backstage/cli/package.json'; import { version as config } from '@backstage/config/package.json'; import { version as core } from '@backstage/core/package.json'; import { version as pluginApiDocs } from '@backstage/plugin-api-docs/package.json'; +import { version as pluginAppBackend } from '@backstage/plugin-app-backend/package.json'; import { version as pluginAuthBackend } from '@backstage/plugin-auth-backend/package.json'; import { version as pluginCatalog } from '@backstage/plugin-catalog/package.json'; import { version as pluginCatalogBackend } from '@backstage/plugin-catalog-backend/package.json'; @@ -61,6 +62,7 @@ export const packageVersions = { '@backstage/config': config, '@backstage/core': core, '@backstage/plugin-api-docs': pluginApiDocs, + '@backstage/plugin-app-backend': pluginAppBackend, '@backstage/plugin-auth-backend': pluginAuthBackend, '@backstage/plugin-catalog': pluginCatalog, '@backstage/plugin-catalog-backend': pluginCatalogBackend, diff --git a/packages/create-app/templates/default-app/app-config.production.yaml b/packages/create-app/templates/default-app/app-config.production.yaml new file mode 100644 index 0000000000..92f4574fd1 --- /dev/null +++ b/packages/create-app/templates/default-app/app-config.production.yaml @@ -0,0 +1,8 @@ +app: + # Should be the same as backend.baseUrl when using the `app-backend` plugin + baseUrl: http://localhost:7000 + +backend: + baseUrl: http://localhost:7000 + listen: + port: 7000 diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index b9fb0f3744..0116287a46 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -8,6 +8,7 @@ "scripts": { "start": "yarn workspace app start", "build": "lerna run build", + "build-image": "yarn workspace backend build-image", "tsc": "tsc", "tsc:full": "tsc --skipLibCheck false --incremental false", "clean": "backstage-cli clean && lerna run clean", diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index 93929ceb86..0fcd23f0e1 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -13,4 +13,4 @@ RUN yarn install --frozen-lockfile --production # Do not use this Dockerfile outside of that command, as it will copy in the source code instead. COPY . . -CMD ["node", "packages/backend"] +CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index df9ac28739..179d604670 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -9,7 +9,7 @@ }, "scripts": { "build": "backstage-cli backend:build", - "build-image": "backstage-cli backend:build-image --build --tag example-backend", + "build-image": "backstage-cli backend:build-image --build --tag backstage", "start": "backstage-cli backend:dev", "lint": "backstage-cli lint", "test": "backstage-cli test", @@ -17,9 +17,11 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { + "app": "0.0.0", "@backstage/backend-common": "^{{version '@backstage/backend-common'}}", "@backstage/catalog-model": "^{{version '@backstage/catalog-model'}}", "@backstage/config": "^{{version '@backstage/config'}}", + "@backstage/plugin-app-backend": "^{{version '@backstage/plugin-app-backend'}}", "@backstage/plugin-auth-backend": "^{{version '@backstage/plugin-auth-backend'}}", "@backstage/plugin-catalog-backend": "^{{version '@backstage/plugin-catalog-backend'}}", "@backstage/plugin-proxy-backend": "^{{version '@backstage/plugin-proxy-backend'}}", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 51de1ad6b3..80dc6230a6 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -18,6 +18,7 @@ import { UrlReaders, } from '@backstage/backend-common'; import { Config } from '@backstage/config'; +import app from './plugins/app'; import auth from './plugins/auth'; import catalog from './plugins/catalog'; import scaffolder from './plugins/scaffolder'; @@ -53,6 +54,7 @@ async function main() { const authEnv = useHotMemoize(module, () => createEnv('auth')); const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + const appEnv = useHotMemoize(module, () => createEnv('app')); const apiRouter = Router(); apiRouter.use('/catalog', await catalog(catalogEnv)); @@ -64,7 +66,8 @@ async function main() { const service = createServiceBuilder(module) .loadConfig(config) - .addRouter('/api', apiRouter); + .addRouter('/api', apiRouter) + .addRouter('', await app(appEnv)); await service.start().catch(err => { console.log(err); diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/app.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/app.ts new file mode 100644 index 0000000000..51316949cb --- /dev/null +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/app.ts @@ -0,0 +1,13 @@ +import { createRouter } from '@backstage/plugin-app-backend'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin({ + logger, + config, +}: PluginEnvironment) { + return await createRouter({ + logger, + config, + appPackageName: 'app', + }); +}