diff --git a/.changeset/nasty-colts-tell.md b/.changeset/nasty-colts-tell.md new file mode 100644 index 0000000000..eeb7818f4c --- /dev/null +++ b/.changeset/nasty-colts-tell.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Add `backend:bundle` command for bundling a backend package with dependencies into a deployment archive. diff --git a/docs/cli/commands.md b/docs/cli/commands.md index c505bf8ae7..726f2a922c 100644 --- a/docs/cli/commands.md +++ b/docs/cli/commands.md @@ -28,6 +28,7 @@ app:diff Diff an existing app with the creation template app:serve Serve an app for local development backend:build Build a backend plugin +backend:bundle Bundle the backend into a deployment archive backend:build-image Bundles the package into a docker image backend:dev Start local development server with HMR for the backend @@ -166,7 +167,7 @@ Options: ## backend:build -Scope: `backend`, `backend-plugin` +Scope: `backend-plugin` This builds a backend package for publishing and use in production. The build output is written to `dist/`. Be sure to list any additional file that the @@ -180,6 +181,52 @@ Options: -h, --help display help for command ``` +## backend:bundle + +Scope: `backend` + +Bundle the backend and all of its local dependencies into a deployment archive. +The archive is written to `dist/bundle.tar.gz`, and contains the packaged +version of all dependencies of the target package, along with the target package +itself. The layout of the packages in the archive is the same as the directory +layout in the target monorepo, and the bundle also contains the root +`package.json` and `yarn.lock`. + +To use the bundle, extract it into a target directory, run +`yarn install --production`, and then start the target backend package using for +example `node package/backend`. + +The `dist/bundle.tar.gz` is accompanied by a `dist/skeleton.tar.gz`, which has +the same layout, but only contains `package.json` files and `yarn.lock`. This +can be used to run a `yarn install` in environments that will benefit from the +caching that this enables, such as Docker image builds. To use the skeleton +archive, simply extract it first, run install, and then extract the main bundle. + +The following is an example of a `Dockerfile` that can be used to package the +output of `backstage-cli backend:bundle` into an image: + +```Dockerfile +FROM node:14-buster +WORKDIR /app + +ADD yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ +RUN yarn install --production --network-timeout 600000 && rm -rf "$(yarn cache dir)" + +ADD packages/backend/dist/bundle.tar.gz app-config.yaml ./ + +CMD node packages/backend +``` + +```text +Usage: backstage-cli backend:bundle [options] + +Bundle the backend into a deployment archive + +Options: + --build-dependencies Build all local package dependencies before bundling the backend + -h, --help display help for command +``` + ## backend:build-image Scope: `backend` diff --git a/packages/cli/src/commands/backend/bundle.ts b/packages/cli/src/commands/backend/bundle.ts index 4d298f3735..25322045e1 100644 --- a/packages/cli/src/commands/backend/bundle.ts +++ b/packages/cli/src/commands/backend/bundle.ts @@ -38,7 +38,7 @@ export default async (cmd: Command) => { try { await createDistWorkspace([pkg.name], { targetDir: tmpDir, - buildDependencies: Boolean(cmd.build), + buildDependencies: Boolean(cmd.buildDependencies), buildExcludes: [pkg.name], parallel: parseParallel(process.env[PARALLEL_ENV_VAR]), skeleton: SKELETON_FILE, diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index e090c454f9..ac8e214d26 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -45,9 +45,12 @@ export function registerCommands(program: CommanderStatic) { .action(lazy(() => import('./backend/build').then(m => m.default))); program - .command('backend:__experimental__bundle__', { hidden: true }) - .description('Bundle all backend packages into dist-workspace') - .option('--build', 'Build packages before packing them into the image') + .command('backend:bundle') + .description('Bundle the backend into a deployment archive') + .option( + '--build-dependencies', + 'Build all local package dependencies before bundling the backend', + ) .action(lazy(() => import('./backend/bundle').then(m => m.default))); program