UNPKG

5.82 kBJavaScriptView Raw
1// @remove-file-on-eject
2/**
3 * Copyright (c) 2015-present, Facebook, Inc.
4 *
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8'use strict';
9
10// Makes the script crash on unhandled rejections instead of silently
11// ignoring them. In the future, promise rejections that are not handled will
12// terminate the Node.js process with a non-zero exit code.
13process.on('unhandledRejection', err => {
14 throw err;
15});
16
17const fs = require('fs-extra');
18const path = require('path');
19const chalk = require('chalk');
20const spawn = require('react-dev-utils/crossSpawn');
21
22module.exports = function(
23 appPath,
24 appName,
25 verbose,
26 originalDirectory,
27 template
28) {
29 const ownPackageName = require(path.join(__dirname, '..', 'package.json'))
30 .name;
31 const ownPath = path.join(appPath, 'node_modules', ownPackageName);
32 const appPackage = require(path.join(appPath, 'package.json'));
33 const useYarn = fs.existsSync(path.join(appPath, 'yarn.lock'));
34
35 // Copy over some of the devDependencies
36 appPackage.dependencies = appPackage.dependencies || {};
37
38 // Setup the script rules
39 appPackage.scripts = {
40 start: 'react-scripts start',
41 build: 'react-scripts build',
42 test: 'react-scripts test --env=jsdom',
43 eject: 'react-scripts eject',
44 };
45
46 fs.writeFileSync(
47 path.join(appPath, 'package.json'),
48 JSON.stringify(appPackage, null, 2)
49 );
50
51 const readmeExists = fs.existsSync(path.join(appPath, 'README.md'));
52 if (readmeExists) {
53 fs.renameSync(
54 path.join(appPath, 'README.md'),
55 path.join(appPath, 'README.old.md')
56 );
57 }
58
59 // Copy the files for the user
60 const templatePath = template
61 ? path.resolve(originalDirectory, template)
62 : path.join(ownPath, 'template');
63 if (fs.existsSync(templatePath)) {
64 fs.copySync(templatePath, appPath);
65 } else {
66 console.error(
67 `Could not locate supplied template: ${chalk.green(templatePath)}`
68 );
69 return;
70 }
71
72 // Rename gitignore after the fact to prevent npm from renaming it to .npmignore
73 // See: https://github.com/npm/npm/issues/1862
74 fs.move(
75 path.join(appPath, 'gitignore'),
76 path.join(appPath, '.gitignore'),
77 [],
78 err => {
79 if (err) {
80 // Append if there's already a `.gitignore` file there
81 if (err.code === 'EEXIST') {
82 const data = fs.readFileSync(path.join(appPath, 'gitignore'));
83 fs.appendFileSync(path.join(appPath, '.gitignore'), data);
84 fs.unlinkSync(path.join(appPath, 'gitignore'));
85 } else {
86 throw err;
87 }
88 }
89 }
90 );
91
92 let command;
93 let args;
94
95 if (useYarn) {
96 command = 'yarnpkg';
97 args = ['add'];
98 } else {
99 command = 'npm';
100 args = ['install', '--save', verbose && '--verbose'].filter(e => e);
101 }
102 args.push('react', 'react-dom');
103
104 // Install additional template dependencies, if present
105 const templateDependenciesPath = path.join(
106 appPath,
107 '.template.dependencies.json'
108 );
109 if (fs.existsSync(templateDependenciesPath)) {
110 const templateDependencies = require(templateDependenciesPath).dependencies;
111 args = args.concat(
112 Object.keys(templateDependencies).map(key => {
113 return `${key}@${templateDependencies[key]}`;
114 })
115 );
116 fs.unlinkSync(templateDependenciesPath);
117 }
118
119 // Install react and react-dom for backward compatibility with old CRA cli
120 // which doesn't install react and react-dom along with react-scripts
121 // or template is presetend (via --internal-testing-template)
122 if (!isReactInstalled(appPackage) || template) {
123 console.log(`Installing react and react-dom using ${command}...`);
124 console.log();
125
126 const proc = spawn.sync(command, args, { stdio: 'inherit' });
127 if (proc.status !== 0) {
128 console.error(`\`${command} ${args.join(' ')}\` failed`);
129 return;
130 }
131 }
132
133 // Display the most elegant way to cd.
134 // This needs to handle an undefined originalDirectory for
135 // backward compatibility with old global-cli's.
136 let cdpath;
137 if (originalDirectory && path.join(originalDirectory, appName) === appPath) {
138 cdpath = appName;
139 } else {
140 cdpath = appPath;
141 }
142
143 // Change displayed command to yarn instead of yarnpkg
144 const displayedCommand = useYarn ? 'yarn' : 'npm';
145
146 console.log();
147 console.log(`Success! Created ${appName} at ${appPath}`);
148 console.log('Inside that directory, you can run several commands:');
149 console.log();
150 console.log(chalk.cyan(` ${displayedCommand} start`));
151 console.log(' Starts the development server.');
152 console.log();
153 console.log(
154 chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}build`)
155 );
156 console.log(' Bundles the app into static files for production.');
157 console.log();
158 console.log(chalk.cyan(` ${displayedCommand} test`));
159 console.log(' Starts the test runner.');
160 console.log();
161 console.log(
162 chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}eject`)
163 );
164 console.log(
165 ' Removes this tool and copies build dependencies, configuration files'
166 );
167 console.log(
168 ' and scripts into the app directory. If you do this, you can’t go back!'
169 );
170 console.log();
171 console.log('We suggest that you begin by typing:');
172 console.log();
173 console.log(chalk.cyan(' cd'), cdpath);
174 console.log(` ${chalk.cyan(`${displayedCommand} start`)}`);
175 if (readmeExists) {
176 console.log();
177 console.log(
178 chalk.yellow(
179 'You had a `README.md` file, we renamed it to `README.old.md`'
180 )
181 );
182 }
183 console.log();
184 console.log('Happy hacking!');
185};
186
187function isReactInstalled(appPackage) {
188 const dependencies = appPackage.dependencies || {};
189
190 return (
191 typeof dependencies.react !== 'undefined' &&
192 typeof dependencies['react-dom'] !== 'undefined'
193 );
194}