UNPKG

6.17 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 spawnSync = require('cross-spawn').sync;
22const chalk = require('chalk');
23const prompt = require('react-dev-utils/prompt');
24const paths = require('../config/paths');
25const createJestConfig = require('./utils/createJestConfig');
26
27const green = chalk.green;
28const cyan = chalk.cyan;
29
30prompt(
31 'Are you sure you want to eject? This action is permanent.',
32 false
33).then(shouldEject => {
34 if (!shouldEject) {
35 console.log(cyan('Close one! Eject aborted.'));
36 process.exit(1);
37 }
38
39 console.log('Ejecting...');
40
41 const ownPath = paths.ownPath;
42 const appPath = paths.appPath;
43
44 function verifyAbsent(file) {
45 if (fs.existsSync(path.join(appPath, file))) {
46 console.error(
47 `\`${file}\` already exists in your app folder. We cannot ` +
48 'continue as you would lose all the changes in that file or directory. ' +
49 'Please move or delete it (maybe make a copy for backup) and run this ' +
50 'command again.'
51 );
52 process.exit(1);
53 }
54 }
55
56 const folders = ['config', 'config/jest', 'scripts', 'scripts/utils'];
57
58 // Make shallow array of files paths
59 const files = folders.reduce(
60 (files, folder) => {
61 return files.concat(
62 fs
63 .readdirSync(path.join(ownPath, folder))
64 // set full path
65 .map(file => path.join(ownPath, folder, file))
66 // omit dirs from file list
67 .filter(file => fs.lstatSync(file).isFile())
68 );
69 },
70 []
71 );
72
73 // Ensure that the app folder is clean and we won't override any files
74 folders.forEach(verifyAbsent);
75 files.forEach(verifyAbsent);
76
77 console.log();
78 console.log(cyan(`Copying files into ${appPath}`));
79
80 folders.forEach(folder => {
81 fs.mkdirSync(path.join(appPath, folder));
82 });
83
84 files.forEach(file => {
85 let content = fs.readFileSync(file, 'utf8');
86
87 // Skip flagged files
88 if (content.match(/\/\/ @remove-file-on-eject/)) {
89 return;
90 }
91 content = content
92 // Remove dead code from .js files on eject
93 .replace(
94 /\/\/ @remove-on-eject-begin([\s\S]*?)\/\/ @remove-on-eject-end/mg,
95 ''
96 )
97 // Remove dead code from .applescript files on eject
98 .replace(
99 /-- @remove-on-eject-begin([\s\S]*?)-- @remove-on-eject-end/mg,
100 ''
101 )
102 .trim() + '\n';
103 console.log(` Adding ${cyan(file.replace(ownPath, ''))} to the project`);
104 fs.writeFileSync(file.replace(ownPath, appPath), content);
105 });
106 console.log();
107
108 const ownPackage = require(path.join(ownPath, 'package.json'));
109 const appPackage = require(path.join(appPath, 'package.json'));
110
111 console.log(cyan('Updating the dependencies'));
112 const ownPackageName = ownPackage.name;
113 if (appPackage.devDependencies[ownPackageName]) {
114 console.log(` Removing ${cyan(ownPackageName)} from devDependencies`);
115 delete appPackage.devDependencies[ownPackageName];
116 }
117 if (appPackage.dependencies[ownPackageName]) {
118 console.log(` Removing ${cyan(ownPackageName)} from dependencies`);
119 delete appPackage.dependencies[ownPackageName];
120 }
121
122 Object.keys(ownPackage.dependencies).forEach(key => {
123 // For some reason optionalDependencies end up in dependencies after install
124 if (ownPackage.optionalDependencies[key]) {
125 return;
126 }
127 console.log(` Adding ${cyan(key)} to devDependencies`);
128 appPackage.devDependencies[key] = ownPackage.dependencies[key];
129 });
130 console.log();
131 console.log(cyan('Updating the scripts'));
132 delete appPackage.scripts['eject'];
133 Object.keys(appPackage.scripts).forEach(key => {
134 Object.keys(ownPackage.bin).forEach(binKey => {
135 const regex = new RegExp(binKey + ' (\\w+)', 'g');
136 appPackage.scripts[key] = appPackage.scripts[key].replace(
137 regex,
138 'node scripts/$1.js'
139 );
140 console.log(
141 ` Replacing ${cyan(`"${binKey} ${key}"`)} with ${cyan(`"node scripts/${key}.js"`)}`
142 );
143 });
144 });
145
146 console.log();
147 console.log(cyan('Configuring package.json'));
148 // Add Jest config
149 console.log(` Adding ${cyan('Jest')} configuration`);
150 appPackage.jest = createJestConfig(
151 filePath => path.posix.join('<rootDir>', filePath),
152 null,
153 true
154 );
155
156 // Add Babel config
157 console.log(` Adding ${cyan('Babel')} preset`);
158 appPackage.babel = {
159 presets: ['react-app'],
160 };
161
162 // Add ESlint config
163 console.log(` Adding ${cyan('ESLint')} configuration`);
164 appPackage.eslintConfig = {
165 extends: 'react-app',
166 };
167
168 fs.writeFileSync(
169 path.join(appPath, 'package.json'),
170 JSON.stringify(appPackage, null, 2) + '\n'
171 );
172 console.log();
173
174 // "Don't destroy what isn't ours"
175 if (ownPath.indexOf(appPath) === 0) {
176 try {
177 // remove react-scripts and react-scripts binaries from app node_modules
178 Object.keys(ownPackage.bin).forEach(binKey => {
179 fs.removeSync(path.join(appPath, 'node_modules', '.bin', binKey));
180 });
181 fs.removeSync(ownPath);
182 } catch (e) {
183 // It's not essential that this succeeds
184 }
185 }
186
187 if (fs.existsSync(paths.yarnLockFile)) {
188 console.log(cyan('Running yarn...'));
189 spawnSync('yarnpkg', [], { stdio: 'inherit' });
190 } else {
191 console.log(cyan('Running npm install...'));
192 spawnSync('npm', ['install'], { stdio: 'inherit' });
193 }
194 console.log(green('Ejected successfully!'));
195 console.log();
196
197 console.log(green('Please consider sharing why you ejected in this survey:'));
198 console.log(green(' http://goo.gl/forms/Bi6CZjk1EqsdelXk1'));
199 console.log();
200});