1
1
/**
2
2
* Copyright (c) 2015-present, Facebook, Inc.
3
- * All rights reserved.
4
3
*
5
- * This source code is licensed under the BSD-style license found in the
6
- * LICENSE file in the root directory of this source tree. An additional grant
7
- * of patent rights can be found in the PATENTS file in the same directory.
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
8
6
*/
9
7
10
8
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -75,14 +73,10 @@ const program = new commander.Command(packageJson.name)
75
73
) ;
76
74
console . log ( ` - a specific npm version: ${ chalk . green ( '0.8.2' ) } ` ) ;
77
75
console . log (
78
- ` - a custom fork published on npm: ${ chalk . green (
79
- 'my-react-scripts'
80
- ) } `
76
+ ` - a custom fork published on npm: ${ chalk . green ( 'my-react-scripts' ) } `
81
77
) ;
82
78
console . log (
83
- ` - a .tgz archive: ${ chalk . green (
84
- 'https://mysite.com/my-react-scripts-0.8.2.tgz'
85
- ) } `
79
+ ` - a .tgz archive: ${ chalk . green ( 'https://mysite.com/my-react-scripts-0.8.2.tgz' ) } `
86
80
) ;
87
81
console . log (
88
82
` It is not needed unless you specifically want to use a fork.`
@@ -92,9 +86,7 @@ const program = new commander.Command(packageJson.name)
92
86
` If you have any problems, do not hesitate to file an issue:`
93
87
) ;
94
88
console . log (
95
- ` ${ chalk . cyan (
96
- 'https://github.com/facebookincubator/create-react-app/issues/new'
97
- ) } `
89
+ ` ${ chalk . cyan ( 'https://github.com/facebookincubator/create-react-app/issues/new' ) } `
98
90
) ;
99
91
console . log ( ) ;
100
92
} )
@@ -160,8 +152,13 @@ function createApp(name, verbose, version, template) {
160
152
path . join ( root , 'package.json' ) ,
161
153
JSON . stringify ( packageJson , null , 2 )
162
154
) ;
155
+
156
+ const useYarn = shouldUseYarn ( ) ;
163
157
const originalDirectory = process . cwd ( ) ;
164
158
process . chdir ( root ) ;
159
+ if ( ! useYarn && ! checkThatNpmCanReadCwd ( ) ) {
160
+ process . exit ( 1 ) ;
161
+ }
165
162
166
163
if ( ! semver . satisfies ( process . version , '>=6.0.0' ) ) {
167
164
console . log (
@@ -174,7 +171,6 @@ function createApp(name, verbose, version, template) {
174
171
version = 'react-scripts@0.9.x' ;
175
172
}
176
173
177
- const useYarn = shouldUseYarn ( ) ;
178
174
if ( ! useYarn ) {
179
175
const npmInfo = checkNpmVersion ( ) ;
180
176
if ( ! npmInfo . hasMinNpm ) {
@@ -202,7 +198,7 @@ function shouldUseYarn() {
202
198
}
203
199
}
204
200
205
- function install ( useYarn , dependencies , verbose , isOnline ) {
201
+ function install ( root , useYarn , dependencies , verbose , isOnline ) {
206
202
return new Promise ( ( resolve , reject ) => {
207
203
let command ;
208
204
let args ;
@@ -214,6 +210,14 @@ function install(useYarn, dependencies, verbose, isOnline) {
214
210
}
215
211
[ ] . push . apply ( args , dependencies ) ;
216
212
213
+ // Explicitly set cwd() to work around issues like
214
+ // https://github.com/facebookincubator/create-react-app/issues/3326.
215
+ // Unfortunately we can only do this for Yarn because npm support for
216
+ // equivalent --prefix flag doesn't help with this issue.
217
+ // This is why for npm, we run checkThatNpmCanReadCwd() early instead.
218
+ args . push ( '--cwd' ) ;
219
+ args . push ( root ) ;
220
+
217
221
if ( ! isOnline ) {
218
222
console . log ( chalk . yellow ( 'You appear to be offline.' ) ) ;
219
223
console . log ( chalk . yellow ( 'Falling back to the local Yarn cache.' ) ) ;
@@ -261,23 +265,19 @@ function run(
261
265
262
266
console . log ( 'Installing packages. This might take a couple of minutes.' ) ;
263
267
getPackageName ( packageToInstall )
264
- . then ( packageName =>
265
- checkIfOnline ( useYarn ) . then ( isOnline => ( {
266
- isOnline : isOnline ,
267
- packageName : packageName ,
268
- } ) )
269
- )
268
+ . then ( packageName => checkIfOnline ( useYarn ) . then ( isOnline => ( {
269
+ isOnline : isOnline ,
270
+ packageName : packageName ,
271
+ } ) ) )
270
272
. then ( info => {
271
273
const isOnline = info . isOnline ;
272
274
const packageName = info . packageName ;
273
275
console . log (
274
- `Installing ${ chalk . cyan ( 'react' ) } , ${ chalk . cyan (
275
- 'react-dom'
276
- ) } , and ${ chalk . cyan ( packageName ) } ...`
276
+ `Installing ${ chalk . cyan ( 'react' ) } , ${ chalk . cyan ( 'react-dom' ) } , and ${ chalk . cyan ( packageName ) } ...`
277
277
) ;
278
278
console . log ( ) ;
279
279
280
- return install ( useYarn , allDependencies , verbose , isOnline ) . then (
280
+ return install ( root , useYarn , allDependencies , verbose , isOnline ) . then (
281
281
( ) => packageName
282
282
) ;
283
283
} )
@@ -341,9 +341,7 @@ function run(
341
341
if ( ! remainingFiles . length ) {
342
342
// Delete target folder if empty
343
343
console . log (
344
- `Deleting ${ chalk . cyan ( `${ appName } /` ) } from ${ chalk . cyan (
345
- path . resolve ( root , '..' )
346
- ) } `
344
+ `Deleting ${ chalk . cyan ( `${ appName } /` ) } from ${ chalk . cyan ( path . resolve ( root , '..' ) ) } `
347
345
) ;
348
346
process . chdir ( path . resolve ( root , '..' ) ) ;
349
347
fs . removeSync ( path . join ( root ) ) ;
@@ -431,9 +429,7 @@ function getPackageName(installPackage) {
431
429
/ ^ .+ \/ ( .+ ?) (?: - \d + .+ ) ? \. t g z $ /
432
430
) [ 1 ] ;
433
431
console . log (
434
- `Based on the filename, assuming it is "${ chalk . cyan (
435
- assumedProjectName
436
- ) } "`
432
+ `Based on the filename, assuming it is "${ chalk . cyan ( assumedProjectName ) } "`
437
433
) ;
438
434
return Promise . resolve ( assumedProjectName ) ;
439
435
} ) ;
@@ -496,9 +492,7 @@ function checkAppName(appName) {
496
492
const validationResult = validateProjectName ( appName ) ;
497
493
if ( ! validationResult . validForNewPackages ) {
498
494
console . error (
499
- `Could not create a project called ${ chalk . red (
500
- `"${ appName } "`
501
- ) } because of npm naming restrictions:`
495
+ `Could not create a project called ${ chalk . red ( `"${ appName } "` ) } because of npm naming restrictions:`
502
496
) ;
503
497
printValidationResults ( validationResult . errors ) ;
504
498
printValidationResults ( validationResult . warnings ) ;
@@ -510,9 +504,7 @@ function checkAppName(appName) {
510
504
if ( dependencies . indexOf ( appName ) >= 0 ) {
511
505
console . error (
512
506
chalk . red (
513
- `We cannot create a project called ${ chalk . green (
514
- appName
515
- ) } because a dependency with the same name exists.\n` +
507
+ `We cannot create a project called ${ chalk . green ( appName ) } because a dependency with the same name exists.\n` +
516
508
`Due to the way npm works, the following names are not allowed:\n\n`
517
509
) +
518
510
chalk . cyan ( dependencies . map ( depName => ` ${ depName } ` ) . join ( '\n' ) ) +
@@ -534,9 +526,7 @@ function makeCaretRange(dependencies, name) {
534
526
535
527
if ( ! semver . validRange ( patchedVersion ) ) {
536
528
console . error (
537
- `Unable to patch ${ name } dependency version because version ${ chalk . red (
538
- version
539
- ) } will become invalid ${ chalk . red ( patchedVersion ) } `
529
+ `Unable to patch ${ name } dependency version because version ${ chalk . red ( version ) } will become invalid ${ chalk . red ( patchedVersion ) } `
540
530
) ;
541
531
patchedVersion = version ;
542
532
}
@@ -606,6 +596,61 @@ function isSafeToCreateProjectIn(root, name) {
606
596
return false ;
607
597
}
608
598
599
+ function checkThatNpmCanReadCwd ( ) {
600
+ const cwd = process . cwd ( ) ;
601
+ let childOutput = null ;
602
+ try {
603
+ // Note: intentionally using spawn over exec since
604
+ // the problem doesn't reproduce otherwise.
605
+ // `npm config list` is the only reliable way I could find
606
+ // to reproduce the wrong path. Just printing process.cwd()
607
+ // in a Node process was not enough.
608
+ childOutput = spawn . sync ( 'npm' , [ 'config' , 'list' ] ) . output . join ( '' ) ;
609
+ } catch ( err ) {
610
+ // Something went wrong spawning node.
611
+ // Not great, but it means we can't do this check.
612
+ // We might fail later on, but let's continue.
613
+ return true ;
614
+ }
615
+ if ( typeof childOutput !== 'string' ) {
616
+ return true ;
617
+ }
618
+ const lines = childOutput . split ( '\n' ) ;
619
+ // `npm config list` output includes the following line:
620
+ // "; cwd = C:\path\to\current\dir" (unquoted)
621
+ // I couldn't find an easier way to get it.
622
+ const prefix = '; cwd = ' ;
623
+ const line = lines . find ( line => line . indexOf ( prefix ) === 0 ) ;
624
+ if ( typeof line !== 'string' ) {
625
+ // Fail gracefully. They could remove it.
626
+ return true ;
627
+ }
628
+ const npmCWD = line . substring ( prefix . length ) ;
629
+ if ( npmCWD === cwd ) {
630
+ return true ;
631
+ }
632
+ console . error (
633
+ chalk . red (
634
+ `Could not start an npm process in the right directory.\n\n` +
635
+ `The current directory is: ${ chalk . bold ( cwd ) } \n` +
636
+ `However, a newly started npm process runs in: ${ chalk . bold ( npmCWD ) } \n\n` +
637
+ `This is probably caused by a misconfigured system terminal shell.`
638
+ )
639
+ ) ;
640
+ if ( process . platform === 'win32' ) {
641
+ console . error (
642
+ chalk . red ( `On Windows, this can usually be fixed by running:\n\n` ) +
643
+ ` ${ chalk . cyan ( 'reg' ) } delete "HKCU\\Software\\Microsoft\\Command Processor" /v AutoRun /f\n` +
644
+ ` ${ chalk . cyan ( 'reg' ) } delete "HKLM\\Software\\Microsoft\\Command Processor" /v AutoRun /f\n\n` +
645
+ chalk . red ( `Try to run the above two lines in the terminal.\n` ) +
646
+ chalk . red (
647
+ `To learn more about this problem, read: https://blogs.msdn.microsoft.com/oldnewthing/20071121-00/?p=24433/`
648
+ )
649
+ ) ;
650
+ }
651
+ return false ;
652
+ }
653
+
609
654
function checkIfOnline ( useYarn ) {
610
655
if ( ! useYarn ) {
611
656
// Don't ping the Yarn registry.
0 commit comments