Skip to content

Commit

Permalink
Install react, react-dom, and react-scripts at the same time (#1253)
Browse files Browse the repository at this point in the history
* Install react and react-dom along with react-scripts

- Install react, react-dom and react-script in a same time
- Move react-scripts to devDependencies.

* Check if react, react-dom has been already installed

- To backward compatibility with old CRA’s cli
- In case old CRA doesn’t install react, react-don along with
react-scripts

* Use packageName to find script dependency

- use packageName to find dependency
- fix pathExists.sync

* Check dependencies.react in package.json instead of actual files

* Process exit when dependencies not found

- Show error and exit when dependencies not found.
- Log install show custom package name

* Remove template string

* Install dependencies if template is preseted

* Remove dangling comma

Resolves #1239
  • Loading branch information
n3tr authored and Timer committed Feb 23, 2017
1 parent 321f8b4 commit 7c4c167
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 54 deletions.
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 @@ -273,6 +279,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'
)
}

0 comments on commit 7c4c167

Please sign in to comment.