eject.js 4.04 KB
Newer Older
eanplatter's avatar
eanplatter committed
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * 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.
 */

var fs = require('fs');
var path = require('path');
var rl = require('readline');
var rimrafSync = require('rimraf').sync;
Dan Abramov's avatar
Dan Abramov committed
14
var spawnSync = require('cross-spawn').sync;
eanplatter's avatar
eanplatter committed
15
16
17
18
19
20
21
22
23
24
25
26

var prompt = function(question, cb) {
  var rlInterface = rl.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rlInterface.question(question + '\n', function(answer) {
    rlInterface.close();
    cb(answer);
  })
}

Dan Abramov's avatar
Dan Abramov committed
27
28
29
30
31
32
prompt('Are you sure you want to eject? This action is permanent. [y/N]', function(answer) {
  var shouldEject = answer && (
    answer.toLowerCase() === 'y' ||
    answer.toLowerCase() === 'yes'
  );
  if (!shouldEject) {
Tyler McGinnis's avatar
Tyler McGinnis committed
33
    console.log('Close one! Eject aborted.');
eanplatter's avatar
eanplatter committed
34
35
36
37
38
    process.exit(1);
  }

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

eanplatter's avatar
eanplatter committed
40
41
42
  var selfPath = path.join(__dirname, '..');
  var hostPath = path.join(selfPath, '..', '..');
  var files = [
43
44
    path.join('config', 'babel.dev.js'),
    path.join('config', 'babel.prod.js'),
Dan Abramov's avatar
Dan Abramov committed
45
46
    path.join('config', 'flow', 'css.js.flow'),
    path.join('config', 'flow', 'file.js.flow'),
47
    path.join('config', 'eslint.js'),
48
49
50
    path.join('config', 'webpack.config.dev.js'),
    path.join('config', 'webpack.config.prod.js'),
    path.join('scripts', 'build.js'),
51
52
    path.join('scripts', 'start.js'),
    path.join('scripts', 'openChrome.applescript')
eanplatter's avatar
eanplatter committed
53
54
55
56
  ];

  // Ensure that the host folder is clean and we won't override any files
  files.forEach(function(file) {
Dan Abramov's avatar
Dan Abramov committed
57
58
59
60
61
62
63
64
65
    if (fs.existsSync(path.join(hostPath, 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 delete it (maybe make a copy for backup) and run this ' +
        'command again.'
      );
      process.exit(1);
    }
eanplatter's avatar
eanplatter committed
66
67
  });

68
  // Copy the files over
69
  fs.mkdirSync(path.join(hostPath, 'config'));
Dan Abramov's avatar
Dan Abramov committed
70
  fs.mkdirSync(path.join(hostPath, 'config', 'flow'));
71
  fs.mkdirSync(path.join(hostPath, 'scripts'));
72

eanplatter's avatar
eanplatter committed
73
  files.forEach(function(file) {
Dan Abramov's avatar
Dan Abramov committed
74
    console.log('Copying ' + file + ' to ' + hostPath);
75
    var content = fs
76
77
78
79
80
81
      .readFileSync(path.join(selfPath, file), 'utf8')
      // Remove license header from JS
      .replace(/^\/\*\*(\*(?!\/)|[^*])*\*\//, '')
      // Remove license header from AppleScript
      .replace(/^--.*\n/gm, '')
      .trim() + '\n';
Dan Abramov's avatar
Dan Abramov committed
82
    fs.writeFileSync(path.join(hostPath, file), content);
eanplatter's avatar
eanplatter committed
83
84
85
86
87
88
  });
  console.log();

  var selfPackage = require(path.join(selfPath, 'package.json'));
  var hostPackage = require(path.join(hostPath, 'package.json'));

89
90
  console.log('Removing dependency: react-scripts');
  delete hostPackage.devDependencies['react-scripts'];
eanplatter's avatar
eanplatter committed
91
92

  Object.keys(selfPackage.dependencies).forEach(function (key) {
Dan Abramov's avatar
Dan Abramov committed
93
94
95
96
97
98
    // For some reason optionalDependencies end up in dependencies after install
    if (selfPackage.optionalDependencies[key]) {
      return;
    }
    console.log('Adding dependency: ' + key);
    hostPackage.devDependencies[key] = selfPackage.dependencies[key];
eanplatter's avatar
eanplatter committed
99
100
101
102
  });

  console.log('Updating scripts');
  Object.keys(hostPackage.scripts).forEach(function (key) {
103
    hostPackage.scripts[key] = 'node ./scripts/' + key + '.js'
eanplatter's avatar
eanplatter committed
104
105
106
  });
  delete hostPackage.scripts['eject'];

107
108
109
110
111
  // explicitly specify ESLint config path for editor plugins
  hostPackage.eslintConfig = {
    extends: './config/eslint.js',
  };

eanplatter's avatar
eanplatter committed
112
113
  console.log('Writing package.json');
  fs.writeFileSync(
Dan Abramov's avatar
Dan Abramov committed
114
115
    path.join(hostPath, 'package.json'),
    JSON.stringify(hostPackage, null, 2)
eanplatter's avatar
eanplatter committed
116
117
118
119
120
121
  );
  console.log();

  console.log('Running npm install...');
  rimrafSync(selfPath);
  spawnSync('npm', ['install'], {stdio: 'inherit'});
Dan Abramov's avatar
Dan Abramov committed
122
  console.log('Ejected successfully!');
eanplatter's avatar
eanplatter committed
123
124
  console.log();

Dan Abramov's avatar
Dan Abramov committed
125
126
127
  console.log('Please consider sharing why you ejected in this survey:');
  console.log('  http://goo.gl/forms/Bi6CZjk1EqsdelXk1');
  console.log();
eanplatter's avatar
eanplatter committed
128
});