diff --git a/.changeset/silver-mice-thank.md b/.changeset/silver-mice-thank.md new file mode 100644 index 00000000000..3cb763c622f --- /dev/null +++ b/.changeset/silver-mice-thank.md @@ -0,0 +1,6 @@ +--- +'@shopify/cli-kit': patch +'@shopify/app': patch +--- + +Remove all template lockfiles, except the one used to install dependencies diff --git a/packages/app/src/cli/services/init/init.ts b/packages/app/src/cli/services/init/init.ts index 6cdfa3417f9..1a3e2659585 100644 --- a/packages/app/src/cli/services/init/init.ts +++ b/packages/app/src/cli/services/init/init.ts @@ -180,7 +180,7 @@ async function init(options: InitOptions) { { title: 'Cleaning up', task: async () => { - await cleanup(templateScaffoldDir) + await cleanup(templateScaffoldDir, packageManager) }, }, { diff --git a/packages/app/src/cli/services/init/template/cleanup.test.ts b/packages/app/src/cli/services/init/template/cleanup.test.ts index 51a4240c06c..37fe613d02e 100644 --- a/packages/app/src/cli/services/init/template/cleanup.test.ts +++ b/packages/app/src/cli/services/init/template/cleanup.test.ts @@ -2,6 +2,7 @@ import cleanup from './cleanup.js' import {describe, expect, test} from 'vitest' import {inTemporaryDirectory, mkdir, writeFile, fileExists} from '@shopify/cli-kit/node/fs' import {joinPath} from '@shopify/cli-kit/node/path' +import {PackageManager} from '@shopify/cli-kit/node/node-package-manager' describe('cleanup', () => { async function mockProjectFolder(tmpDir: string) { @@ -35,7 +36,7 @@ describe('cleanup', () => { await mockProjectFolder(tmpDir) // When - await cleanup(tmpDir) + await cleanup(tmpDir, 'npm') // Then await expect(fileExists(joinPath(tmpDir, '.git'))).resolves.toBe(false) @@ -52,7 +53,7 @@ describe('cleanup', () => { await mockProjectFolder(tmpDir) // When - await cleanup(tmpDir) + await cleanup(tmpDir, 'npm') // Then await expect(fileExists(joinPath(tmpDir, 'server.js'))).resolves.toBe(true) @@ -60,4 +61,42 @@ describe('cleanup', () => { await expect(fileExists(joinPath(tmpDir, 'frontend', 'node_modules'))).resolves.toBe(true) }) }) + + test.each(['npm', 'yarn', 'pnpm', 'bun'])('deletes unused lockfiles for %s', async (packageManager) => { + await inTemporaryDirectory(async (tmpDir) => { + await mockProjectFolder(tmpDir) + await writeFile(joinPath(tmpDir, 'package-lock.json'), '{}') + await writeFile(joinPath(tmpDir, 'yarn.lock'), '{}') + await writeFile(joinPath(tmpDir, 'pnpm-lock.yaml'), '{}') + await writeFile(joinPath(tmpDir, 'bun.lockb'), '{}') + + // When + await cleanup(tmpDir, packageManager as PackageManager) + + // Then + await expect(fileExists(joinPath(tmpDir, 'package-lock.json'))).resolves.toBe(packageManager === 'npm') + await expect(fileExists(joinPath(tmpDir, 'yarn.lock'))).resolves.toBe(packageManager === 'yarn') + await expect(fileExists(joinPath(tmpDir, 'pnpm-lock.yaml'))).resolves.toBe(packageManager === 'pnpm') + await expect(fileExists(joinPath(tmpDir, 'bun.lockb'))).resolves.toBe(packageManager === 'bun') + }) + }) + + test('deletes all lockfiles for unknown package manager', async () => { + await inTemporaryDirectory(async (tmpDir) => { + await mockProjectFolder(tmpDir) + await writeFile(joinPath(tmpDir, 'package-lock.json'), '{}') + await writeFile(joinPath(tmpDir, 'yarn.lock'), '{}') + await writeFile(joinPath(tmpDir, 'pnpm-lock.yaml'), '{}') + await writeFile(joinPath(tmpDir, 'bun.lockb'), '{}') + + // When + await cleanup(tmpDir, 'unknown') + + // Then + await expect(fileExists(joinPath(tmpDir, 'package-lock.json'))).resolves.toBe(false) + await expect(fileExists(joinPath(tmpDir, 'yarn.lock'))).resolves.toBe(false) + await expect(fileExists(joinPath(tmpDir, 'pnpm-lock.yaml'))).resolves.toBe(false) + await expect(fileExists(joinPath(tmpDir, 'bun.lockb'))).resolves.toBe(false) + }) + }) }) diff --git a/packages/app/src/cli/services/init/template/cleanup.ts b/packages/app/src/cli/services/init/template/cleanup.ts index fa46e90b370..fde535065e4 100644 --- a/packages/app/src/cli/services/init/template/cleanup.ts +++ b/packages/app/src/cli/services/init/template/cleanup.ts @@ -1,7 +1,8 @@ -import {rmdir, glob} from '@shopify/cli-kit/node/fs' +import {rmdir, glob, fileExistsSync, unlinkFile} from '@shopify/cli-kit/node/fs' +import {Lockfile, lockfilesByManager, PackageManager} from '@shopify/cli-kit/node/node-package-manager' import {joinPath} from '@shopify/cli-kit/node/path' -export default async function cleanup(webOutputDirectory: string) { +export default async function cleanup(webOutputDirectory: string, packageManager: PackageManager) { const gitPaths = await glob( [ joinPath(webOutputDirectory, '**', '.git'), @@ -20,5 +21,14 @@ export default async function cleanup(webOutputDirectory: string) { }, ) - return Promise.all(gitPaths.map((path) => rmdir(path, {force: true}))).then(() => {}) + const gitPathPromises = gitPaths.map((path) => rmdir(path, {force: true})) + + const lockfilePromises = Object.entries(lockfilesByManager) + .filter(([manager, lockfile]) => manager !== packageManager && lockfile) + .map(([_, lockfile]) => { + const path = joinPath(webOutputDirectory, lockfile as Lockfile) + if (fileExistsSync(path)) return unlinkFile(path) + }, []) + + return Promise.all([...gitPathPromises, ...lockfilePromises]) } diff --git a/packages/cli-kit/src/public/node/fs.ts b/packages/cli-kit/src/public/node/fs.ts index 44799515c9f..b9ee1291900 100644 --- a/packages/cli-kit/src/public/node/fs.ts +++ b/packages/cli-kit/src/public/node/fs.ts @@ -43,6 +43,7 @@ import { chmod as fsChmod, access as fsAccess, rename as fsRename, + unlink as fsUnlink, } from 'fs/promises' import {pathToFileURL as pathToFile} from 'url' import * as os from 'os' @@ -329,14 +330,24 @@ export function fileSizeSync(path: string): number { } /** - * Unlink a file at the given path. + * Synchronously unlink a file at the given path. + * * @param path - Path to the file. - * @returns A promise that resolves when the file is unlinked. */ export function unlinkFileSync(path: string): void { fsUnlinkSync(path) } +/** + * Unlink a file at the given path. + * + * @param path - Path to the file. + * @returns A promise that resolves when the file is unlinked. + */ +export function unlinkFile(path: string): Promise { + return fsUnlink(path) +} + /** * Create a read stream for a file with optional options. * diff --git a/packages/cli-kit/src/public/node/node-package-manager.ts b/packages/cli-kit/src/public/node/node-package-manager.ts index 99094948dd1..89dcb0ca417 100644 --- a/packages/cli-kit/src/public/node/node-package-manager.ts +++ b/packages/cli-kit/src/public/node/node-package-manager.ts @@ -29,6 +29,13 @@ export const pnpmWorkspaceFile = 'pnpm-workspace.yaml' /** An array containing the lockfiles from all the package managers */ export const lockfiles: Lockfile[] = [yarnLockfile, pnpmLockfile, npmLockfile, bunLockfile] +export const lockfilesByManager: {[key in PackageManager]: Lockfile | undefined} = { + yarn: yarnLockfile, + npm: npmLockfile, + pnpm: pnpmLockfile, + bun: bunLockfile, + unknown: undefined, +} export type Lockfile = 'yarn.lock' | 'package-lock.json' | 'pnpm-lock.yaml' | 'bun.lockb' /**