eject.js 4.09 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;
15
var paths = require('../config/paths');
eanplatter's avatar
eanplatter committed
16
17
18
19
20
21
22
23
24
25
26
27

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
28
29
30
31
32
33
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
34
    console.log('Close one! Eject aborted.');
eanplatter's avatar
eanplatter committed
35
36
37
38
39
    process.exit(1);
  }

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

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

57
  // Ensure that the app folder is clean and we won't override any files
eanplatter's avatar
eanplatter committed
58
  files.forEach(function(file) {
59
    if (fs.existsSync(path.join(appPath, file))) {
Dan Abramov's avatar
Dan Abramov committed
60
61
62
63
64
65
66
67
      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
68
69
  });

70
  // Copy the files over
71
72
73
  fs.mkdirSync(path.join(appPath, 'config'));
  fs.mkdirSync(path.join(appPath, 'config', 'flow'));
  fs.mkdirSync(path.join(appPath, 'scripts'));
74

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

88
89
  var ownPackage = require(path.join(ownPath, 'package.json'));
  var appPackage = require(path.join(appPath, 'package.json'));
eanplatter's avatar
eanplatter committed
90

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

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

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

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

eanplatter's avatar
eanplatter committed
114
115
  console.log('Writing package.json');
  fs.writeFileSync(
116
117
    path.join(appPath, 'package.json'),
    JSON.stringify(appPackage, null, 2)
eanplatter's avatar
eanplatter committed
118
119
120
121
  );
  console.log();

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

Dan Abramov's avatar
Dan Abramov committed
127
128
129
  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
130
});