Skip to content

Commit a82896c

Browse files
n3trTimer
authored andcommitted
Install react, react-dom, and react-scripts at the same time (#1253)
* 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
1 parent d945370 commit a82896c

File tree

2 files changed

+97
-54
lines changed

2 files changed

+97
-54
lines changed

packages/create-react-app/index.js

+43-10
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
var chalk = require('chalk');
4242

43-
var currentNodeVersion = process.versions.node
43+
var currentNodeVersion = process.versions.node;
4444
if (currentNodeVersion.split('.')[0] < 4) {
4545
console.error(
4646
chalk.red(
@@ -124,7 +124,7 @@ function createApp(name, verbose, version, template) {
124124
var packageJson = {
125125
name: appName,
126126
version: '0.1.0',
127-
private: true,
127+
private: true
128128
};
129129
fs.writeFileSync(
130130
path.join(root, 'package.json'),
@@ -133,10 +133,6 @@ function createApp(name, verbose, version, template) {
133133
var originalDirectory = process.cwd();
134134
process.chdir(root);
135135

136-
console.log('Installing packages. This might take a couple minutes.');
137-
console.log('Installing ' + chalk.cyan('react-scripts') + '...');
138-
console.log();
139-
140136
run(root, appName, version, verbose, originalDirectory, template);
141137
}
142138

@@ -149,15 +145,15 @@ function shouldUseYarn() {
149145
}
150146
}
151147

152-
function install(packageToInstall, verbose, callback) {
148+
function install(dependencies, verbose, callback) {
153149
var command;
154150
var args;
155151
if (shouldUseYarn()) {
156152
command = 'yarnpkg';
157-
args = [ 'add', '--dev', '--exact', packageToInstall];
153+
args = [ 'add', '--exact'].concat(dependencies);
158154
} else {
159155
command = 'npm';
160-
args = ['install', '--save-dev', '--save-exact', packageToInstall];
156+
args = ['install', '--save', '--save-exact'].concat(dependencies);
161157
}
162158

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

177-
install(packageToInstall, verbose, function(code, command, args) {
173+
var allDependencies = ['react', 'react-dom', packageToInstall];
174+
175+
console.log('Installing packages. This might take a couple minutes.');
176+
console.log('Installing ' + chalk.cyan('react, react-dom, ' + packageName) + '...');
177+
console.log();
178+
179+
install(allDependencies, verbose, function(code, command, args) {
178180
if (code !== 0) {
179181
console.error(chalk.cyan(command + ' ' + args.join(' ')) + ' failed');
180182
process.exit(1);
181183
}
182184

183185
checkNodeVersion(packageName);
184186

187+
// Since react-scripts has been installed with --save
188+
// We need to move it into devDependencies and rewrite package.json
189+
moveReactScriptsToDev(packageName);
190+
185191
var scriptsPath = path.resolve(
186192
process.cwd(),
187193
'node_modules',
@@ -273,6 +279,33 @@ function checkAppName(appName) {
273279
}
274280
}
275281

282+
function moveReactScriptsToDev(packageName) {
283+
var packagePath = path.join(process.cwd(), 'package.json');
284+
var packageJson = require(packagePath);
285+
286+
if (typeof packageJson.dependencies === 'undefined') {
287+
console.error(
288+
chalk.red('Missing dependencies in package.json')
289+
);
290+
process.exit(1);
291+
}
292+
293+
var packageVersion = packageJson.dependencies[packageName];
294+
295+
if (typeof packageVersion === 'undefined') {
296+
console.error(
297+
chalk.red('Unable to find ' + packageName + ' in package.json')
298+
);
299+
process.exit(1);
300+
}
301+
302+
packageJson.devDependencies = packageJson.devDependencies || {};
303+
packageJson.devDependencies[packageName] = packageVersion;
304+
delete packageJson.dependencies[packageName];
305+
306+
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2));
307+
}
308+
276309
// If project only contains files generated by GH, it’s safe.
277310
// We also special case IJ-based products .idea because it integrates with CRA:
278311
// https://github.com/facebookincubator/create-react-app/pull/368#issuecomment-243446094

packages/react-scripts/scripts/init.js

+54-44
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ module.exports = function(appPath, appName, verbose, originalDirectory, template
6464
}
6565
});
6666

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

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

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

98-
var proc = spawn(command, args, {stdio: 'inherit'});
99-
proc.on('close', function (code) {
100-
if (code !== 0) {
100+
var proc = spawn.sync(command, args, {stdio: 'inherit'});
101+
if (proc.status !== 0) {
101102
console.error('`' + command + ' ' + args.join(' ') + '` failed');
102103
return;
103104
}
105+
}
104106

105-
// Display the most elegant way to cd.
106-
// This needs to handle an undefined originalDirectory for
107-
// backward compatibility with old global-cli's.
108-
var cdpath;
109-
if (originalDirectory &&
110-
path.join(originalDirectory, appName) === appPath) {
111-
cdpath = appName;
112-
} else {
113-
cdpath = appPath;
114-
}
107+
// Display the most elegant way to cd.
108+
// This needs to handle an undefined originalDirectory for
109+
// backward compatibility with old global-cli's.
110+
var cdpath;
111+
if (originalDirectory &&
112+
path.join(originalDirectory, appName) === appPath) {
113+
cdpath = appName;
114+
} else {
115+
cdpath = appPath;
116+
}
115117

118+
console.log();
119+
console.log('Success! Created ' + appName + ' at ' + appPath);
120+
console.log('Inside that directory, you can run several commands:');
121+
console.log();
122+
console.log(chalk.cyan(' ' + command + ' start'));
123+
console.log(' Starts the development server.');
124+
console.log();
125+
console.log(chalk.cyan(' ' + command + ' run build'));
126+
console.log(' Bundles the app into static files for production.');
127+
console.log();
128+
console.log(chalk.cyan(' ' + command + ' test'));
129+
console.log(' Starts the test runner.');
130+
console.log();
131+
console.log(chalk.cyan(' ' + command + ' run eject'));
132+
console.log(' Removes this tool and copies build dependencies, configuration files');
133+
console.log(' and scripts into the app directory. If you do this, you can’t go back!');
134+
console.log();
135+
console.log('We suggest that you begin by typing:');
136+
console.log();
137+
console.log(chalk.cyan(' cd'), cdpath);
138+
console.log(' ' + chalk.cyan(command + ' start'));
139+
if (readmeExists) {
116140
console.log();
117-
console.log('Success! Created ' + appName + ' at ' + appPath);
118-
console.log('Inside that directory, you can run several commands:');
119-
console.log();
120-
console.log(chalk.cyan(' ' + command + ' start'));
121-
console.log(' Starts the development server.');
122-
console.log();
123-
console.log(chalk.cyan(' ' + command + ' run build'));
124-
console.log(' Bundles the app into static files for production.');
125-
console.log();
126-
console.log(chalk.cyan(' ' + command + ' test'));
127-
console.log(' Starts the test runner.');
128-
console.log();
129-
console.log(chalk.cyan(' ' + command + ' run eject'));
130-
console.log(' Removes this tool and copies build dependencies, configuration files');
131-
console.log(' and scripts into the app directory. If you do this, you can’t go back!');
132-
console.log();
133-
console.log('We suggest that you begin by typing:');
134-
console.log();
135-
console.log(chalk.cyan(' cd'), cdpath);
136-
console.log(' ' + chalk.cyan(command + ' start'));
137-
if (readmeExists) {
138-
console.log();
139-
console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`'));
140-
}
141-
console.log();
142-
console.log('Happy hacking!');
143-
});
141+
console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`'));
142+
}
143+
console.log();
144+
console.log('Happy hacking!');
144145
};
146+
147+
function isReactInstalled(appPackage) {
148+
var dependencies = appPackage.dependencies || {};
149+
150+
return (
151+
typeof dependencies.react !== 'undefined' &&
152+
typeof dependencies['react-dom'] !== 'undefined'
153+
)
154+
}

0 commit comments

Comments
 (0)