UNPKG

6.76 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 // don't use yarn link, see: https://github.com/reasonml-community/reason-scripts/issues/20
45 prepare: 'npm link bs-platform',
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 let argsExtra;
97
98 if (useYarn) {
99 command = 'yarnpkg';
100 args = argsExtra = ['add'];
101 } else {
102 command = 'npm';
103 args = argsExtra = ['install', '--save', verbose && '--verbose'].filter(
104 e => e
105 );
106 }
107 args.push('react', 'react-dom');
108
109 // Install additional template dependencies, if present
110 const templateDependenciesPath = path.join(
111 appPath,
112 '.template.dependencies.json'
113 );
114 if (fs.existsSync(templateDependenciesPath)) {
115 const templateDependencies = require(templateDependenciesPath).dependencies;
116 args = args.concat(
117 Object.keys(templateDependencies).map(key => {
118 return `${key}@${templateDependencies[key]}`;
119 })
120 );
121 fs.unlinkSync(templateDependenciesPath);
122 }
123
124 const linkProc = spawn.sync('npm', ['link', 'bs-platform'], {
125 stdio: 'inherit',
126 });
127 if (linkProc.status !== 0) {
128 console.error(
129 `\`npm link bs-platform\` failed. Did you install bs-platform globally?`
130 );
131 return;
132 }
133
134 // Install react and react-dom for backward compatibility with old CRA cli
135 // which doesn't install react and react-dom along with react-scripts
136 // or template is presetend (via --internal-testing-template)
137 if (!isReactInstalled(appPackage) || template) {
138 console.log(`Installing react and react-dom using ${command}...`);
139 console.log();
140
141 const proc = spawn.sync(command, args, { stdio: 'inherit' });
142 if (proc.status !== 0) {
143 console.error(`\`${command} ${args.join(' ')}\` failed`);
144 return;
145 }
146 }
147
148 argsExtra.push(
149 'reason-react',
150 'bs-jest',
151 'classnames',
152 'history',
153 'immutable',
154 'react-redux',
155 'react-router-dom',
156 'react-router-redux@next',
157 'redux',
158 'redux-duck',
159 'redux-thunk'
160 );
161
162 console.log('Installing extra dependencies by react-script-appier');
163 console.log();
164
165 const procExtra = spawn.sync(command, argsExtra, { stdio: 'inherit' });
166 if (procExtra.status !== 0) {
167 console.error(`\`${command} ${argsExtra.join(' ')}\` failed`);
168 return;
169 }
170
171 // Display the most elegant way to cd.
172 // This needs to handle an undefined originalDirectory for
173 // backward compatibility with old global-cli's.
174 let cdpath;
175 if (originalDirectory && path.join(originalDirectory, appName) === appPath) {
176 cdpath = appName;
177 } else {
178 cdpath = appPath;
179 }
180
181 // Change displayed command to yarn instead of yarnpkg
182 const displayedCommand = useYarn ? 'yarn' : 'npm';
183
184 console.log();
185 console.log(`Success! Created ${appName} at ${appPath}`);
186 console.log('Inside that directory, you can run several commands:');
187 console.log();
188 console.log(chalk.cyan(` ${displayedCommand} start`));
189 console.log(' Starts the development server.');
190 console.log();
191 console.log(
192 chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}build`)
193 );
194 console.log(' Bundles the app into static files for production.');
195 console.log();
196 console.log(chalk.cyan(` ${displayedCommand} test`));
197 console.log(' Starts the test runner.');
198 console.log();
199 console.log(
200 chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}eject`)
201 );
202 console.log(
203 ' Removes this tool and copies build dependencies, configuration files'
204 );
205 console.log(
206 ' and scripts into the app directory. If you do this, you can’t go back!'
207 );
208 console.log();
209 console.log('We suggest that you begin by typing:');
210 console.log();
211 console.log(chalk.cyan(' cd'), cdpath);
212 console.log(` ${chalk.cyan(`${displayedCommand} start`)}`);
213 if (readmeExists) {
214 console.log();
215 console.log(
216 chalk.yellow(
217 'You had a `README.md` file, we renamed it to `README.old.md`'
218 )
219 );
220 }
221 console.log();
222 console.log('Happy hacking!');
223};
224
225function isReactInstalled(appPackage) {
226 const dependencies = appPackage.dependencies || {};
227
228 return (
229 typeof dependencies.react !== 'undefined' &&
230 typeof dependencies['react-dom'] !== 'undefined'
231 );
232}