diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index b6351cb19a..926166b712 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -28,6 +28,8 @@ import {getBunVersionIfAvailable} from '../../tools/bun'; import {getNpmVersionIfAvailable} from '../../tools/npm'; import {getYarnVersionIfAvailable} from '../../tools/yarn'; import {createHash} from 'crypto'; +import semver from 'semver'; +import {executeCommand} from '../../tools/executeCommand'; const DEFAULT_VERSION = 'latest'; @@ -56,6 +58,30 @@ interface TemplateOptions { installCocoaPods?: string | boolean; } +const YARN_VERSION = '3.6.4'; + +const bumpYarnVersion = async (silent: boolean, root: string) => { + try { + let yarnVersion = semver.parse(getYarnVersionIfAvailable()); + if (yarnVersion && semver.major(yarnVersion) === 1) { + await executeCommand('yarn', ['set', 'version', YARN_VERSION], { + root, + silent, + }); + + // React Native doesn't support PnP, so we need to set nodeLinker to node-modules. Read more here: https://github.com/react-native-community/cli/issues/27#issuecomment-1772626767 + + await executeCommand( + 'yarn', + ['config', 'set', 'nodeLinker', 'node-modules'], + {root, silent}, + ); + } + } catch (e) { + logger.debug(e as string); + } +}; + function doesDirectoryExist(dir: string) { return fs.existsSync(dir); } @@ -168,6 +194,10 @@ async function createFromTemplate({ packageName, }); + if (packageManager === 'yarn') { + await bumpYarnVersion(false, projectDirectory); + } + loader.succeed(); const {postInitScript} = templateConfig; if (postInitScript) { diff --git a/packages/cli/src/tools/executeCommand.ts b/packages/cli/src/tools/executeCommand.ts new file mode 100644 index 0000000000..61bec24936 --- /dev/null +++ b/packages/cli/src/tools/executeCommand.ts @@ -0,0 +1,16 @@ +import {logger} from '@react-native-community/cli-tools'; +import execa from 'execa'; + +export function executeCommand( + command: string, + args: Array, + options: { + root: string; + silent?: boolean; + }, +) { + return execa(command, args, { + stdio: options.silent && !logger.isVerbose() ? 'pipe' : 'inherit', + cwd: options.root, + }); +} diff --git a/packages/cli/src/tools/packageManager.ts b/packages/cli/src/tools/packageManager.ts index b465f1858e..53921d944b 100644 --- a/packages/cli/src/tools/packageManager.ts +++ b/packages/cli/src/tools/packageManager.ts @@ -1,8 +1,7 @@ -import execa from 'execa'; -import {logger} from '@react-native-community/cli-tools'; import {getYarnVersionIfAvailable, isProjectUsingYarn} from './yarn'; import {getBunVersionIfAvailable, isProjectUsingBun} from './bun'; import {getNpmVersionIfAvailable, isProjectUsingNpm} from './npm'; +import {executeCommand} from './executeCommand'; export type PackageManager = keyof typeof packageManagers; @@ -51,17 +50,6 @@ function configurePackageManager( return executeCommand(pm, args, options); } -function executeCommand( - command: string, - args: Array, - options: Options, -) { - return execa(command, args, { - stdio: options.silent && !logger.isVerbose() ? 'pipe' : 'inherit', - cwd: options.root, - }); -} - export function shouldUseYarn(options: Options) { if (options.packageManager === 'yarn') { return getYarnVersionIfAvailable();