UNPKG

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