From 634d2e37a4c6fe098798e4a8db85ad226eec0aa3 Mon Sep 17 00:00:00 2001 From: Nestor Date: Sat, 8 Oct 2022 12:54:28 +0200 Subject: [PATCH 1/5] Add npm to environment package parser --- .../create-next-app/helpers/get-pkg-manager.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/create-next-app/helpers/get-pkg-manager.ts b/packages/create-next-app/helpers/get-pkg-manager.ts index e3de28a4f9d46..1944565296e89 100644 --- a/packages/create-next-app/helpers/get-pkg-manager.ts +++ b/packages/create-next-app/helpers/get-pkg-manager.ts @@ -5,19 +5,19 @@ export type PackageManager = 'npm' | 'pnpm' | 'yarn' export function getPkgManager(): PackageManager { try { const userAgent = process.env.npm_config_user_agent + if (userAgent) { if (userAgent.startsWith('yarn')) { + execSync('yarn --version', { stdio: 'ignore' }) return 'yarn' } else if (userAgent.startsWith('pnpm')) { + execSync('pnpm --version', { stdio: 'ignore' }) return 'pnpm' + } else { + return 'npm' } - } - try { - execSync('yarn --version', { stdio: 'ignore' }) - return 'yarn' - } catch { - execSync('pnpm --version', { stdio: 'ignore' }) - return 'pnpm' + } else { + return 'npm' } } catch { return 'npm' From 6dcd680d13862ec785d82977ac1f931c11d32325 Mon Sep 17 00:00:00 2001 From: Nestor Date: Sun, 9 Oct 2022 16:35:18 +0200 Subject: [PATCH 2/5] Simplify getPkgManager function in create-next-app --- .../helpers/get-pkg-manager.ts | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/packages/create-next-app/helpers/get-pkg-manager.ts b/packages/create-next-app/helpers/get-pkg-manager.ts index 1944565296e89..b95ff3abe0bde 100644 --- a/packages/create-next-app/helpers/get-pkg-manager.ts +++ b/packages/create-next-app/helpers/get-pkg-manager.ts @@ -1,25 +1,17 @@ -import { execSync } from 'child_process' - export type PackageManager = 'npm' | 'pnpm' | 'yarn' export function getPkgManager(): PackageManager { - try { - const userAgent = process.env.npm_config_user_agent + const userAgent = process.env.npm_config_user_agent - if (userAgent) { - if (userAgent.startsWith('yarn')) { - execSync('yarn --version', { stdio: 'ignore' }) - return 'yarn' - } else if (userAgent.startsWith('pnpm')) { - execSync('pnpm --version', { stdio: 'ignore' }) - return 'pnpm' - } else { - return 'npm' - } + if (userAgent) { + if (userAgent.startsWith('yarn')) { + return 'yarn' + } else if (userAgent.startsWith('pnpm')) { + return 'pnpm' } else { return 'npm' } - } catch { + } else { return 'npm' } } From 3251822111dcbcb0a6e09cb79931c93951e659bc Mon Sep 17 00:00:00 2001 From: Nestor Date: Sun, 9 Oct 2022 16:35:52 +0200 Subject: [PATCH 3/5] Use custom message based on package manager --- packages/create-next-app/index.ts | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/create-next-app/index.ts b/packages/create-next-app/index.ts index aa89b4fd25175..6a1c6e61f53db 100644 --- a/packages/create-next-app/index.ts +++ b/packages/create-next-app/index.ts @@ -62,6 +62,12 @@ const program = new Commander.Command(packageJson.name) .allowUnknownOption() .parse(process.argv) +const packageManager = !!program.useNpm + ? 'npm' + : !!program.usePnpm + ? 'pnpm' + : getPkgManager() + async function run(): Promise { if (typeof projectPath === 'string') { projectPath = projectPath.trim() @@ -122,12 +128,6 @@ async function run(): Promise { process.exit(1) } - const packageManager = !!program.useNpm - ? 'npm' - : !!program.usePnpm - ? 'pnpm' - : getPkgManager() - const example = typeof program.example === 'string' && program.example.trim() try { await createApp({ @@ -168,16 +168,18 @@ async function notifyUpdate(): Promise { try { const res = await update if (res?.latest) { - const pkgManager = getPkgManager() + const updateMessage = + packageManager === 'yarn' + ? 'yarn global add create-next-app' + : packageManager === 'pnpm' + ? 'pnpm add -g create-next-app' + : 'npm i -g create-next-app' + console.log( chalk.yellow.bold('A new version of `create-next-app` is available!') + '\n' + 'You can update by running: ' + - chalk.cyan( - pkgManager === 'yarn' - ? 'yarn global add create-next-app' - : `${pkgManager} install --global create-next-app` - ) + + chalk.cyan(updateMessage) + '\n' ) } From 7339a3f70c4c370bc9b203d276507d81b3f43f56 Mon Sep 17 00:00:00 2001 From: Nestor Date: Wed, 12 Oct 2022 17:04:36 +0200 Subject: [PATCH 4/5] Add tests to create-next-app package manager inference --- .../integration/create-next-app/index.test.ts | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/test/integration/create-next-app/index.test.ts b/test/integration/create-next-app/index.test.ts index ba7fd5df86c7e..831817e8cf8bf 100644 --- a/test/integration/create-next-app/index.test.ts +++ b/test/integration/create-next-app/index.test.ts @@ -506,10 +506,172 @@ describe('create next app', () => { 'pnpm-lock.yaml', 'node_modules/next', ] + files.forEach((file) => + expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy() + ) + }) + }) + it('should infer npm as the package manager', async () => { + await usingTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run([projectName], { + cwd, + env: { ...process.env, npm_config_user_agent: 'npm' }, + }) + expect(res.exitCode).toBe(0) + + const files = [ + 'package.json', + 'pages/index.js', + '.gitignore', + '.eslintrc.json', + 'package-lock.json', + 'node_modules/next', + ] files.forEach((file) => expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy() ) }) }) + + it('should infer npm as the package manager with example', async () => { + await usingTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run( + [projectName, '--example', `${exampleRepo}/${examplePath}`], + { cwd, env: { ...process.env, npm_config_user_agent: 'npm' } } + ) + expect(res.exitCode).toBe(0) + + const files = [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'package-lock.json', + 'node_modules/next', + ] + files.forEach((file) => + expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy() + ) + }) + }) + + it('should infer yarn as the package manager', async () => { + try { + await execa('yarn', ['--version']) + } catch (_) { + // install yarn if not available + await execa('npm', ['i', '-g', 'yarn']) + } + + await usingTempDir(async (cwd) => { + const projectName = 'infer-package-manager-yarn' + const res = await run([projectName], { + cwd, + env: { ...process.env, npm_config_user_agent: 'yarn' }, + }) + expect(res.exitCode).toBe(0) + + const files = [ + 'package.json', + 'pages/index.js', + '.gitignore', + '.eslintrc.json', + 'yarn.lock', + 'node_modules/next', + ] + files.forEach((file) => + expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy() + ) + }) + }) + + it('should infer yarn as the package manager with example', async () => { + try { + await execa('yarn', ['--version']) + } catch (_) { + // install yarn if not available + await execa('npm', ['i', '-g', 'yarn']) + } + + await usingTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run( + [projectName, '--example', `${exampleRepo}/${examplePath}`], + { cwd, env: { ...process.env, npm_config_user_agent: 'yarn' } } + ) + expect(res.exitCode).toBe(0) + + const files = [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'yarn.lock', + 'node_modules/next', + ] + files.forEach((file) => + expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy() + ) + }) + }) + + it('should infer pnpm as the package manager', async () => { + try { + await execa('pnpm', ['--version']) + } catch (_) { + // install pnpm if not available + await execa('npm', ['i', '-g', 'pnpm']) + } + + await usingTempDir(async (cwd) => { + const projectName = 'infer-package-manager' + const res = await run([projectName], { + cwd, + env: { ...process.env, npm_config_user_agent: 'pnpm' }, + }) + expect(res.exitCode).toBe(0) + + const files = [ + 'package.json', + 'pages/index.js', + '.gitignore', + '.eslintrc.json', + 'pnpm-lock.yaml', + 'node_modules/next', + ] + files.forEach((file) => + expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy() + ) + }) + }) +}) + +it('should infer pnpm as the package manager with example', async () => { + try { + await execa('yarn', ['--version']) + } catch (_) { + // install yarn if not available + await execa('npm', ['i', '-g', 'pnpm']) + } + + await usingTempDir(async (cwd) => { + const projectName = 'infer-package-manager-npm' + const res = await run( + [projectName, '--example', `${exampleRepo}/${examplePath}`], + { cwd, env: { ...process.env, npm_config_user_agent: 'pnpm' } } + ) + expect(res.exitCode).toBe(0) + + const files = [ + 'package.json', + 'pages/index.tsx', + '.gitignore', + 'pnpm-lock.yaml', + 'node_modules/next', + ] + files.forEach((file) => + expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy() + ) + }) }) From 48ae4d3028baa1f58590666abd03ad6f235d298e Mon Sep 17 00:00:00 2001 From: Nestor Date: Thu, 13 Oct 2022 12:48:20 +0200 Subject: [PATCH 5/5] Fix try catch check in pnpm usage for create-next-app --- test/integration/create-next-app/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/create-next-app/index.test.ts b/test/integration/create-next-app/index.test.ts index 831817e8cf8bf..3b56e3864aa7f 100644 --- a/test/integration/create-next-app/index.test.ts +++ b/test/integration/create-next-app/index.test.ts @@ -649,9 +649,9 @@ describe('create next app', () => { it('should infer pnpm as the package manager with example', async () => { try { - await execa('yarn', ['--version']) + await execa('pnpm', ['--version']) } catch (_) { - // install yarn if not available + // install pnpm if not available await execa('npm', ['i', '-g', 'pnpm']) }