最近一段時間一直在寫 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…