eject.js 5.19 KB
Newer Older
eanplatter's avatar
eanplatter committed
1
2
3
4
5
6
7
8
9
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

10
var createJestConfig = require('../utils/createJestConfig');
11
var fs = require('fs-extra');
eanplatter's avatar
eanplatter committed
12
var path = require('path');
Ville Immonen's avatar
Ville Immonen committed
13
14
var pathExists = require('path-exists');
var paths = require('../config/paths');
15
var prompt = require('react-dev-utils/prompt');
Dan Abramov's avatar
Dan Abramov committed
16
var spawnSync = require('cross-spawn').sync;
17
18
19
var chalk = require('chalk');
var green = chalk.green;
var cyan = chalk.cyan;
eanplatter's avatar
eanplatter committed
20

21
22
23
24
prompt(
  'Are you sure you want to eject? This action is permanent.',
  false
).then(shouldEject => {
Dan Abramov's avatar
Dan Abramov committed
25
  if (!shouldEject) {
26
    console.log(cyan('Close one! Eject aborted.'));
eanplatter's avatar
eanplatter committed
27
28
29
30
    process.exit(1);
  }

  console.log('Ejecting...');
Dan Abramov's avatar
Dan Abramov committed
31

32
33
  var ownPath = path.join(__dirname, '..');
  var appPath = path.join(ownPath, '..', '..');
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

  function verifyAbsent(file) {
    if (fs.existsSync(path.join(appPath, file))) {
      console.error(
        '`' + file + '` already exists in your app folder. We cannot ' +
        'continue as you would lose all the changes in that file or directory. ' +
        'Please move or delete it (maybe make a copy for backup) and run this ' +
        'command again.'
      );
      process.exit(1);
    }
  }

  var folders = [
    'config',
    path.join('config', 'jest'),
    'scripts'
  ];

eanplatter's avatar
eanplatter committed
53
  var files = [
54
    path.join('config', 'env.js'),
55
    path.join('config', 'paths.js'),
56
    path.join('config', 'polyfills.js'),
57
58
    path.join('config', 'webpack.config.dev.js'),
    path.join('config', 'webpack.config.prod.js'),
59
60
    path.join('config', 'jest', 'cssTransform.js'),
    path.join('config', 'jest', 'fileTransform.js'),
61
    path.join('scripts', 'build.js'),
62
    path.join('scripts', 'start.js'),
63
    path.join('scripts', 'test.js')
eanplatter's avatar
eanplatter committed
64
65
  ];

66
  // Ensure that the app folder is clean and we won't override any files
67
68
  folders.forEach(verifyAbsent);
  files.forEach(verifyAbsent);
eanplatter's avatar
eanplatter committed
69

70
  // Copy the files over
71
72
73
  folders.forEach(function(folder) {
    fs.mkdirSync(path.join(appPath, folder))
  });
74

75
  console.log();
Dan Abramov's avatar
Dan Abramov committed
76
  console.log(cyan('Copying files into ' + appPath));
eanplatter's avatar
eanplatter committed
77
  files.forEach(function(file) {
Dan Abramov's avatar
Dan Abramov committed
78
    console.log('  Adding ' + cyan(file) + ' to the project');
79
    var content = fs
80
      .readFileSync(path.join(ownPath, file), 'utf8')
81
82
83
84
      // Remove dead code from .js files on eject
      .replace(/\/\/ @remove-on-eject-begin([\s\S]*?)\/\/ @remove-on-eject-end/mg, '')
      // Remove dead code from .applescript files on eject
      .replace(/-- @remove-on-eject-begin([\s\S]*?)-- @remove-on-eject-end/mg, '')
85
      .trim() + '\n';
86
    fs.writeFileSync(path.join(appPath, file), content);
eanplatter's avatar
eanplatter committed
87
88
89
  });
  console.log();

90
91
  var ownPackage = require(path.join(ownPath, 'package.json'));
  var appPackage = require(path.join(appPath, 'package.json'));
92
93
  var babelConfig = JSON.parse(fs.readFileSync(path.join(ownPath, '.babelrc'), 'utf8'));
  var eslintConfig = JSON.parse(fs.readFileSync(path.join(ownPath, '.eslintrc'), 'utf8'));
eanplatter's avatar
eanplatter committed
94

Dan Abramov's avatar
Dan Abramov committed
95
  console.log(cyan('Updating the dependencies'));
96
  var ownPackageName = ownPackage.name;
Dan Abramov's avatar
Dan Abramov committed
97
  console.log('  Removing ' + cyan(ownPackageName) + ' from devDependencies');
98
  delete appPackage.devDependencies[ownPackageName];
eanplatter's avatar
eanplatter committed
99

100
  Object.keys(ownPackage.dependencies).forEach(function (key) {
Dan Abramov's avatar
Dan Abramov committed
101
    // For some reason optionalDependencies end up in dependencies after install
102
    if (ownPackage.optionalDependencies[key]) {
Dan Abramov's avatar
Dan Abramov committed
103
104
      return;
    }
Dan Abramov's avatar
Dan Abramov committed
105
    console.log('  Adding ' + cyan(key) + ' to devDependencies');
106
    appPackage.devDependencies[key] = ownPackage.dependencies[key];
eanplatter's avatar
eanplatter committed
107
  });
108
  console.log();
Dan Abramov's avatar
Dan Abramov committed
109
  console.log(cyan('Updating the scripts'));
Dan Abramov's avatar
Dan Abramov committed
110
  delete appPackage.scripts['eject'];
111
  Object.keys(appPackage.scripts).forEach(function (key) {
Dan Abramov's avatar
Dan Abramov committed
112
    appPackage.scripts[key] = appPackage.scripts[key]
113
      .replace(/react-scripts (\w+)/g, 'node scripts/$1.js');
114
115
    console.log(
      '  Replacing ' +
Dan Abramov's avatar
Dan Abramov committed
116
      cyan('"react-scripts ' + key + '"') +
117
      ' with ' +
Dan Abramov's avatar
Dan Abramov committed
118
      cyan('"node scripts/' + key + '.js"')
119
    );
eanplatter's avatar
eanplatter committed
120
121
  });

122
  console.log();
Dan Abramov's avatar
Dan Abramov committed
123
  console.log(cyan('Configuring package.json'));
Dan Abramov's avatar
Dan Abramov committed
124
  // Add Jest config
125
  console.log('  Adding ' + cyan('Jest') + ' configuration');
Christoph Pojer's avatar
Christoph Pojer committed
126
  appPackage.jest = createJestConfig(
127
128
129
    filePath => path.join('<rootDir>', filePath),
    null,
    true
Christoph Pojer's avatar
Christoph Pojer committed
130
131
  );

132
  // Add Babel config
133
134

  console.log('  Adding ' + cyan('Babel') + ' preset');
135
136
137
  appPackage.babel = babelConfig;

  // Add ESlint config
138
  console.log('  Adding ' + cyan('ESLint') +' configuration');
139
140
  appPackage.eslintConfig = eslintConfig;

eanplatter's avatar
eanplatter committed
141
  fs.writeFileSync(
142
143
    path.join(appPath, 'package.json'),
    JSON.stringify(appPackage, null, 2)
eanplatter's avatar
eanplatter committed
144
145
146
  );
  console.log();

Ville Immonen's avatar
Ville Immonen committed
147
148
  if (pathExists.sync(paths.yarnLockFile)) {
    console.log(cyan('Running yarn...'));
149
    fs.removeSync(ownPath);
Ville Immonen's avatar
Ville Immonen committed
150
151
152
    spawnSync('yarn', [], {stdio: 'inherit'});
  } else {
    console.log(cyan('Running npm install...'));
153
    fs.removeSync(ownPath);
Ville Immonen's avatar
Ville Immonen committed
154
155
    spawnSync('npm', ['install'], {stdio: 'inherit'});
  }
156
  console.log(green('Ejected successfully!'));
eanplatter's avatar
eanplatter committed
157
158
  console.log();

159
160
161
162
  console.log(green('Please consider sharing why you ejected in this survey:'));
  console.log(green('  http://goo.gl/forms/Bi6CZjk1EqsdelXk1'));
  console.log()
})