febs-react-web
Version:
A framework for building web apps with React
472 lines (414 loc) • 13 kB
JavaScript
/**
* Copyright (c) 2015-present, Alibaba Group Holding Limited.
* All rights reserved.
* 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.
*/
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// /!\ DO NOT MODIFY THIS FILE /!\
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// febs-react-web-cli is installed globally on people's computers. This means
// that it is extremely difficult to have them upgrade the version and
// because there's only one global version installed, it is very prone to
// breaking changes.
//
// The only job of febs-react-web-cli is to init the repository and then
// forward all the commands to the local version of febs-react-web.
//
// If you need to add a new command, please add it to local-cli/.
//
// The only reason to modify this file is to add more warnings and
// troubleshooting information for the `febs-react-web init` command.
//
// Do not make breaking changes! We absolutely don't want to have to
// tell people to update their global version of febs-react-web-cli.
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// /!\ DO NOT MODIFY THIS FILE /!\
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
var colors = require('colors');
colors.setTheme({
silly: 'rainbow',
input: 'grey',
verbose: 'cyan',
prompt: 'red',
info: 'green',
data: 'blue',
help: 'cyan',
warn: 'yellow',
debug: 'magenta',
error: 'red'
});
var fs = require('fs');
var path = require('path');
var exec = require('child_process').exec;
var spawn = require('cross-spawn');
var chalk = require('chalk');
var prompt = require('prompt');
var semver = require('semver');
var febs = require('febs');
var os = require('os');
var reactnativeVer = '0.42.0';
var is_win = (os.platform().indexOf('win') == 0);
/**
* Used arguments:
* -v --version - to print current version of febs-react-web-cli and febs-react-web dependency
* if you are in a RW app folder
* init - to create a new project and npm install it
* --verbose - to print logs while init
* --version <alternative febs-react-web package> - override default (https://registry.npmjs.org/febs-react-web@latest),
* package to install
*/
var argv = require('minimist')(process.argv.slice(2));
var CLI_MODULE_PATH = function() {
return path.resolve(
process.cwd(),
'node_modules',
'febs-react-web',
'local-cli',
'cli.js'
);
};
var REACT_WEB_PACKAGE_JSON_PATH = function() {
return path.resolve(
process.cwd(),
'node_modules',
'febs-react-web',
'package.json'
);
};
console.log('');
console.log('-----------------------------------------------------------------'.info);
console.log('* Create Febs Web Project *'.info);
console.log('* - If occurs the Permission error, solved by follow: *'.info);
console.log('* 1. '.info + 'sudo'.prompt + ' febs-react-web init dirname *'.info);
console.log('* or 2. '.info + 'chown -R -v username dirname'.prompt + ' *'.info);
console.log('-----------------------------------------------------------------'.info);
console.log('');
checkForVersionArgument();
var cli;
var cliPath = CLI_MODULE_PATH();
if (fs.existsSync(cliPath)) {
cli = require(cliPath);
}
// minimist api
var commands = argv._;
if (cli) {
cli.run();
} else {
if (commands.length === 0) {
console.error(
'You did not pass any commands, did you mean to run `' + 'febs-react-web init'.info + '`?'
);
process.exit(1);
}
switch (commands[0]) {
case 'init':
if (!commands[1]) {
console.error(
'Usage: ' + 'febs-react-web init <ProjectName> [--verbose] [--version=0.0.1]'.info
);
process.exit(1);
} else {
init(commands[1], argv.verbose, argv.version);
}
break;
default:
console.error(
'Command `%s` unrecognized. ' +
'Make sure that you have run `' + 'npm install'.info + '` and that you are inside a febs-react-web project.',
commands[0]
);
process.exit(1);
break;
}
}
function validatePackageName(name) {
if (!name.match(/^[$A-Z_][0-9A-Z_$]*$/i)) {
console.error(
'"%s" is not a valid name for a project. Please use a valid identifier ' +
'name (alphanumeric).',
name
);
process.exit(1);
}
if (name === 'React') {
console.error(
'"%s" is not a valid name for a project. Please do not use the ' +
'reserved word "React".',
name
);
process.exit(1);
}
}
function init(name, verbose, rwPackage) {
validatePackageName(name);
if (fs.existsSync(name)) {
createAfterConfirmation(name, verbose, rwPackage);
} else {
createProject(name, verbose, rwPackage);
}
}
function useCnpmConfirmation(cb) {
prompt.start();
var property = {
name: 'usecnpm',
message: 'Do you wanna use taobao npm registry?',
validator: /y[es]*|n[o]?/,
warning: 'Must respond yes or no',
default: 'no'
};
prompt.get(property, function (err, result) {
if (result.usecnpm[0] === 'y') {
console.log('will config registry to https://registry.npm.taobao.org'.verbose);
exec('npm config set registry "https://registry.npm.taobao.org"', function(e, stdout, stderr) {
if (e) {
console.error('npm set registry failed');
console.error(e);
process.exit(1);
}
cb&&cb();
});
} else {
exec('npm config set registry "https://registry.npmjs.org/"', function(e, stdout, stderr) {
if (e) {
console.error('npm set registry failed');
console.error(e);
process.exit(1);
}
cb&&cb();
});
}
});
}
function installRNCliConfirmation(cb) {
prompt.start();
var property = {
name: 'rncli',
message: 'Did you already install ' + 'react-native-cli'.info + '?',
validator: /y[es]*|n[o]?/,
warning: 'Must respond yes or no',
default: 'yes'
};
prompt.get(property, function (err, result) {
if (result.rncli[0] === 'n') {
console.log('Installing ' + 'react-native-cli'.info + ' package from npm...');
var proc = spawn('npm', [
'install',
'--g',
(is_win ? 'yarn' : ''),
'react-native-cli'
], {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
console.error('install react-native-cli failed');
console.error(code);
process.exit(1);
}
cb && cb();
});
} else {
cb && cb();
}
});
}
function restoreNpmConfirmation() {
prompt.start();
var property = {
name: 'restorenpm',
message: 'Do you restore npm registry -> https://registry.npmjs.org/',
validator: /y[es]*|n[o]?/,
warning: 'Must respond yes or no',
default: 'no'
};
prompt.get(property, function (err, result) {
if (result.restorenpm[0] === 'y') {
console.log('will config registry to https://registry.npmjs.org/'.verbose);
exec('npm config set registry "https://registry.npmjs.org/"', function(e, stdout, stderr) {
if (e) {
console.error('npm set registry failed');
console.error(e);
process.exit(1);
}
});
} else {
}
});
}
function createAfterConfirmation(name, verbose, rwPackage) {
prompt.start();
var property = {
name: 'yesno',
message: 'Directory ' + name + ' already exists. Continue?',
validator: /y[es]*|n[o]?/,
warning: 'Must respond yes or no',
default: 'no'
};
prompt.get(property, function (err, result) {
if (result.yesno[0] === 'y') {
createProject(name, verbose, rwPackage);
} else {
console.log('Project initialization canceled');
process.exit();
}
});
}
function createProject(name, verbose, rwPackage) {
var root = path.resolve(name);
var projectName = path.basename(root);
useCnpmConfirmation(function(){
installRNCliConfirmation(function(){
installReactNative(projectName, reactnativeVer, function(){
console.log(
'This will walk you through creating a new [' + 'Febs React Web'.info + '] project in',
root.info
);
if (!fs.existsSync(root)) {
fs.mkdirSync(root);
}
var packageJsonPath = path.join(root, 'package.json');
if (!fs.existsSync(packageJsonPath)) {
var packageJson = {
name: projectName,
version: '0.0.1',
private: true,
};
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(packageJson));
}
process.chdir(root);
if (verbose) {
runVerbose(root, projectName, rwPackage);
} else {
run(root, projectName, rwPackage);
}
});
});
});
}
function getInstallPackage(rwPackage) {
var packageToInstall = 'febs-react-web';
var valideSemver = semver.valid(rwPackage);
if (valideSemver) {
packageToInstall += '@' + valideSemver;
} else if (rwPackage) {
// for tar.gz or alternative paths
packageToInstall = rwPackage;
}
console.log('Installing ' + packageToInstall.info + ' package from npm...');
return packageToInstall;
}
function run(root, projectName, rwPackage) {
var proc = spawn('npm', ['install', '--save', '--save-exact', getInstallPackage(rwPackage)], {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
console.error('`npm install --save --save-exact febs-react-web` failed');
return;
}
checkForDependencies(function(err){
if (!err) {
var cli = require(CLI_MODULE_PATH());
cli.init(root, projectName, function(err){
restoreNpmConfirmation();
});
}
});
});
}
function runVerbose(root, projectName, rwPackage) {
var proc = spawn('npm', ['install', '--verbose', '--save', '--save-exact', getInstallPackage(rwPackage)], {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
console.error('`npm install --save --save-exact febs-react-web` failed');
return;
}
checkForDependencies(function(err){
if (!err) {
var cli = require(CLI_MODULE_PATH());
cli.init(root, projectName, function(err){
restoreNpmConfirmation();
});
}
});
});
}
function checkForVersionArgument() {
if (argv._.length === 0 && (argv.v || argv.version)) {
console.log('febs-react-web-cli: ' + require('./package.json').version);
try {
console.log('febs-react-web: ' + require(REACT_WEB_PACKAGE_JSON_PATH()).version);
} catch (e) {
console.log('febs-react-web: n/a - not inside a React Web project directory')
}
process.exit();
}
}
function installReactNative(projectName, version, cb) {
// react-native.
console.log('It will take a while...'.input);
console.log('Creating a ' + 'react-native'.info + (version?'@'+version:'').info + ' project...');
var proc = spawn('react-native', [
'init',
projectName,
(version ? '--version='+version : '')
], {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
console.error('install react-native' + (version?'@'+version:'') + ' failed');
console.error(code);
process.exit(1);
} else {
cb&&cb(code);
}
});
}
function checkForDependencies(cb) {
cb && cb();
// console.log('Installing dependencies package from npm...');
// checkForDependenciesPkgVer('react', '15.3.2', false, function(){
// checkForDependenciesPkgVer('react-dom', '15.3.2', false, function(){
// checkForDependenciesPkgVer('febs-react-component', null, false, function(){
// cb && cb();
// });
// });
// });
}
function checkForDependenciesPkg(pkgName, jsonFile, verbose, cb) {
console.log('Installing ' + pkgName.info + ' from npm...');
var proc = spawn('npm', [
'install',
verbose? '--verbose': '',
pkgName+ (jsonFile? '@' + require(jsonFile).dependencies[pkgName] : ''),
], {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
console.error('`npm install`' + pkgName + ' failed');
cb&&cb(code);
} else {
cb&&cb(code);
}
});
}
function checkForDependenciesPkgVer(pkgName, version, verbose, cb) {
console.log('Installing ' + pkgName.info + ' from npm...');
var proc = spawn('npm', [
'install',
verbose? '--verbose': '',
'--save',
pkgName+ (version? '@' + version : ''),
], {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
console.error('`npm install`' + pkgName + ' failed');
cb&&cb(code);
} else {
cb&&cb(code);
}
});
}