我的 React Native 技能樹點(diǎn)亮計(jì)劃 の Javascript 模塊管理器 npm

@author ASCE1885的 Github 簡(jiǎn)書 微博 CSDN 知乎
本文由于潛在的商業(yè)目的千扶,不開放全文轉(zhuǎn)載許可踪宠,謝謝!

image_1akdbc4t86e41r17s2518obtgb13.png-1421.1kB
image_1akdbc4t86e41r17s2518obtgb13.png-1421.1kB

廣而告之時(shí)間:我的新書《Android 高級(jí)進(jìn)階》(https://item.jd.com/10821975932.html在京東開始預(yù)售了,歡迎訂購唤冈!

TB2MnqlXH1J.eBjSszcXXbFzVXa_!!1020536390.png-39kB
TB2MnqlXH1J.eBjSszcXXbFzVXa_!!1020536390.png-39kB

npm帅容,全稱是 node package manager颇象,顧名思義最開始是作為 Node 的包管理器存在的。不過經(jīng)過不斷的發(fā)展和壯大并徘,現(xiàn)在的 npm 早就不再局限于 Node 的范疇遣钳,已經(jīng)成為 Javascript 的包管理器,看看下面的 npm 官網(wǎng)首頁介紹就知道了:

image_1ak5a6lts1i7t1taee9t12djb599.png-313.4kB
image_1ak5a6lts1i7t1taee9t12djb599.png-313.4kB

本系列教程假設(shè)你已經(jīng)按照 React Native 官方入門指南安裝好相關(guān)的環(huán)境(尤其是 Node.js)麦乞,并且執(zhí)行 react-native init AwesomeProject 命令生成了 Demo 工程 AwesomeProject蕴茴,工程目錄結(jié)構(gòu)如下圖所示:

image_1ak5eb3u0h5u1gandlpjle1e1v9.png-151.2kB
image_1ak5eb3u0h5u1gandlpjle1e1v9.png-151.2kB

package.json 的文件結(jié)構(gòu)

從上圖中可以看到劝评,AwesomeProject 工程的根目錄有一個(gè)名為 package.json 的文件,它是工程的元數(shù)據(jù)集荐开,主要作用有:

  • 管理項(xiàng)目中依賴的第三方包付翁,可以很方便的和團(tuán)隊(duì)中其他開發(fā)者共享工程的依賴配置,這樣不需要每個(gè)人都手動(dòng) npm install 相應(yīng)的依賴包
  • 定義 npm 中可以執(zhí)行的腳本

一個(gè)合格的 package.json 文件需要至少包含 nameversion 兩個(gè)字段晃听,這兩個(gè)字段組成的二元組可以唯一標(biāo)識(shí)一個(gè)包百侧,如下所示:

{
  "name": "AwesomeProject",
  "version": "0.0.1"
}

當(dāng)然一般情況下,工程的 package.json 不可能這么簡(jiǎn)單能扒,常用的字段和解釋如下表所示佣渴,開發(fā)者需要根據(jù)具體的業(yè)務(wù)需求進(jìn)行選擇:

字段名 含義 示例
name 包名需要具備唯一性,而且字母必須全部小寫初斑,如果一個(gè)包缺少這個(gè)字段辛润,使用 npm install 將會(huì)失敗 "name": "redux"
version 包的版本號(hào),遵循語義化版本(http://semver.org/lang/zh-CN/)格式见秤,也就是版本號(hào)包含三位:MAJOR.MINOR.PATCH砂竖。MAJOR 表示版本發(fā)生大的變化,例如 API 不兼容舊版本鹃答;MINOR 表示版本增加新功能乎澄,但是兼容舊版本的;PATCH 表示兼容舊版本的一些 bug 修復(fù) "version": "3.5.2"
description 項(xiàng)目的描述测摔,盡量保持言簡(jiǎn)意賅 "description": "Predictable state container for JavaScript apps"
author 項(xiàng)目的作者名字和郵件地址置济,如果有多個(gè),以 JSON 數(shù)組形式表示 "authors": ["Dan Abramov dan.abramov@me.com(https://github.com/gaearon)","Andrew Clark acdlite@me.com(https://github.com/acdlite)"]
contributors 項(xiàng)目的貢獻(xiàn)者名單锋八,以 JSON 數(shù)組的形式表示 "contributors": [{"name": "asce1885","email": "asce1885@gmail.com"}]
bin 項(xiàng)目對(duì)外暴露的 CLI 接口浙于,提供給其他項(xiàng)目使用的腳本 "bin": {"module-name":"./bin/module-name"}
scripts 定義 npm 腳本命令,key 值表示命令名挟纱,value 值表示命令對(duì)應(yīng)的腳本或者腳本的路徑羞酗,通過 npm run 或者 npm run-script 可以執(zhí)行對(duì)應(yīng)的命令 "scripts": { "clean": "rimraf lib dist es coverage", "lint": "eslint src test examples build", "start": "node node_modules/react-native/local-cli/cli.js start"
main 工程生成的 Package 的主入口點(diǎn),當(dāng)在 node 中調(diào)用 require('{module name}') 時(shí)會(huì) require 到這個(gè)文件 "main": "lib/index.js"
repostitory 如果我們這個(gè)工程是開源的紊服,這個(gè)字段用來指明工程的倉庫 URL 地址以及版本控制系統(tǒng)的類型檀轨,這可以方便其他開發(fā)者貢獻(xiàn)代碼 "repository": { "type": "git", "url": "https://github.com/reactjs/redux.git" }
bugs 使用者可以提交bugs的 URL 或者郵件地址 "bugs": {"url": "https://github.com/reactjs/redux/issues"}
keywords 描述這個(gè) Package 的關(guān)鍵字信息,方便用戶通過關(guān)鍵字搜索到這個(gè) Package "keywords": ["redux","reducer","state","predictable","functional","immutable","hot","live","replay","flux","elm"]
dependencies 這個(gè) Package 的生產(chǎn)依賴围苫,當(dāng)用戶安裝你的 Package 時(shí)會(huì)自動(dòng)安裝這些依賴 "dependencies": { "react": "^15.1.0", "react-native": "^0.27.0-rc2" }
devDependencies 這個(gè) Package 在開發(fā)或者測(cè)試階段的依賴裤园,不會(huì)打包到最終的生產(chǎn)包中 "devDependencies": { "babel-eslint": "^5.0.0", "eslint": "^2.1.0", "eslint-plugin-react": "^3.16.1" }
preferGlobal 表明這個(gè) Package 希望通過 npm install -g {module-name} 全局安裝撤师,這個(gè)字段是給包含了 CLI 的 Package 使用剂府, 其他情況下不要使用這個(gè)字段 "preferGlobal": true
private 設(shè)置為 true 時(shí),npm 將不會(huì)發(fā)布這個(gè) Package剃盾,這個(gè)標(biāo)記主要用來防止不小心發(fā)布某個(gè)內(nèi)部使用的私有 Package 到公共的 npm registry "private": true
publishConfig 發(fā)布這個(gè) Package 時(shí)用到的一些配置信息腺占,這些配置信息會(huì)覆蓋默認(rèn)的 npm 配置 "publishConfig": { "registry": "https://your-private-hosted-npm.registry.nodejitsu.com" }
subdomain 指明應(yīng)用的 subdomain淤袜,說明應(yīng)該只包含 subdomain,而不是 root domain
analyze 如果你的 Package 托管在 Nodejitsu(https://www.nodejitsu.com/) 上面衰伯,同時(shí)將這個(gè)字段設(shè)置為 true铡羡,Nodejitsu 將會(huì)自動(dòng)嘗試掃描你的 Package,可以及時(shí)發(fā)現(xiàn)缺少的依賴意鲸,可能存在的 bugs 以及語法錯(cuò)誤等 "analyze": true
license 如果這個(gè) Package 是開源的烦周,此處指定它遵循的許可協(xié)議 "license": "MIT"

一個(gè)真實(shí)項(xiàng)目的 Package.json 文件內(nèi)容如下所示(取自 redux-logger[1]

{
  "name": "redux-logger",
  "version": "2.6.1",
  "description": "Logger for Redux",
  "main": "lib/index.js",
  "scripts": {
    "lint": "$(npm bin)/eslint src",
    "test": "npm run lint",
    "clean": "$(npm bin)/rimraf dist lib",
    "build:lib": "$(npm bin)/babel src --out-dir lib",
    "build:umd": "LIBRARY_NAME=reduxLogger NODE_ENV=development $(npm bin)/webpack src/index.js dist/index.js --config webpack.build.js",
    "build:umd:min": "LIBRARY_NAME=reduxLogger NODE_ENV=production $(npm bin)/webpack -p src/index.js dist/index.min.js --config webpack.build.js",
    "build": "npm run build:lib && npm run build:umd && npm run build:umd:min",
    "prepublish": "npm run clean && npm run test && npm run build"
  },
  "files": [
    "dist",
    "lib",
    "src"
  ],
  "repository": {
    "type": "git",
    "url": "git+https://github.com/theaqua/redux-logger.git"
  },
  "keywords": [
    "redux",
    "logger",
    "redux-logger",
    "redux",
    "middleware"
  ],
  "author": "Eugene Rodionov (https://github.com/theaqua)",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/theaqua/redux-logger/issues"
  },
  "homepage": "https://github.com/theaqua/redux-logger#readme",
  "devDependencies": {
    "@dtrussia/eslint-config-dtrussia": "2.2.1",
    "babel-cli": "6.3.13",
    "babel-core": "6.3.13",
    "babel-eslint": "6.0.4",
    "babel-loader": "6.2.0",
    "babel-plugin-add-module-exports": "0.1.1",
    "babel-preset-es2015": "6.3.13",
    "babel-preset-react": "6.3.13",
    "babel-preset-stage-0": "6.3.13",
    "eslint": "2.10.2",
    "eslint-plugin-react": "5.1.1",
    "rimraf": "2.4.4",
    "webpack": "1.12.9"
  },
  "dependencies": {
    "deep-diff": "0.3.4"
  }
}

npm 的模塊管理

熟悉 npm 的常用命令,往往能夠使得你的工作事半功倍怎顾。首先我們來介紹最常用的 npm install 命令读慎,它是用來將依賴的模塊安裝到 node_modules 目錄中,依賴分為兩種:生產(chǎn)環(huán)境的依賴和開發(fā)環(huán)境的依賴槐雾,這個(gè)在前面一節(jié)已經(jīng)介紹過了夭委,對(duì)應(yīng)的命令分別如下所示:

npm install redux // 生產(chǎn)環(huán)境的依賴
npm install redux -dev // 開發(fā)環(huán)境的依賴

在安裝之前,npm 會(huì)先檢查 node_modules 目錄中是否已經(jīng)存在指定的模塊募强,如果存在株灸,則不會(huì)重新安裝,即使這個(gè)模塊已經(jīng)有新版本擎值。當(dāng)然慌烧,我們可以通過增加 -f 或者 --force 參數(shù)來強(qiáng)制重新安裝最新版本。上面的命令安裝完成后幅恋,我們可以在 node_modules 目錄中找到 redux 的包杏死,但這時(shí) package.json 文件內(nèi)容并沒有發(fā)生變化,為了在發(fā)布我們這個(gè)包給其他開發(fā)者使用時(shí)捆交,他們可以自動(dòng)安裝這些依賴淑翼,我們需要將依賴寫入 package.json 文件中,當(dāng)然你可以選擇手動(dòng)寫入品追,但更方便的方法是在 npm install 時(shí)增加 --save 參數(shù)玄括,如下所示:

npm install redux --save // 生產(chǎn)環(huán)境的依賴
npm install redux --save-dev // 開發(fā)環(huán)境的依賴

這時(shí) npm 會(huì)自動(dòng)幫我們寫入 package.json 文件,如下所示:

{
  ...
  "dependencies": {
    ...
    "redux": "^3.5.2"
  },
  "devDependencies": {
    "eslint": "^2.11.1"
  }
}

有了依賴的安裝肉瓦,當(dāng)然也有卸載的命令遭京,很簡(jiǎn)單就是 npm uninstall,后面參數(shù)是需要卸載的包名泞莉,例如 npm uninstall redux哪雕。

前面使用 React Native 提供的 react-native init AwesomeProject 命令生成的 Demo 工程已經(jīng)自動(dòng)幫我們生成了 package.json 文件,如果我們自己手動(dòng)建立一個(gè) React Native 的工程鲫趁,那么可以選擇從其他工程拷貝現(xiàn)成的 package.json 并進(jìn)行修改斯嚎,當(dāng)正確的做法是使用 npm init 命令來生成它。在 Terminal 中輸入 npm init,npm 將會(huì)一步一步引導(dǎo)我們輸入一些關(guān)鍵的字段堡僻,最終生成的文件內(nèi)容如下所示糠惫,從中看到的字段幾乎是每個(gè)工程必備的:

{
  "name": "asce1885",
  "version": "1.0.0",
  "description": "One Piece",
  "main": "index.js",
  "scripts": {
    "test": "op"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/PaicHyperionDev/MobileDevWeekly.git"
  },
  "keywords": [
    "mobile",
    "dev"
  ],
  "author": "asce1885",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/PaicHyperionDev/MobileDevWeekly/issues"
  },
  "homepage": "https://github.com/PaicHyperionDev/MobileDevWeekly#readme"
}

當(dāng)某個(gè)第三方依賴庫需要發(fā)布新版本,我們項(xiàng)目也需要跟著升級(jí)時(shí)钉疫,可以通過 npm update 命令對(duì)指定的 Package 進(jìn)行升級(jí)硼讽,例如 npm update redux。同時(shí)牲阁,我們可以通過執(zhí)行命令 npm outdated 來查詢當(dāng)前安裝的所有 npm 包中是否有存在新版本的固阁。

一般來說,掌握上面幾個(gè)命令城菊,對(duì)開發(fā) React Native 來說就已經(jīng)足夠了您炉,對(duì)于不熟悉的命令,我們可以通過 npm help 來查詢對(duì)應(yīng)命令的用法役电,例如輸入 npm help registry赚爵,會(huì)得到如下結(jié)果:

image_1akd8q4b8nr8124l1jli1q3sj4im.png-221.9kB
image_1akd8q4b8nr8124l1jli1q3sj4im.png-221.9kB

npm scripts

上一節(jié)我們介紹了 npm 的模塊管理功能,事實(shí)上法瑟,npm 另外一個(gè)高頻使用的功能就是用來執(zhí)行腳本冀膝。我們?cè)?package.json 文件的 scripts 字段中定義的腳本可以通過 npm run 或者 npm run-script 執(zhí)行,例如在 React Native 工程中霎挟,我們可以定義如下腳本窝剖,分別用來創(chuàng)建,啟動(dòng) Android 模擬器酥夭,啟動(dòng) node 服務(wù)和打包等:

"scripts": {
    "avd:create": "android create avd -t 1 -n MuchVote -d 9 -b x86_64 -s 1440x2560",
    "avd:start": "emulator -avd MuchVote -gpu on -dpi-device 560 -scale ${SCALE:-0.25}",
    "adb:reverse": "adb reverse tcp:8081 tcp:8081",
    "android": "npm run adb:reverse && node node_modules/react-native/local-cli/cli.js run-android",
    "start": "npm run adb:reverse && node_modules/react-native/packager/packager.sh",
  }

定義完成之后赐纱,就可以在 React Native 目錄中像下面這樣執(zhí)行對(duì)應(yīng)的命令:

npm run adb:reverse
npm run android
...

為了方便腳本的執(zhí)行,npm 默認(rèn)定義了一些命令的快捷鍵熬北,例如 npm test疙描,npm startnpm stop 等等讶隐,也就是說執(zhí)行這些命令時(shí)起胰,我們省去了 run 的輸入。之所以定義這些快捷鍵巫延,除了可以節(jié)省執(zhí)行命令的時(shí)間效五,更重要的一點(diǎn)是這些命令的命名是通用的約定,很多持續(xù)構(gòu)建平臺(tái)例如 Travis 會(huì)默認(rèn)為 Node.js 工程添加 npm test 命令炉峰;同時(shí)畏妖,這些通用的命令定義也方便其他開發(fā)者使用你的包。

npm 為每一條命令都提供了 pre--post 這兩個(gè)鉤子疼阔,分別表示在命令執(zhí)行前和執(zhí)行后會(huì)執(zhí)行對(duì)應(yīng)的鉤子命令戒劫。例如下面的腳本适瓦,當(dāng)用戶執(zhí)行 npm run test 命令時(shí),事實(shí)上 npm 會(huì)先執(zhí)行 pretest 命令谱仪,然后才執(zhí)行 test 命令。

"scripts": {
    "eslint": "eslint --rulesdir **",
    "test": "mocha test/",

    "pretest": "npm run eslint"
  }

當(dāng)一個(gè)命令比較復(fù)雜時(shí)否彩,我們還可以將這個(gè)命令定義在一個(gè)單獨(dú)的 js 文件中疯攒,然后通過 node 來執(zhí)行,如下所示:

"scripts": {
    "build": "node build.js"
}

本系列關(guān)于 npm 的介紹就到這里列荔,基本上對(duì)開發(fā) React Native 已經(jīng)足夠用了敬尺,如果你不滿足于這些基礎(chǔ)知識(shí),可以查閱拓展閱讀部分的文檔贴浙,進(jìn)一步學(xué)習(xí)砂吞。

拓展閱讀

《npm 官方文檔》[2]
《我為何放棄 Gulp 與 Grunt,轉(zhuǎn)投 npm scripts》上[3][4][5]
《Introduction to Using NPM as a Build Tool》[6]
《How to Use npm as a Build Tool》[7]
《package.json》[8]
《玩轉(zhuǎn) npm》[9]
《玩轉(zhuǎn) npm》[10]
《npm 模塊安裝機(jī)制簡(jiǎn)介》[11]

歡迎關(guān)注我的微信公眾號(hào)崎溃,專注與原創(chuàng)或者分享 Android蜻直,iOS,ReactNative袁串,Web 前端移動(dòng)開發(fā)領(lǐng)域高質(zhì)量文章概而,主要包括業(yè)界最新動(dòng)態(tài),前沿技術(shù)趨勢(shì)囱修,開源函數(shù)庫與工具等赎瑰。


  1. https://github.com/evgenyrodionov/redux-logger ?

  2. https://docs.npmjs.com/ ?

  3. http://www.infoq.com/cn/news/2016/02/gulp-grunt-npm-scripts-part1 ?

  4. http://www.infoq.com/cn/news/2016/02/gulp-grunt-npm-scripts-part2 ?

  5. http://www.infoq.com/cn/news/2016/02/gulp-grunt-npm-scripts-part3 ?

  6. https://medium.com/@dabit3/introduction-to-using-npm-as-a-build-tool-b41076f488b0#.tylyovxdw ?

  7. http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/ ?

  8. http://browsenpm.org/package.json#description ?

  9. http://www.alloyteam.com/2016/03/master-npm/ ?

  10. https://github.com/icepy/_posts/issues/36 ?

  11. http://www.ruanyifeng.com/blog/2016/01/npm-install.html ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市破镰,隨后出現(xiàn)的幾起案子餐曼,更是在濱河造成了極大的恐慌,老刑警劉巖鲜漩,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件源譬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡孕似,警方通過查閱死者的電腦和手機(jī)瓶佳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鳞青,“玉大人霸饲,你說我怎么就攤上這事”弁兀” “怎么了厚脉?”我有些...
    開封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)胶惰。 經(jīng)常有香客問我傻工,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任中捆,我火速辦了婚禮鸯匹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泄伪。我一直安慰自己殴蓬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開白布蟋滴。 她就那樣靜靜地躺著染厅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪津函。 梳的紋絲不亂的頭發(fā)上肖粮,一...
    開封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音尔苦,去河邊找鬼涩馆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛允坚,可吹牛的內(nèi)容都是我干的凌净。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼屋讶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼冰寻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起皿渗,我...
    開封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤斩芭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后乐疆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體划乖,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年挤土,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了琴庵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仰美,死狀恐怖迷殿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咖杂,我是刑警寧澤庆寺,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站诉字,受9級(jí)特大地震影響懦尝,放射性物質(zhì)發(fā)生泄漏知纷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一陵霉、第九天 我趴在偏房一處隱蔽的房頂上張望琅轧。 院中可真熱鬧,春花似錦踊挠、人聲如沸乍桂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至漠趁,卻和暖如春扁凛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闯传。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工谨朝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人甥绿。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓字币,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親共缕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洗出,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容