UNPKG

6 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2015-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
9'use strict';
10
11var createJestConfig = require('../utils/createJestConfig');
12var fs = require('fs-extra');
13var path = require('path');
14var paths = require('../config/paths');
15var prompt = require('react-dev-utils/prompt');
16var spawnSync = require('cross-spawn').sync;
17var chalk = require('chalk');
18var green = chalk.green;
19var cyan = chalk.cyan;
20
21prompt(
22 'Are you sure you want to eject? This action is permanent.',
23 false
24).then(shouldEject => {
25 if (!shouldEject) {
26 console.log(cyan('Close one! Eject aborted.'));
27 process.exit(1);
28 }
29
30 console.log('Ejecting...');
31
32 var ownPath = paths.ownPath;
33 var appPath = paths.appPath;
34
35 function verifyAbsent(file) {
36 if (fs.existsSync(path.join(appPath, file))) {
37 console.error(
38 '`' + file + '` already exists in your app folder. We cannot ' +
39 'continue as you would lose all the changes in that file or directory. ' +
40 'Please move or delete it (maybe make a copy for backup) and run this ' +
41 'command again.'
42 );
43 process.exit(1);
44 }
45 }
46
47 var folders = [
48 'config',
49 path.join('config', 'jest'),
50 'scripts'
51 ];
52
53 var files = [
54 path.join('config', 'env.js'),
55 path.join('config', 'paths.js'),
56 path.join('config', 'polyfills.js'),
57 path.join('config', 'webpack.config.dev.js'),
58 path.join('config', 'webpack.config.prod.js'),
59 path.join('config', 'jest', 'cssTransform.js'),
60 path.join('config', 'jest', 'fileTransform.js'),
61 path.join('scripts', 'build.js'),
62 path.join('scripts', 'start.js'),
63 path.join('scripts', 'test.js')
64 ];
65
66 // Ensure that the app folder is clean and we won't override any files
67 folders.forEach(verifyAbsent);
68 files.forEach(verifyAbsent);
69
70 // Copy the files over
71 folders.forEach(function(folder) {
72 fs.mkdirSync(path.join(appPath, folder))
73 });
74
75 console.log();
76 console.log(cyan('Copying files into ' + appPath));
77 files.forEach(function(file) {
78 console.log(' Adding ' + cyan(file) + ' to the project');
79 var content = fs
80 .readFileSync(path.join(ownPath, file), 'utf8')
81 // Remove dead code from .js files on eject
82 .replace(/\/\/ @remove-on-eject-begin([\s\S]*?)\/\/ @remove-on-eject-end/mg, '')
83 // Remove dead code from .applescript files on eject
84 .replace(/-- @remove-on-eject-begin([\s\S]*?)-- @remove-on-eject-end/mg, '')
85 .trim() + '\n';
86 fs.writeFileSync(path.join(appPath, file), content);
87 });
88 console.log();
89
90 var ownPackage = require(path.join(ownPath, 'package.json'));
91 var appPackage = require(path.join(appPath, 'package.json'));
92 var babelConfig = JSON.parse(fs.readFileSync(path.join(ownPath, 'babelrc'), 'utf8'));
93 var eslintConfig = JSON.parse(fs.readFileSync(path.join(ownPath, 'eslintrc'), 'utf8'));
94
95 console.log(cyan('Updating the dependencies'));
96 var ownPackageName = ownPackage.name;
97 if (appPackage.devDependencies[ownPackageName]) {
98 console.log(' Removing ' + cyan(ownPackageName) + ' from devDependencies');
99 delete appPackage.devDependencies[ownPackageName];
100 }
101 if (appPackage.dependencies[ownPackageName]) {
102 console.log(' Removing ' + cyan(ownPackageName) + ' from dependencies');
103 delete appPackage.dependencies[ownPackageName];
104 }
105
106 Object.keys(ownPackage.dependencies).forEach(function (key) {
107 // For some reason optionalDependencies end up in dependencies after install
108 if (ownPackage.optionalDependencies[key]) {
109 return;
110 }
111 console.log(' Adding ' + cyan(key) + ' to devDependencies');
112 appPackage.devDependencies[key] = ownPackage.dependencies[key];
113 });
114 console.log();
115 console.log(cyan('Updating the scripts'));
116 delete appPackage.scripts['eject'];
117 Object.keys(appPackage.scripts).forEach(function (key) {
118 Object.keys(ownPackage.bin).forEach(function (binKey) {
119 var regex = new RegExp(binKey + ' (\\w+)', 'g');
120 appPackage.scripts[key] = appPackage.scripts[key]
121 .replace(regex, 'node scripts/$1.js');
122 console.log(
123 ' Replacing ' +
124 cyan('"' + binKey + ' ' + key + '"') +
125 ' with ' +
126 cyan('"node scripts/' + key + '.js"')
127 );
128 });
129 });
130
131 console.log();
132 console.log(cyan('Configuring package.json'));
133 // Add Jest config
134 console.log(' Adding ' + cyan('Jest') + ' configuration');
135 appPackage.jest = createJestConfig(
136 filePath => path.posix.join('<rootDir>', filePath),
137 null,
138 true
139 );
140
141 // Add Babel config
142 console.log(' Adding ' + cyan('Babel') + ' preset');
143 appPackage.babel = babelConfig;
144
145 // Add ESlint config
146 console.log(' Adding ' + cyan('ESLint') +' configuration');
147 appPackage.eslintConfig = eslintConfig;
148
149 fs.writeFileSync(
150 path.join(appPath, 'package.json'),
151 JSON.stringify(appPackage, null, 2) + '\n'
152 );
153 console.log();
154
155 // "Don't destroy what isn't ours"
156 if (ownPath.indexOf(appPath) === 0) {
157 try {
158 // remove react-scripts and react-scripts binaries from app node_modules
159 Object.keys(ownPackage.bin).forEach(function(binKey) {
160 fs.removeSync(path.join(appPath, 'node_modules', '.bin', binKey));
161 });
162 fs.removeSync(ownPath);
163 } catch(e) {
164 // It's not essential that this succeeds
165 }
166 }
167
168 if (fs.existsSync(paths.yarnLockFile)) {
169 console.log(cyan('Running yarn...'));
170 spawnSync('yarnpkg', [], {stdio: 'inherit'});
171 } else {
172 console.log(cyan('Running npm install...'));
173 spawnSync('npm', ['install'], {stdio: 'inherit'});
174 }
175 console.log(green('Ejected successfully!'));
176 console.log();
177
178 console.log(green('Please consider sharing why you ejected in this survey:'));
179 console.log(green(' http://goo.gl/forms/Bi6CZjk1EqsdelXk1'));
180 console.log()
181})