3434
3535'use strict' ;
3636
37- const validateProjectName = require ( 'validate-npm-package-name' ) ;
3837const chalk = require ( 'chalk' ) ;
3938const commander = require ( 'commander' ) ;
39+ const dns = require ( 'dns' ) ;
40+ const envinfo = require ( 'envinfo' ) ;
41+ const execSync = require ( 'child_process' ) . execSync ;
4042const fs = require ( 'fs-extra' ) ;
43+ const hyperquest = require ( 'hyperquest' ) ;
44+ const inquirer = require ( 'inquirer' ) ;
45+ const os = require ( 'os' ) ;
4146const path = require ( 'path' ) ;
42- const execSync = require ( 'child_process' ) . execSync ;
43- const spawn = require ( 'cross-spawn' ) ;
4447const semver = require ( 'semver' ) ;
45- const dns = require ( 'dns ' ) ;
48+ const spawn = require ( 'cross-spawn ' ) ;
4649const tmp = require ( 'tmp' ) ;
4750const unpack = require ( 'tar-pack' ) . unpack ;
4851const url = require ( 'url' ) ;
49- const hyperquest = require ( 'hyperquest' ) ;
50- const envinfo = require ( 'envinfo' ) ;
51- const os = require ( 'os' ) ;
52+ const validateProjectName = require ( 'validate-npm-package-name' ) ;
5253
5354const packageJson = require ( './package.json' ) ;
5455
@@ -135,7 +136,6 @@ if (program.info) {
135136 npmGlobalPackages : [ 'create-react-app' ] ,
136137 } ,
137138 {
138- clipboard : false ,
139139 duplicates : true ,
140140 showNotFound : true ,
141141 }
@@ -222,13 +222,13 @@ function createApp(
222222 process . exit ( 1 ) ;
223223 }
224224
225- if ( ! semver . satisfies ( process . version , '>=6.0 .0' ) ) {
225+ if ( ! semver . satisfies ( process . version , '>=8.10 .0' ) ) {
226226 console . log (
227227 chalk . yellow (
228228 `You are using Node ${
229229 process . version
230230 } so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
231- `Please update to Node 6 or higher for a better, fully supported experience.\n`
231+ `Please update to Node 8.10 or higher for a better, fully supported experience.\n`
232232 )
233233 ) ;
234234 // Fall back to latest supported react-scripts on Node 4
@@ -244,7 +244,7 @@ function createApp(
244244 `You are using npm ${
245245 npmInfo . npmVersion
246246 } so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
247- `Please update to npm 3 or higher for a better, fully supported experience.\n`
247+ `Please update to npm 5 or higher for a better, fully supported experience.\n`
248248 )
249249 ) ;
250250 }
@@ -255,11 +255,13 @@ function createApp(
255255 const yarnInfo = checkYarnVersion ( ) ;
256256 if ( ! yarnInfo . hasMinYarnPnp ) {
257257 if ( yarnInfo . yarnVersion ) {
258- chalk . yellow (
259- `You are using Yarn ${
260- yarnInfo . yarnVersion
261- } together with the --use-pnp flag, but Plug'n'Play is only supported starting from the 1.12 release.\n\n` +
262- `Please update to Yarn 1.12 or higher for a better, fully supported experience.\n`
258+ console . log (
259+ chalk . yellow (
260+ `You are using Yarn ${
261+ yarnInfo . yarnVersion
262+ } together with the --use-pnp flag, but Plug'n'Play is only supported starting from the 1.12 release.\n\n` +
263+ `Please update to Yarn 1.12 or higher for a better, fully supported experience.\n`
264+ )
263265 ) ;
264266 }
265267 // 1.11 had an issue with webpack-dev-middleware, so better not use PnP with it (never reached stable, but still)
@@ -380,112 +382,120 @@ function run(
380382 usePnp ,
381383 useTypescript
382384) {
383- const packageToInstall = getInstallPackage ( version , originalDirectory ) ;
384- const allDependencies = [ 'react' , 'react-dom' , packageToInstall ] ;
385- if ( useTypescript ) {
386- // TODO: get user's node version instead of installing latest
387- allDependencies . push (
388- '@types/node' ,
389- '@types/react' ,
390- '@types/react-dom' ,
391- '@types/jest' ,
392- 'typescript'
393- ) ;
394- }
395-
396- console . log ( 'Installing packages. This might take a couple of minutes.' ) ;
397- getPackageName ( packageToInstall )
398- . then ( packageName =>
399- checkIfOnline ( useYarn ) . then ( isOnline => ( {
400- isOnline : isOnline ,
401- packageName : packageName ,
402- } ) )
403- )
404- . then ( info => {
405- const isOnline = info . isOnline ;
406- const packageName = info . packageName ;
407- console . log (
408- `Installing ${ chalk . cyan ( 'react' ) } , ${ chalk . cyan (
409- 'react-dom'
410- ) } , and ${ chalk . cyan ( packageName ) } ...`
385+ getInstallPackage ( version , originalDirectory ) . then ( packageToInstall => {
386+ const allDependencies = [ 'react' , 'react-dom' , packageToInstall ] ;
387+ if ( useTypescript ) {
388+ allDependencies . push (
389+ // TODO: get user's node version instead of installing latest
390+ '@types/node' ,
391+ '@types/react' ,
392+ '@types/react-dom' ,
393+ // TODO: get version of Jest being used instead of installing latest
394+ '@types/jest' ,
395+ 'typescript'
411396 ) ;
412- console . log ( ) ;
413-
414- return install (
415- root ,
416- useYarn ,
417- usePnp ,
418- allDependencies ,
419- verbose ,
420- isOnline
421- ) . then ( ( ) => packageName ) ;
422- } )
423- . then ( async packageName => {
424- checkNodeVersion ( packageName ) ;
425- setCaretRangeForRuntimeDeps ( packageName ) ;
426-
427- const pnpPath = path . resolve ( process . cwd ( ) , '.pnp.js' ) ;
428-
429- const nodeArgs = fs . existsSync ( pnpPath ) ? [ '--require' , pnpPath ] : [ ] ;
430-
431- await executeNodeScript (
432- {
433- cwd : process . cwd ( ) ,
434- args : nodeArgs ,
435- } ,
436- [ root , appName , verbose , originalDirectory , template ] ,
437- `
397+ }
398+
399+ console . log ( 'Installing packages. This might take a couple of minutes.' ) ;
400+ getPackageName ( packageToInstall )
401+ . then ( packageName =>
402+ checkIfOnline ( useYarn ) . then ( isOnline => ( {
403+ isOnline : isOnline ,
404+ packageName : packageName ,
405+ } ) )
406+ )
407+ . then ( info => {
408+ const isOnline = info . isOnline ;
409+ const packageName = info . packageName ;
410+ console . log (
411+ `Installing ${ chalk . cyan ( 'react' ) } , ${ chalk . cyan (
412+ 'react-dom'
413+ ) } , and ${ chalk . cyan ( packageName ) } ...`
414+ ) ;
415+ console . log ( ) ;
416+
417+ return install (
418+ root ,
419+ useYarn ,
420+ usePnp ,
421+ allDependencies ,
422+ verbose ,
423+ isOnline
424+ ) . then ( ( ) => packageName ) ;
425+ } )
426+ . then ( async packageName => {
427+ checkNodeVersion ( packageName ) ;
428+ setCaretRangeForRuntimeDeps ( packageName ) ;
429+
430+ const pnpPath = path . resolve ( process . cwd ( ) , '.pnp.js' ) ;
431+
432+ const nodeArgs = fs . existsSync ( pnpPath ) ? [ '--require' , pnpPath ] : [ ] ;
433+
434+ await executeNodeScript (
435+ {
436+ cwd : process . cwd ( ) ,
437+ args : nodeArgs ,
438+ } ,
439+ [ root , appName , verbose , originalDirectory , template ] ,
440+ `
438441 var init = require('${ packageName } /scripts/init.js');
439442 init.apply(null, JSON.parse(process.argv[1]));
440443 `
441- ) ;
442-
443- if ( version === '[email protected] ' ) { 444- console . log (
445- chalk . yellow (
446- `\nNote: the project was bootstrapped with an old unsupported version of tools.\n` +
447- `Please update to Node >=6 and npm >=3 to get supported tools in new projects.\n`
448- )
449444 ) ;
450- }
451- } )
452- . catch ( reason => {
453- console . log ( ) ;
454- console . log ( 'Aborting installation.' ) ;
455- if ( reason . command ) {
456- console . log ( ` ${ chalk . cyan ( reason . command ) } has failed.` ) ;
457- } else {
458- console . log ( chalk . red ( 'Unexpected error. Please report it as a bug:' ) ) ;
459- console . log ( reason ) ;
460- }
461- console . log ( ) ;
462-
463- // On 'exit' we will delete these files from target directory.
464- const knownGeneratedFiles = [ 'package.json' , 'yarn.lock' , 'node_modules' ] ;
465- const currentFiles = fs . readdirSync ( path . join ( root ) ) ;
466- currentFiles . forEach ( file => {
467- knownGeneratedFiles . forEach ( fileToMatch => {
468- // This removes all knownGeneratedFiles.
469- if ( file === fileToMatch ) {
470- console . log ( `Deleting generated file... ${ chalk . cyan ( file ) } ` ) ;
471- fs . removeSync ( path . join ( root , file ) ) ;
472- }
445+
446+ if ( version === '[email protected] ' ) { 447+ console . log (
448+ chalk . yellow (
449+ `\nNote: the project was bootstrapped with an old unsupported version of tools.\n` +
450+ `Please update to Node >=8.10 and npm >=5 to get supported tools in new projects.\n`
451+ )
452+ ) ;
453+ }
454+ } )
455+ . catch ( reason => {
456+ console . log ( ) ;
457+ console . log ( 'Aborting installation.' ) ;
458+ if ( reason . command ) {
459+ console . log ( ` ${ chalk . cyan ( reason . command ) } has failed.` ) ;
460+ } else {
461+ console . log (
462+ chalk . red ( 'Unexpected error. Please report it as a bug:' )
463+ ) ;
464+ console . log ( reason ) ;
465+ }
466+ console . log ( ) ;
467+
468+ // On 'exit' we will delete these files from target directory.
469+ const knownGeneratedFiles = [
470+ 'package.json' ,
471+ 'yarn.lock' ,
472+ 'node_modules' ,
473+ ] ;
474+ const currentFiles = fs . readdirSync ( path . join ( root ) ) ;
475+ currentFiles . forEach ( file => {
476+ knownGeneratedFiles . forEach ( fileToMatch => {
477+ // This removes all knownGeneratedFiles.
478+ if ( file === fileToMatch ) {
479+ console . log ( `Deleting generated file... ${ chalk . cyan ( file ) } ` ) ;
480+ fs . removeSync ( path . join ( root , file ) ) ;
481+ }
482+ } ) ;
473483 } ) ;
484+ const remainingFiles = fs . readdirSync ( path . join ( root ) ) ;
485+ if ( ! remainingFiles . length ) {
486+ // Delete target folder if empty
487+ console . log (
488+ `Deleting ${ chalk . cyan ( `${ appName } /` ) } from ${ chalk . cyan (
489+ path . resolve ( root , '..' )
490+ ) } `
491+ ) ;
492+ process . chdir ( path . resolve ( root , '..' ) ) ;
493+ fs . removeSync ( path . join ( root ) ) ;
494+ }
495+ console . log ( 'Done.' ) ;
496+ process . exit ( 1 ) ;
474497 } ) ;
475- const remainingFiles = fs . readdirSync ( path . join ( root ) ) ;
476- if ( ! remainingFiles . length ) {
477- // Delete target folder if empty
478- console . log (
479- `Deleting ${ chalk . cyan ( `${ appName } /` ) } from ${ chalk . cyan (
480- path . resolve ( root , '..' )
481- ) } `
482- ) ;
483- process . chdir ( path . resolve ( root , '..' ) ) ;
484- fs . removeSync ( path . join ( root ) ) ;
485- }
486- console . log ( 'Done.' ) ;
487- process . exit ( 1 ) ;
488- } ) ;
498+ } ) ;
489499}
490500
491501function getInstallPackage ( version , originalDirectory ) {
@@ -506,7 +516,36 @@ function getInstallPackage(version, originalDirectory) {
506516 packageToInstall = version ;
507517 }
508518 }
509- return packageToInstall ;
519+
520+ const scriptsToWarn = [
521+ {
522+ name : 'react-scripts-ts' ,
523+ message : chalk . yellow (
524+ 'The react-scripts-ts package is deprecated. TypeScript is now supported natively in Create React App. You can use the --typescript option instead when generating your app to include TypeScript support. Would you like to continue using react-scripts-ts?'
525+ ) ,
526+ } ,
527+ ] ;
528+
529+ for ( const script of scriptsToWarn ) {
530+ if ( packageToInstall . startsWith ( script . name ) ) {
531+ return inquirer
532+ . prompt ( {
533+ type : 'confirm' ,
534+ name : 'useScript' ,
535+ message : script . message ,
536+ default : false ,
537+ } )
538+ . then ( answer => {
539+ if ( ! answer . useScript ) {
540+ process . exit ( 0 ) ;
541+ }
542+
543+ return packageToInstall ;
544+ } ) ;
545+ }
546+ }
547+
548+ return Promise . resolve ( packageToInstall ) ;
510549}
511550
512551function getTemporaryDirectory ( ) {
@@ -609,7 +648,7 @@ function checkNpmVersion() {
609648 npmVersion = execSync ( 'npm --version' )
610649 . toString ( )
611650 . trim ( ) ;
612- hasMinNpm = semver . gte ( npmVersion , '3 .0.0' ) ;
651+ hasMinNpm = semver . gte ( npmVersion , '5 .0.0' ) ;
613652 } catch ( err ) {
614653 // ignore
615654 }
0 commit comments