Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve flow in init command on higher Yarn versions #1931

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions packages/cli/src/commands/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import * as PackageManager from '../../tools/packageManager';
import {installPods} from '@react-native-community/cli-doctor';
import banner from './banner';
import TemplateAndVersionError from './errors/TemplateAndVersionError';
import addNodeLinker from '../../tools/addNodeLinker';
import {getYarnVersionIfAvailable} from '../../tools/yarn';
import semver from 'semver';
import prompts from 'prompts';
import findUp from 'find-up';
import {parse, stringify} from 'yaml';

const DEFAULT_VERSION = 'latest';

Expand Down Expand Up @@ -78,6 +84,32 @@ function getTemplateName(cwd: string) {
return name;
}

async function overwriteYarnrcFile(filePath: string, fileContent: any) {
logger.info(
'Detected ".yarnrc.yml" file but it doesn\'t contain "nodeLinker: node-modules". To create React Native project you need to use "node-modules" as "nodeLinker"',
);

const {value} = await prompts({
type: 'confirm',
name: 'value',
message:
'Do you want to add "nodeLinker: node-modules" to "yarnrc.yml" file?',
initial: true,
});

if (value) {
fileContent.nodeLinker = 'node-modules';
fs.writeFileSync(filePath, stringify(fileContent), {
encoding: 'utf8',
flag: 'w',
});
} else {
throw new CLIError(
'In order to create React Native app you need to use "node-modules" as "nodeLinker" in ".yarnrc.yml", or use Yarn Classic.',
);
}
}

async function createFromTemplate({
projectName,
templateUri,
Expand All @@ -98,6 +130,79 @@ async function createFromTemplate({
);

try {
await PackageManager.init({
preferYarn: !npm,
silent: true,
root: templateSourceDir,
});

const yarnVersion = getYarnVersionIfAvailable();

if (!npm && yarnVersion !== null) {
if (semver.satisfies(yarnVersion, '>=3.0.0')) {
const yarnrcYmlPathLocation = await findUp('.yarnrc.yml', {
type: 'file',
});

if (yarnrcYmlPathLocation && fs.existsSync(yarnrcYmlPathLocation)) {
const yarnYmlContent = parse(
fs.readFileSync(yarnrcYmlPathLocation, 'utf8'),
);

if (
!yarnYmlContent.nodeLinker ||
yarnYmlContent.nodeLinker !== 'node-modules'
) {
await overwriteYarnrcFile(yarnrcYmlPathLocation, yarnYmlContent);
}

addNodeLinker(templateSourceDir);
szymonrybczak marked this conversation as resolved.
Show resolved Hide resolved
} else {
throw new CLIError(
'Failed to found "yarnrc.yml". To create React Native app without "yarnrc.yml" file you need to use Yarn Classic.',
);
}
} else if (semver.satisfies(yarnVersion, '>=2.0.0')) {
const yarnrcYmlPathLocation = await findUp('.yarnrc.yml', {
type: 'file',
});

if (yarnrcYmlPathLocation && fs.existsSync(yarnrcYmlPathLocation)) {
const yarnYmlContent = parse(
fs.readFileSync(yarnrcYmlPathLocation, 'utf8'),
);

if (
!yarnYmlContent.nodeLinker ||
yarnYmlContent.nodeLinker !== 'node-modules'
) {
await overwriteYarnrcFile(yarnrcYmlPathLocation, yarnYmlContent);
}

addNodeLinker(templateSourceDir);
} else {
logger.info(
`You're using Yarn at ${yarnVersion} version but you don't have ".yarnrc.yml" with "nodeLinker: node-modules". To create project without ".yarnrc.yml" file you need to use Yarn Classic.`,
);

const {value} = await prompts({
type: 'confirm',
name: 'value',
message:
'Do you want to add ".yarnrc.yml" file with "nodeLinker: node-modules" to your project?',
initial: true,
});

if (value) {
addNodeLinker(projectDirectory);
addNodeLinker(templateSourceDir);
} else {
throw new CLIError('Aborting process.');
}
}
}
}

loader.start();

await installTemplatePackage(templateUri, templateSourceDir, npm);
Expand Down
6 changes: 0 additions & 6 deletions packages/cli/src/commands/init/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ export async function installTemplatePackage(
) {
logger.debug(`Installing template from ${templateName}`);

await PackageManager.init({
preferYarn: !npm,
silent: true,
root,
});

return PackageManager.install([templateName], {
preferYarn: !npm,
silent: true,
Expand Down
17 changes: 17 additions & 0 deletions packages/cli/src/tools/addNodeLinker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import path from 'path';
import fs from 'fs';

/**
Creates a `.yarnrc.yml` file with "nodeLinker: node-module" in passed path to force Yarn to use the `node-modules` linker, because React Native doesn't support the Plug'n'Play node linker.
*/

const addNodeLinker = (root: string) => {
const yarnrcFileContent = 'nodeLinker: node-modules\n';

fs.writeFileSync(path.join(root, '.yarnrc.yml'), yarnrcFileContent, {
szymonrybczak marked this conversation as resolved.
Show resolved Hide resolved
encoding: 'utf8',
flag: 'w',
});
};

export default addNodeLinker;