mirror of
https://github.com/strapi/strapi.git
synced 2025-08-22 15:48:59 +00:00
fix(create-strapi-app): yarn 4 support (#21329)
This commit is contained in:
parent
8853cdb951
commit
8893730a2f
@ -14,6 +14,7 @@ import { isStderrError } from './types';
|
||||
import type { Scope } from './types';
|
||||
import { logger } from './utils/logger';
|
||||
import { gitIgnore } from './utils/gitignore';
|
||||
import { getInstallArgs } from './utils/get-package-manager-args';
|
||||
|
||||
async function createStrapi(scope: Scope) {
|
||||
const { rootPath } = scope;
|
||||
@ -239,29 +240,27 @@ async function createApp(scope: Scope) {
|
||||
}
|
||||
}
|
||||
|
||||
const installArguments = ['install'];
|
||||
async function runInstall({ rootPath, packageManager }: Scope) {
|
||||
// include same cwd and env to ensure version check returns same version we use below
|
||||
const { envArgs, cmdArgs } = await getInstallArgs(packageManager, {
|
||||
cwd: rootPath,
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: 'development',
|
||||
},
|
||||
});
|
||||
|
||||
const installArgumentsMap = {
|
||||
npm: ['--legacy-peer-deps'],
|
||||
yarn: ['--network-timeout 1000000'],
|
||||
pnpm: [],
|
||||
};
|
||||
|
||||
function runInstall({ rootPath, packageManager }: Scope) {
|
||||
const options: execa.Options = {
|
||||
cwd: rootPath,
|
||||
stdio: 'inherit',
|
||||
env: {
|
||||
...process.env,
|
||||
...envArgs,
|
||||
NODE_ENV: 'development',
|
||||
},
|
||||
};
|
||||
|
||||
if (packageManager in installArgumentsMap) {
|
||||
installArguments.push(...(installArgumentsMap[packageManager] ?? []));
|
||||
}
|
||||
|
||||
const proc = execa(packageManager, installArguments, options);
|
||||
const proc = execa(packageManager, cmdArgs, options);
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
@ -0,0 +1,144 @@
|
||||
import execa from 'execa';
|
||||
import semver from 'semver';
|
||||
|
||||
const installArguments = ['install'];
|
||||
|
||||
type VersionedArgumentsMap = {
|
||||
[key: string]: string[]; // Maps semver ranges to argument arrays
|
||||
};
|
||||
|
||||
type VersionedEnvMap = {
|
||||
[key: string]: Record<string, string>; // Maps semver ranges to environment variables
|
||||
};
|
||||
|
||||
// Set command line options for specific package managers, with full semver ranges
|
||||
const installArgumentsMap: {
|
||||
[key: string]: VersionedArgumentsMap;
|
||||
} = {
|
||||
npm: {
|
||||
'*': ['--legacy-peer-deps'],
|
||||
},
|
||||
yarn: {
|
||||
'<4': ['--network-timeout', '1000000'],
|
||||
'*': [],
|
||||
},
|
||||
pnpm: {
|
||||
'*': [],
|
||||
},
|
||||
};
|
||||
|
||||
// Set environment variables for specific package managers, with full semver ranges
|
||||
const installEnvMap: {
|
||||
[key: string]: VersionedEnvMap;
|
||||
} = {
|
||||
yarn: {
|
||||
'>=4': { YARN_HTTP_TIMEOUT: '1000000' },
|
||||
'*': {},
|
||||
},
|
||||
npm: {
|
||||
'*': {},
|
||||
},
|
||||
pnpm: {
|
||||
'*': {},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the version of the specified package manager.
|
||||
*
|
||||
* Executes the package manager's `--version` command to determine its version.
|
||||
*
|
||||
* @param packageManager - The name of the package manager (e.g., 'npm', 'yarn', 'pnpm').
|
||||
* @param options - Optional execution options to pass to `execa`.
|
||||
* @returns A promise that resolves to the trimmed version string of the package manager.
|
||||
*
|
||||
* @throws Will throw an error if the package manager's version cannot be determined.
|
||||
*/
|
||||
export const getPackageManagerVersion = async (
|
||||
packageManager: string,
|
||||
options?: execa.Options
|
||||
): Promise<string> => {
|
||||
try {
|
||||
const { stdout } = await execa(packageManager, ['--version'], options);
|
||||
return stdout.trim();
|
||||
} catch (err) {
|
||||
throw new Error(`Error detecting ${packageManager} version: ${err}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges all matching semver ranges using a custom merge function.
|
||||
*
|
||||
* Iterates over the `versionMap`, checking if the provided `version` satisfies each semver range.
|
||||
* If it does, the corresponding value is merged using the provided `mergeFn`.
|
||||
* The merging starts with the value associated with the wildcard '*' key.
|
||||
*
|
||||
* @param version - The package manager version to check against the ranges.
|
||||
* @param versionMap - A map of semver ranges to corresponding values (arguments or environment variables).
|
||||
* @param mergeFn - A function that defines how to merge two values (accumulated and current).
|
||||
* @returns The merged result of all matching ranges.
|
||||
*/
|
||||
function mergeMatchingVersionRanges<T>(
|
||||
version: string,
|
||||
versionMap: { [key: string]: T },
|
||||
mergeFn: (acc: T, curr: T) => T
|
||||
): T {
|
||||
return Object.keys(versionMap).reduce((acc, range) => {
|
||||
if (semver.satisfies(version, range) || range === '*') {
|
||||
return mergeFn(acc, versionMap[range]);
|
||||
}
|
||||
return acc;
|
||||
}, versionMap['*']); // Start with the wildcard entry
|
||||
}
|
||||
|
||||
function mergeArguments(acc: string[], curr: string[]): string[] {
|
||||
return [...acc, ...curr];
|
||||
}
|
||||
|
||||
function mergeEnvVars(
|
||||
acc: Record<string, string>,
|
||||
curr: Record<string, string>
|
||||
): Record<string, string> {
|
||||
return { ...acc, ...curr };
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the install arguments and environment variables for a given package manager.
|
||||
*
|
||||
* This function determines the correct command line arguments and environment variables
|
||||
* based on the package manager's version. It uses predefined semver ranges to match
|
||||
* the package manager's version and merges all applicable settings.
|
||||
*
|
||||
* The arguments and environment variables are sourced from:
|
||||
* - `installArgumentsMap` for command line arguments.
|
||||
* - `installEnvMap` for environment variables.
|
||||
*
|
||||
* The function ensures that all matching semver ranges are considered and merged appropriately.
|
||||
* It always includes the base `installArguments` (e.g., `['install']`) and applies any additional
|
||||
* arguments or environment variables as defined by the matched version ranges.
|
||||
*
|
||||
* @param packageManager - The name of the package manager (e.g., 'npm', 'yarn', 'pnpm').
|
||||
* @param options - Optional execution options to pass to `execa`.
|
||||
* @returns An object containing:
|
||||
* - `cmdArgs`: The full array of install arguments for the given package manager and version.
|
||||
* - `envArgs`: The merged environment variables applicable to the package manager and version.
|
||||
*
|
||||
* @throws Will throw an error if the package manager version cannot be determined.
|
||||
*/
|
||||
export const getInstallArgs = async (packageManager: string, options?: execa.Options) => {
|
||||
const packageManagerVersion = await getPackageManagerVersion(packageManager, options);
|
||||
|
||||
// Get environment variables
|
||||
const envMap = installEnvMap[packageManager];
|
||||
const envArgs = packageManagerVersion
|
||||
? mergeMatchingVersionRanges(packageManagerVersion, envMap, mergeEnvVars)
|
||||
: envMap['*'];
|
||||
|
||||
// Get install arguments
|
||||
const argsMap = installArgumentsMap[packageManager];
|
||||
const cmdArgs = packageManagerVersion
|
||||
? mergeMatchingVersionRanges(packageManagerVersion, argsMap, mergeArguments)
|
||||
: argsMap['*'];
|
||||
|
||||
return { envArgs, cmdArgs: [...installArguments, ...cmdArgs], version: packageManagerVersion };
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user