diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 8d17821101..a7bd814b19 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -2,10 +2,15 @@ FROM node:12 WORKDIR /usr/src/app +# Copy repo skeleton first, to avoid unnecessary docker cache invalidation. +# The skeleton contains the package.json of each package in the monorepo, +# and along with yarn.lock and the root package.json, that's enough to run yarn install. +ADD yarn.lock package.json skeleton.tar ./ + +RUN yarn install --frozen-lockfile --production + # This will copy the contents of the dist-workspace when running the build-image command. # Do not use this Dockerfile outside of that command, as it will copy in the source code instead. COPY . . -RUN yarn install --frozen-lockfile --production - CMD ["node", "packages/backend"] diff --git a/packages/cli/src/commands/backend/buildImage.ts b/packages/cli/src/commands/backend/buildImage.ts index 36d4ef7129..b6e9da7b39 100644 --- a/packages/cli/src/commands/backend/buildImage.ts +++ b/packages/cli/src/commands/backend/buildImage.ts @@ -41,6 +41,7 @@ export default async (cmd: Command) => { ...appConfigs, { src: paths.resolveTarget('Dockerfile'), dest: 'Dockerfile' }, ], + skeleton: 'skeleton.tar', }); console.log(`Dist workspace ready at ${tempDistWorkspace}`); diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/packager/index.ts index 5584e1fc21..564317e46a 100644 --- a/packages/cli/src/lib/packager/index.ts +++ b/packages/cli/src/lib/packager/index.ts @@ -15,10 +15,14 @@ */ import fs from 'fs-extra'; -import { resolve as resolvePath, relative as relativePath } from 'path'; +import { + join as joinPath, + resolve as resolvePath, + relative as relativePath, +} from 'path'; import { paths } from '../paths'; import { run } from '../run'; -import tar from 'tar'; +import tar, { CreateOptions } from 'tar'; import { tmpdir } from 'os'; type LernaPackage = { @@ -53,6 +57,12 @@ type Options = { * If set to true, the target packages are built before they are packaged into the workspace. */ buildDependencies?: boolean; + + /** + * If set, creates a skeleton tarball that contains all package.json files + * with the same structure as the workspace dir. + */ + skeleton?: 'skeleton.tar'; }; /** @@ -89,6 +99,24 @@ export async function createDistWorkspace( const dest = typeof file === 'string' ? file : file.dest; await fs.copy(paths.resolveTargetRoot(src), resolvePath(targetDir, dest)); } + + if (options.skeleton) { + const skeletonFiles = targets.map(target => { + const dir = relativePath(paths.targetRoot, target.location); + return joinPath(dir, 'package.json'); + }); + + await tar.create( + { + file: resolvePath(targetDir, options.skeleton), + cwd: targetDir, + portable: true, + noMtime: true, + } as CreateOptions & { noMtime: boolean }, + skeletonFiles, + ); + } + return targetDir; }