Remove react-native-cli
Summary: This is now part of https://github.com/react-native-community/react-native-cli/tree/master/packages/global-cli Reviewed By: TheSavior Differential Revision: D13396231 fbshipit-source-id: 9d490ae26bf90a79e20797c96be81f08562f4017
This commit is contained in:
parent
63a6bb7637
commit
f8e13afb23
|
@ -1,126 +0,0 @@
|
|||
## Running CLI with local modifications
|
||||
|
||||
React Native is distributed as two npm packages, `react-native-cli` and `react-native`. The first one is a lightweight package that should be installed globally (`npm install -g react-native-cli`), while the second one contains the actual React Native framework code and is installed locally into your project when you run `react-native init`.
|
||||
|
||||
Because `react-native init` calls `npm install react-native`, simply linking your local github clone into npm is not enough to test local changes.
|
||||
|
||||
### Introducing Sinopia
|
||||
|
||||
[Sinopia] is an npm registry that runs on your local machine and allows you to publish packages to it. Everything else is proxied from `npmjs.com`. We'll set up sinopia for React Native CLI development. First, install it with:
|
||||
|
||||
$ npm install -g sinopia
|
||||
|
||||
Now you can run sinopia by simply doing:
|
||||
|
||||
$ sinopia
|
||||
|
||||
Running it for the first time creates a default config file. Open `~/.config/sinopia/config.yaml` and configure it like this (note the `max_body_size`):
|
||||
|
||||
storage: ./storage
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: https://registry.npmjs.org/
|
||||
|
||||
packages:
|
||||
'react-native':
|
||||
allow_access: $all
|
||||
allow_publish: $all
|
||||
|
||||
'react-native-cli':
|
||||
allow_access: $all
|
||||
allow_publish: $all
|
||||
|
||||
'**':
|
||||
allow_access: $all
|
||||
proxy: npmjs
|
||||
|
||||
'*':
|
||||
allow_access: $all
|
||||
proxy: npmjs
|
||||
|
||||
logs:
|
||||
- {type: stdout, format: pretty, level: http}
|
||||
|
||||
max_body_size: '50mb'
|
||||
|
||||
Remember to restart sinopia afterwards.
|
||||
|
||||
### Publishing to sinopia
|
||||
|
||||
Now we need to publish the two React Native packages to our local registry. To do this, we configure npm to use the new registry, unpublish any existing packages and then publish the new ones:
|
||||
|
||||
react-native$ npm set registry http://localhost:4873/
|
||||
react-native$ npm adduser --registry http://localhost:4873/
|
||||
# Check that it worked:
|
||||
react-native$ npm config list
|
||||
react-native$ npm unpublish --force
|
||||
react-native$ npm publish
|
||||
react-native$ cd react-native-cli/
|
||||
react-native-cli$ npm unpublish --force
|
||||
react-native-cli$ npm publish
|
||||
|
||||
### Running the local CLI
|
||||
|
||||
Now that the packages are installed in sinopia, you can install the new `react-native-cli` package globally and when you use `react-native init`, it will install the new `react-native` package as well:
|
||||
|
||||
$ npm uninstall -g react-native-cli
|
||||
$ npm install -g react-native-cli
|
||||
$ react-native init AwesomeApp
|
||||
|
||||
## Testing changes
|
||||
|
||||
Most of the CLI code is covered by jest tests, which you can run with:
|
||||
|
||||
$ npm test
|
||||
|
||||
Project generation is also covered by e2e tests, which you can run with:
|
||||
|
||||
$ ./scripts/e2e-test.sh
|
||||
|
||||
These tests actually create a very similar setup to what is described above (using sinopia) and they also run iOS-specific tests, so you will need to run this on OSX and have [xctool] installed.
|
||||
|
||||
Both of these types of tests also run on Travis both continuously and on pull requests.
|
||||
|
||||
[sinopia]: https://www.npmjs.com/package/sinopia
|
||||
[xctool]: https://github.com/facebook/xctool
|
||||
|
||||
## Clean up
|
||||
|
||||
To unset the npm registry, do:
|
||||
|
||||
$ npm set registry https://registry.npmjs.org/
|
||||
# Check that it worked:
|
||||
$ npm config list
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
##### Sinopia crashes with "Module version mismatch"
|
||||
|
||||
This usually happens when you install a package using one version of Node and then change to a different version. This can happen when you update Node, or switch to a different version with nvm. Do:
|
||||
|
||||
$ npm uninstall -g sinopia
|
||||
$ npm install -g sinopia
|
||||
|
||||
After upgrading to Node 4 you might also need to reinstall npm. What worked for me was:
|
||||
|
||||
$ npm uninstall -g npm
|
||||
$ nvm install npm
|
||||
|
||||
See the [nvm guide](https://github.com/creationix/nvm#usage) for more info.
|
||||
|
||||
### Alternative workflow
|
||||
|
||||
If you don't want to install Sinopia you could still test changes done on the cli by creating a sample project and installing your checkout of `react-native` on that project instead of downloading it from npm. The simplest way to do this is by:
|
||||
|
||||
$ npm init AwesomeProject
|
||||
$ cd AwesomeProject
|
||||
$ npm install $REACT_NATIVE_GITHUB
|
||||
|
||||
Note that `REACT_NATIVE_GITHUB` should point to the directory where you have a checkout.
|
||||
|
||||
Also, if the changes you're making get triggered when running `react-native init AwesomeProject` you will want to tweak the global installed `react-native-cli` library to install the local checkout instead of downloading the module from npm. To do so just change this [line](https://github.com/facebook/react-native/blob/master/react-native-cli/index.js#L191) and refer the local checkout instead.
|
|
@ -1,346 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// /!\ DO NOT MODIFY THIS FILE /!\
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// react-native-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 react-native-cli is to init the repository and then
|
||||
// forward all the commands to the local version of react-native.
|
||||
//
|
||||
// If you need to add a new command, please add it to react-native-local-cli.
|
||||
//
|
||||
// The only reason to modify this file is to add more warnings and
|
||||
// troubleshooting information for the `react-native init` command.
|
||||
//
|
||||
// To allow for graceful failure on older node versions, this file should
|
||||
// retain ES5 compatibility.
|
||||
//
|
||||
// Do not make breaking changes! We absolutely don't want to have to
|
||||
// tell people to update their global version of react-native-cli.
|
||||
//
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// /!\ DO NOT MODIFY THIS FILE /!\
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var execSync = require('child_process').execSync;
|
||||
var chalk = require('chalk');
|
||||
var prompt = require('prompt');
|
||||
var semver = require('semver');
|
||||
/**
|
||||
* Used arguments:
|
||||
* -v --version - to print current version of react-native-cli and react-native dependency
|
||||
* if you are in a RN app folder
|
||||
* init - to create a new project and npm install it
|
||||
* --verbose - to print logs while init
|
||||
* --template - name of the template to use, e.g. --template navigation
|
||||
* --version <alternative react-native package> - override default (https://registry.npmjs.org/react-native@latest),
|
||||
* package to install, examples:
|
||||
* - "0.22.0-rc1" - A new app will be created using a specific version of React Native from npm repo
|
||||
* - "https://registry.npmjs.org/react-native/-/react-native-0.20.0.tgz" - a .tgz archive from any npm repo
|
||||
* - "/Users/home/react-native/react-native-0.22.0.tgz" - for package prepared with `npm pack`, useful for e2e tests
|
||||
*/
|
||||
|
||||
var args = require('minimist')(process.argv.slice(2));
|
||||
|
||||
var CLI_MODULE_PATH = function() {
|
||||
return path.resolve(process.cwd(), 'node_modules', 'react-native', 'cli.js');
|
||||
};
|
||||
|
||||
var REACT_NATIVE_PACKAGE_JSON_PATH = function() {
|
||||
return path.resolve(
|
||||
process.cwd(),
|
||||
'node_modules',
|
||||
'react-native',
|
||||
'package.json',
|
||||
);
|
||||
};
|
||||
|
||||
if (args._.length === 0 && (args.v || args.version)) {
|
||||
printVersionsAndExit(REACT_NATIVE_PACKAGE_JSON_PATH());
|
||||
}
|
||||
|
||||
// Use Yarn if available, it's much faster than the npm client.
|
||||
// Return the version of yarn installed on the system, null if yarn is not available.
|
||||
function getYarnVersionIfAvailable() {
|
||||
var yarnVersion;
|
||||
try {
|
||||
// execSync returns a Buffer -> convert to string
|
||||
if (process.platform.startsWith('win')) {
|
||||
yarnVersion = (execSync('yarn --version 2> NUL').toString() || '').trim();
|
||||
} else {
|
||||
yarnVersion = (
|
||||
execSync('yarn --version 2>/dev/null').toString() || ''
|
||||
).trim();
|
||||
}
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
// yarn < 0.16 has a 'missing manifest' bug
|
||||
try {
|
||||
if (semver.gte(yarnVersion, '0.16.0')) {
|
||||
return yarnVersion;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Cannot parse yarn version: ' + yarnVersion);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var cli;
|
||||
var cliPath = CLI_MODULE_PATH();
|
||||
if (fs.existsSync(cliPath)) {
|
||||
cli = require(cliPath);
|
||||
}
|
||||
|
||||
var commands = args._;
|
||||
if (cli) {
|
||||
cli.run();
|
||||
} else {
|
||||
if (args._.length === 0 && (args.h || args.help)) {
|
||||
console.log(
|
||||
[
|
||||
'',
|
||||
' Usage: react-native [command] [args]',
|
||||
'',
|
||||
'',
|
||||
' Commands:',
|
||||
'',
|
||||
' init <ProjectName> [args] generates a new project and installs its dependencies',
|
||||
'',
|
||||
' Options:',
|
||||
'',
|
||||
' -h, --help output usage information',
|
||||
' -v, --version use a specific version of React Native',
|
||||
' --template use an app template. Use --template to see available templates.',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (commands.length === 0) {
|
||||
console.error(
|
||||
'You did not pass any commands, run `react-native --help` to see a list of all available commands.',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
switch (commands[0]) {
|
||||
case 'init':
|
||||
if (!commands[1]) {
|
||||
console.error('Usage: react-native init <ProjectName> [--verbose]');
|
||||
process.exit(1);
|
||||
} else {
|
||||
init(commands[1], args);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.error(
|
||||
'Command `%s` unrecognized. ' +
|
||||
'Make sure that you have run `npm install` and that you are inside a react-native project.',
|
||||
commands[0],
|
||||
);
|
||||
process.exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function validateProjectName(name) {
|
||||
if (!String(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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Project name, e.g. 'AwesomeApp'.
|
||||
* @param options.verbose If true, will run 'npm install' in verbose mode (for debugging).
|
||||
* @param options.version Version of React Native to install, e.g. '0.38.0'.
|
||||
* @param options.npm If true, always use the npm command line client,
|
||||
* don't use yarn even if available.
|
||||
*/
|
||||
function init(name, options) {
|
||||
validateProjectName(name);
|
||||
|
||||
if (fs.existsSync(name)) {
|
||||
createAfterConfirmation(name, options);
|
||||
} else {
|
||||
createProject(name, options);
|
||||
}
|
||||
}
|
||||
|
||||
function createAfterConfirmation(name, options) {
|
||||
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 (err) {
|
||||
console.log('Error initializing project');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (result.yesno[0] === 'y') {
|
||||
createProject(name, options);
|
||||
} else {
|
||||
console.log('Project initialization canceled');
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createProject(name, options) {
|
||||
var root = path.resolve(name);
|
||||
var projectName = path.basename(root);
|
||||
|
||||
console.log(
|
||||
'This will walk you through creating a new React Native project in',
|
||||
root,
|
||||
);
|
||||
|
||||
if (!fs.existsSync(root)) {
|
||||
fs.mkdirSync(root);
|
||||
}
|
||||
|
||||
var packageJson = {
|
||||
name: projectName,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
scripts: {
|
||||
start: 'node node_modules/react-native/cli.js start',
|
||||
ios: 'react-native run-ios',
|
||||
android: 'react-native run-android',
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(
|
||||
path.join(root, 'package.json'),
|
||||
JSON.stringify(packageJson),
|
||||
);
|
||||
process.chdir(root);
|
||||
|
||||
run(root, projectName, options);
|
||||
}
|
||||
|
||||
function getInstallPackage(rnPackage) {
|
||||
var packageToInstall = 'react-native';
|
||||
var isValidSemver = semver.valid(rnPackage);
|
||||
if (isValidSemver) {
|
||||
packageToInstall += '@' + isValidSemver;
|
||||
} else if (rnPackage) {
|
||||
// for tar.gz or alternative paths
|
||||
packageToInstall = rnPackage;
|
||||
}
|
||||
return packageToInstall;
|
||||
}
|
||||
|
||||
function run(root, projectName, options) {
|
||||
var rnPackage = options.version; // e.g. '0.38' or '/path/to/archive.tgz'
|
||||
var forceNpmClient = options.npm;
|
||||
var yarnVersion = !forceNpmClient && getYarnVersionIfAvailable();
|
||||
var installCommand;
|
||||
if (options.installCommand) {
|
||||
// In CI environments it can be useful to provide a custom command,
|
||||
// to set up and use an offline mirror for installing dependencies, for example.
|
||||
installCommand = options.installCommand;
|
||||
} else {
|
||||
if (yarnVersion) {
|
||||
console.log('Using yarn v' + yarnVersion);
|
||||
console.log('Installing ' + getInstallPackage(rnPackage) + '...');
|
||||
installCommand = 'yarn add ' + getInstallPackage(rnPackage) + ' --exact';
|
||||
if (options.verbose) {
|
||||
installCommand += ' --verbose';
|
||||
}
|
||||
} else {
|
||||
console.log('Installing ' + getInstallPackage(rnPackage) + '...');
|
||||
if (!forceNpmClient) {
|
||||
console.log(
|
||||
'Consider installing yarn to make this faster: https://yarnpkg.com',
|
||||
);
|
||||
}
|
||||
installCommand =
|
||||
'npm install --save --save-exact ' + getInstallPackage(rnPackage);
|
||||
if (options.verbose) {
|
||||
installCommand += ' --verbose';
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
execSync(installCommand, {stdio: 'inherit'});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
console.error('Command `' + installCommand + '` failed.');
|
||||
process.exit(1);
|
||||
}
|
||||
checkNodeVersion();
|
||||
cli = require(CLI_MODULE_PATH());
|
||||
cli.init(root, projectName);
|
||||
}
|
||||
|
||||
function checkNodeVersion() {
|
||||
var packageJson = require(REACT_NATIVE_PACKAGE_JSON_PATH());
|
||||
if (!packageJson.engines || !packageJson.engines.node) {
|
||||
return;
|
||||
}
|
||||
if (!semver.satisfies(process.version, packageJson.engines.node)) {
|
||||
console.error(
|
||||
chalk.red(
|
||||
'You are currently running Node %s but React Native requires %s. ' +
|
||||
'Please use a supported version of Node.\n' +
|
||||
'See https://facebook.github.io/react-native/docs/getting-started.html',
|
||||
),
|
||||
process.version,
|
||||
packageJson.engines.node,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function printVersionsAndExit(reactNativePackageJsonPath) {
|
||||
console.log('react-native-cli: ' + require('./package.json').version);
|
||||
try {
|
||||
console.log('react-native: ' + require(reactNativePackageJsonPath).version);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
'react-native: n/a - not inside a React Native project directory',
|
||||
);
|
||||
}
|
||||
process.exit();
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"name": "react-native-cli",
|
||||
"version": "2.0.1",
|
||||
"license": "MIT",
|
||||
"description": "The React Native CLI tools",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/facebook/react-native.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
},
|
||||
"bin": {
|
||||
"react-native": "index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^2.4.1",
|
||||
"minimist": "^1.2.0",
|
||||
"prompt": "^0.2.14",
|
||||
"semver": "^5.0.3"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue