最近一段时间一直在写 RN 的项目,期间遇到了挺多的坑,而后想着记录一下填坑的过程(想看答案的小伙伴能够忽略个人心厉路程,直接跳到结尾总结处)。html
因而乎,第一步,赶忙新建一个demo,飞快地在 terminal 中输入 react native init yx_rnDemo
,漫长的等待后,项目成功创建。 而后用 IDE 打开 demo ,执行react-native run-android
命令,结果半路夭折,没跑起来。仔细一看错误日志,发现 android 各类依赖都下载失败。而后看了下 package.json
中 react-native 的版本,发现引用的是最新版本,而后点击查看 android 文件夹,发现引用的 gradle 版本是 3.1.4 ,然鹅我用的仍是 2.3.3 的版本。。node
由于比较懒(这句话在个人博客中出现的次数不低,懒是万恶之源,罪过罪过~~),不想升级,再配置一系列东西,因此按照 中文网 给出的建立指定版本的方法:react
提示:你可使用--version参数(注意是两个杠)建立指定版本的项目。例如react-native init MyApp --version 0.44.3。注意版本号必须精确到两个小数点android
删掉 demo ,从新输入 react native init yx_rnDemo --version0.47.2
,结果最后发现其实建立的仍是最新版。。(心里 OS,what??其实细心的朋友估计已经发现问题了,哈哈,嘘~~)git
而后开始各类面向搜索引擎,发现你们都是这样建立的啊,而且 RN 官网上给出的命令也是这样的,为何别人没有问题,到我这就有问题了呢。github
而后换了一个命令执行: react-native init yx_rnDemo --verbose --version 0.47.2
想来看一下建立项目的详细信息,结果最后显示建立的居然是对的!! 就是 0.47.2 。shell
难道说加了一个 --verbose
条件就能建立成功了?不对啊,我看了下说 --verbose
条件只是会输出详细信息的啊,照理说不该该对结果产生什么影响的。而后不信邪的我把 --verbose
命令去掉,又执行了react-native init yx_rnDemo --version 0.47.2
,过了一会发现,居然也是对的!!npm
吓得我赶忙去翻我第一次写的命令,一对比,发现我第一个命令--verison
后没有换行~~json
第一次的:react native init yx_rnDemo --version0.47.2 第二次的:react-native init yx_rnDemo --version 0.47.2react-native
原本到这就能够结束的,然而做为一个想有灵魂的程序猿,仍是很想弄清楚为何不加空格就会建立最新版本,而不是提示语法错误的缘由。
这里首先介绍一下, react-native 源码中 react-native-cli 文件夹下的 index.js 这个文件很重要,它惟一的工做是初始化存储库,而后将全部命令转发到本地的 react-native 版本。因此咱们初始化项目时作的操做能够在这个文件中找到。
打开这个 js 文件,而后开始一探究竟吧。 1.
'use strict';
var fs = require('fs');
var path = require('path');
var exec = require('child_process').exec;
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 options = require('minimist')(process.argv.slice(2));
复制代码
文件的前 62 行都是在声明变量及引用,其中有几个变量这里咱们须要知道它们是的做用:
变量名 | 含义 |
---|---|
fs | Node.js 中 文件系统操做的模块 |
path | Node.js 中用于处理文件路径的小工具的模块 |
exec | Node.js 中子进程模块, 衍生一个 shell 并在 shell 上运行命令 |
execSync | exec 的同步函数,会阻塞 Node.js 事件循环 |
chalk | 定制控制台日志的输入样式的一个插件 |
prompt | node 命令行输入控件 |
semver | semver 语义化版本号 |
options | 轻量级的命令行参数解析工具 |
其中一个很关键的变量 options ,也就是引用的require('minimist')(process.argv.slice(2))
,是一个命令行参数解析工具,具体的介绍能够参考这里,它是以键值对进行解析的。好比咱们输入的命令行是:react-native init yx_rnDemo --version 0.47.2
,其中 --version 0.47.2
就是一个可解析的键值对,key 为 version , value 为 0.47.2 。
这个文件中,咱们有用到的键值对的值在截图的注释中能够看到:
-v
: 打印当前 react-native-cli 的版本和 react native 的依赖关系init
: 建立一个新工程而且执行 npm install--verbose
: init
时添加的参数,打印init
时的参数-template
:用到的模板的名称--version
: 会覆盖默认(最新版本)安装的 react-native 的版本。 也就是若是要建立指定版本的,须要加上这个参数OK, 各个变量的含义咱们都弄清楚了,下面让咱们继续探究~~
2.
switch (commands[0]) {
case 'init':
if (!commands[1]) {
console.error('Usage: react-native init <ProjectName> [--verbose]');
process.exit(1);
} else {
init(commands[1], options);
}
break;
default:
//...代码省略
break;
}
}
复制代码
在这以前 116 行 定义了 commands 这个变量,取值的结果是解析的参数,应该是 _ [ 'init ', 'yx_rnDEmo']
,因此会走switch 的第一个选项,去执行 init(commands[1], options)
方法,参数为 'yx_rnDemo’ 和 options 变量。
3.
/**
* @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); } } 复制代码
很简单,先去判断咱们起的工程名称是否符合命名规范,而且判断是否存在。因此下面直接看 createProject(name, options)
方法
4.
function createProject(name, options) {
//....代码省略
run(root, projectName, options);
}
复制代码
这个方法里主要是去进行建立工程文件夹和 package.json 文件的操做,而后后续行动在run(root, projectName, options)
函数中
5.
function run(root, projectName, options) {
var rnPackage = options.version; // e.g. '0.38' or '/path/to/archive.tgz'
console.log('Installing ' + getInstallPackage(rnPackage) + '...');
//...代码省略
installCommand = 'npm install --save --save-exact ' + getInstallPackage(rnPackage);
if (options.verbose) {
installCommand += ' --verbose';
}
//...代码省略
try {
execSync(installCommand, {stdio: 'inherit'});
} catch (err) {
//... 代码省略
}
cli.init(root, projectName);
}
复制代码
其中这个 rnPackage
就是解析的 version 参数 ,因此,对于个人第一次使用的命令:react-native init yx_rnDemo --version0.47.2
来讲,解析工具并无找到 key 为 version 的参数,因此第一次命令的 rnPackage
的值应该是空的,输入正确后就是 0.47.2 了。 而后看 installCommand
这个变量,就是最终执行的命令。其中一个参数是须要到getInstallPackage(rnPackage)
去肯定一下是什么。
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;
}
复制代码
OMG! 看到上面的代码 激不激动,终于真相大白了!! 按照个人第一次错误的写法,这个 rnPackage 是空,而后
var isValidSemver = semver.valid(rnPackage);
复制代码
这一行代码的含义是进行一个版本语义化规范的检查,就是你建立的版本号必须符合 semver语义化规范,也就是 x.y.z 的格式,好比 0.47.2 ,然而我如今传的空,确定是不符合规范的,果断返回 false ,因此该方法会返回 "react-native", 默认会安装最新版。 而我后来正确的写法,是符合规范的,最终该方法会返回 "react-native@0.47.2" ! 而后就会下载指定的版本了。
最后咱们这边能够验证下,输出的 log 参数是否是咱们在代码中看到的。
上图:
果真如此~~
而后终于理解了,react-native 中文网 中提示若是建立指定版本,版本号必须知足两位小数点 这句话是为何了。
因此说了那么多,若是想在 init 时候指定版本号,很是简单,,就是官网指出的:
react-native init MyApp --version 0.44.3
但必须注意检查两点(估计也就我这么粗心的人会犯吧):
1.--version
必定要加空格,千万不要写成 --version0.44.3
2.版本号必定要两位小数点,必须符合 semver语义化规范
github.com/facebook/re… nodejs.cn/api/child_p… www.runoob.com/nodejs/node… nodejs.cn/api/fs.html… www.jianshu.com/p/231b931ab…