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

Install React, ReactDOM and React-Scripts at the same time #1253

Merged
merged 8 commits into from
Feb 23, 2017
Merged
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
53 changes: 43 additions & 10 deletions packages/create-react-app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

var chalk = require('chalk');

var currentNodeVersion = process.versions.node
var currentNodeVersion = process.versions.node;
if (currentNodeVersion.split('.')[0] < 4) {
console.error(
chalk.red(
Expand Down Expand Up @@ -124,7 +124,7 @@ function createApp(name, verbose, version, template) {
var packageJson = {
name: appName,
version: '0.1.0',
private: true,
private: true
};
fs.writeFileSync(
path.join(root, 'package.json'),
Expand All @@ -133,10 +133,6 @@ function createApp(name, verbose, version, template) {
var originalDirectory = process.cwd();
process.chdir(root);

console.log('Installing packages. This might take a couple minutes.');
console.log('Installing ' + chalk.cyan('react-scripts') + '...');
console.log();

run(root, appName, version, verbose, originalDirectory, template);
}

Expand All @@ -149,15 +145,15 @@ function shouldUseYarn() {
}
}

function install(packageToInstall, verbose, callback) {
function install(dependencies, verbose, callback) {
var command;
var args;
if (shouldUseYarn()) {
command = 'yarnpkg';
args = [ 'add', '--dev', '--exact', packageToInstall];
args = [ 'add', '--exact'].concat(dependencies);
} else {
command = 'npm';
args = ['install', '--save-dev', '--save-exact', packageToInstall];
args = ['install', '--save', '--save-exact'].concat(dependencies);
}

if (verbose) {
Expand All @@ -174,14 +170,24 @@ function run(root, appName, version, verbose, originalDirectory, template) {
var packageToInstall = getInstallPackage(version);
var packageName = getPackageName(packageToInstall);

install(packageToInstall, verbose, function(code, command, args) {
var allDependencies = ['react', 'react-dom', packageToInstall];

console.log('Installing packages. This might take a couple minutes.');
console.log('Installing ' + chalk.cyan('react, react-dom, ' + packageName) + '...');
console.log();

install(allDependencies, verbose, function(code, command, args) {
if (code !== 0) {
console.error(chalk.cyan(command + ' ' + args.join(' ')) + ' failed');
process.exit(1);
}

checkNodeVersion(packageName);

// Since react-scripts has been installed with --save
// We need to move it into devDependencies and rewrite package.json
moveReactScriptsToDev(packageName);

var scriptsPath = path.resolve(
process.cwd(),
'node_modules',
Expand Down Expand Up @@ -268,6 +274,33 @@ function checkAppName(appName) {
}
}

function moveReactScriptsToDev(packageName) {
var packagePath = path.join(process.cwd(), 'package.json');
var packageJson = require(packagePath);

if (typeof packageJson.dependencies === 'undefined') {
console.error(
chalk.red('Missing dependencies in package.json')
);
process.exit(1);
}

var packageVersion = packageJson.dependencies[packageName];

if (typeof packageVersion === 'undefined') {
console.error(
chalk.red('Unable to find ' + packageName + ' in package.json')
);
process.exit(1);
}

packageJson.devDependencies = packageJson.devDependencies || {};
packageJson.devDependencies[packageName] = packageVersion;
delete packageJson.dependencies[packageName];

fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2));
}

// If project only contains files generated by GH, it’s safe.
// We also special case IJ-based products .idea because it integrates with CRA:
// https://github.com/facebookincubator/create-react-app/pull/368#issuecomment-243446094
Expand Down
98 changes: 54 additions & 44 deletions packages/react-scripts/scripts/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ module.exports = function(appPath, appName, verbose, originalDirectory, template
}
});

// Run yarn or npm for react and react-dom
// TODO: having to do two npm/yarn installs is bad, can we avoid it?
var command;
var args;

Expand All @@ -92,53 +90,65 @@ module.exports = function(appPath, appName, verbose, originalDirectory, template
fs.unlinkSync(templateDependenciesPath);
}

console.log('Installing react and react-dom using ' + command + '...');
console.log();
// Install react and react-dom for backward compatibility with old CRA cli
// which doesn't install react and react-dom along with react-scripts
// or template is presetend (via --internal-testing-template)
if (!isReactInstalled(appPackage) || template) {
console.log('Installing react and react-dom using ' + command + '...');
console.log();

var proc = spawn(command, args, {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
var proc = spawn.sync(command, args, {stdio: 'inherit'});
if (proc.status !== 0) {
console.error('`' + command + ' ' + args.join(' ') + '` failed');
return;
}
}

// Display the most elegant way to cd.
// This needs to handle an undefined originalDirectory for
// backward compatibility with old global-cli's.
var cdpath;
if (originalDirectory &&
path.join(originalDirectory, appName) === appPath) {
cdpath = appName;
} else {
cdpath = appPath;
}
// Display the most elegant way to cd.
// This needs to handle an undefined originalDirectory for
// backward compatibility with old global-cli's.
var cdpath;
if (originalDirectory &&
path.join(originalDirectory, appName) === appPath) {
cdpath = appName;
} else {
cdpath = appPath;
}

console.log();
console.log('Success! Created ' + appName + ' at ' + appPath);
console.log('Inside that directory, you can run several commands:');
console.log();
console.log(chalk.cyan(' ' + command + ' start'));
console.log(' Starts the development server.');
console.log();
console.log(chalk.cyan(' ' + command + ' run build'));
console.log(' Bundles the app into static files for production.');
console.log();
console.log(chalk.cyan(' ' + command + ' test'));
console.log(' Starts the test runner.');
console.log();
console.log(chalk.cyan(' ' + command + ' run eject'));
console.log(' Removes this tool and copies build dependencies, configuration files');
console.log(' and scripts into the app directory. If you do this, you can’t go back!');
console.log();
console.log('We suggest that you begin by typing:');
console.log();
console.log(chalk.cyan(' cd'), cdpath);
console.log(' ' + chalk.cyan(command + ' start'));
if (readmeExists) {
console.log();
console.log('Success! Created ' + appName + ' at ' + appPath);
console.log('Inside that directory, you can run several commands:');
console.log();
console.log(chalk.cyan(' ' + command + ' start'));
console.log(' Starts the development server.');
console.log();
console.log(chalk.cyan(' ' + command + ' run build'));
console.log(' Bundles the app into static files for production.');
console.log();
console.log(chalk.cyan(' ' + command + ' test'));
console.log(' Starts the test runner.');
console.log();
console.log(chalk.cyan(' ' + command + ' run eject'));
console.log(' Removes this tool and copies build dependencies, configuration files');
console.log(' and scripts into the app directory. If you do this, you can’t go back!');
console.log();
console.log('We suggest that you begin by typing:');
console.log();
console.log(chalk.cyan(' cd'), cdpath);
console.log(' ' + chalk.cyan(command + ' start'));
if (readmeExists) {
console.log();
console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`'));
}
console.log();
console.log('Happy hacking!');
});
console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`'));
}
console.log();
console.log('Happy hacking!');
};

function isReactInstalled(appPackage) {
var dependencies = appPackage.dependencies || {};

return (
typeof dependencies.react !== 'undefined' &&
typeof dependencies['react-dom'] !== 'undefined'
)
}