一、路由機制(靜態資原始檔處理)
1.1 Nodejs沒有根目錄
MIME型別:http://www.w3school.com.cn/media/media_mimeref.asp
在Apache中,它會自動將htdocs資料夾提供靜態化路由服務。
但是Nodejs沒有這個機制。
在資料夾中建立這樣的層次目錄:
┠ www
┋┠ a
┋┋┠ b
┋┋┋┠ page.html
┠ 11-Nodejs沒有根目錄容器.js
訪問的時候,可以看見page.html頁面:
var http = require('http'); var fs = require('fs'); var server = http.createServer(function(req,res){ res.setHeader("Content-Type", "text/html;charset=UTF8"); fs.readFile("./www/page.html" , (err,data)=>{ res.end(data.toString()); }) }); server.listen(3000);
會發現URL中看不出來物理檔案的真實位置。
可以用req.url來識別url地址,從而呈遞不同的檔案:
page.html頁面:
<html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <style type="text/css"> div{ width: 300px; height: 100px; background: orange; } </style> <link rel="stylesheet" href="aaa"> </head> <body> <h1>page頁面!</h1> <div></div> <img src="images/d1.jpg"> <img src="images/d2.jpg"> <img src="images/d3.jpg"> </body> </html>
var server = http.createServer(function(req,res){ console.log(req.url) if(req.url == "/"){ fs.readFile("./www/page.html",(err,data)=>{ res.setHeader("Content-type","text/html;charset=UTF8"); res.end(data.toString()); }); }else if(req.url == "/images/d1.jpg"){ fs.readFile("./www/images/baby1.jpg",(err,data)=>{ res.setHeader("Content-type","image/jpeg"); res.end(data); }); }else if(req.url == "/images/d2.jpg"){ fs.readFile("./www/images/d2.jpg",(err,data)=>{ res.end(data); }); }else if(req.url == "/d3.jpg"){ fs.readFile("./www/images/d3.jpg",(err,data)=>{ res.end(data); }); }else if(req.url == "aaa"){ fs.readFile("./www/css/css.css",(err,data)=>{ res.setHeader("Content-type","text/css"); res.end(data); }); }else{ res.setHeader("Content-type","text/html;charset=UTF8"); res.end("404,沒有這個頁面!"); } });
紅色部分是發出的url請求,藍色部分是根據請求的url從而呈遞真實的檔案,URL和真實的物理檔案的路徑沒有任何關係!
比如www/a/b/c/d1.jpg可以被路由顯示為/d1.jpg
1.2頂級路由設計
Nodejs開啟了RestFul路由設計風格。簡單來說是:
可以通過這樣的路徑來檢視100001號使用者的資訊: http://127.0.0.1:3000/student/100001
而不是老土的: http://127.0.0.1:3000/showinfo.php?id=100001
後面將知道可以利用POST、GET請求的不同,也可以讓一個URL有不同的操作。
這樣的路由的好處就是:不需要開闢過多的資料夾、並且不暴露技術細節。
可以用字串match方法,結合正則獲取路由中的某部分:
1.3 url模組和path模組
一個完整的URL,包括querystring部分(就是get請求字串部分)、hash部分。
http://127.0.0.1:3000/a/b.html?id=123&name=xiaoming#aaa
此時的req.url是:
也就是說,querystring部分屬於req.url,但是hash不屬於。
但是我們要得到檔名部分,不想要querystring部分,如果正則匹配,太麻煩。
此時node中提供內建模組:url、path、querystring,他們都可以用於URL的識別。
var http = require("http"); var fs = require("fs"); var url = require("url"); var server = http.createServer(function(req,res){ console.log(url.parse(req.url)) });
網址:http://127.0.0.1:3000/haha/1.html?id=123&name=xiaoming&sex=男#abc
輸出的內容:
沒有正確識別protocol協議、host主機名、port埠號等等,因為是Windows環境,有這個問題。
如果加上true,此時query部分將自動變為物件,方便我們操作
url.parse(req.url,true);
還有兩個模組path、querystring它們都是服務於url的
var http = require('http'); var fs = require('fs'); var url = require('url'); var path = require('path'); var server = http.createServer(function(req,res){ //將url字串轉為json物件 var urljson = url.parse(req.url,true); //得到檔案路徑 var pathname = urljson.pathname; //得到副檔名 var extname = path.extname(pathname); console.log(extname) }); server.listen(3000);
1.4自動路由
建立一個www根目錄資料夾,我們的程式能夠自動為裡面的檔案、圖片、css、js加上路由,實現一個Apache。
思想:使用者輸入什麼URL,就用fs去讀那個檔案。
訪問/a.png ,就自動讀取www/a/b/c/a.png
url可能很複雜,比如: http://127.0.0.1:3000/a/b/c.html?id=123&asf=32434#3243 要讀取c.html。就要過濾掉藍色的部分,當中有協議、域名、埠號、get請求查詢字串、hash。
使用內建url模組: var pathname = url.parse(req.url).pathname; url.parse(req.url) 可以將這個url拆分,比如.pathname表示上面紅色的部分。
有幾個不好用的地方,首先就是content-type的事,
如果我們訪問的是.html檔案,content-type就應該是text/html。如果訪問一個.jpg,此時應該是image/jpeg。請參考:http://www.w3school.com.cn/media/media_mimeref.asp
然後就是不能自動識別index檔案。比如我們輸入: http://127.0.0.1:3000/a 應該讀取www中的a資料夾中的index.html
解決辦法:這種路徑都沒有擴充名,如果使用者輸入了一個URL不存在擴充名,則自動補充/index.html即可。
var http = require("http"); var fs = require("fs"); var url = require("url"); var path = require("path"); //準備mime型別的json var mimejson = { ".jpg" : "image/jpeg", ".png" : "image/png", ".gif" : "image/gif", ".html": "text/html;charset=UTF8", ".css" : "text/css", ".js" : "application/x-javascript", ".ogg" : "audio/ogg", ".mp3" : "audio/mpeg" } var server = http.createServer(function(req,res){ //訪問路徑 var pathname = url.parse(req.url).pathname; //得到副檔名 var extname = path.extname(pathname) //如果當前路徑不以副檔名結尾,此時表示這是一個資料夾形式的路徑,要自動補全index.html if(!extname){ //如果不是以“/”結尾,此時會早瀏覽器識別圖片路徑層次有問題 //比如http://127.0.0.1:3000/a和http://127.0.0.1:3000/a/不一樣 //前者認為是同級目錄下的,後者認為是a資料夾中的 if(pathname.substr(-1) != "/"){ res.writeHead(302, {"Location": pathname + "/"}) } pathname = pathname + "index.html"; extname = "./html"; } //檢查是否屬於已知的mime型別 if(mimejson.hasOwnProperty(extname)){ //設定MIME型別(下行報文頭) res.setHeader("Content-type", mimejson[extname]); } //讀取對應的真實檔案路徑,這裡將當前檔案的路徑和www資料夾和訪問的路徑合併 fs.readFile("./www/" + pathname , function(err,data){ if(err){ res.end("沒有這個檔案"); return; } res.end(data); }) }); server.listen(3000,function(err){ console.log("伺服器開啟成功,在3000埠,快開啟瀏覽器看看吧!"); })
二、總結和REPL環境
2.1複習
NodeJS是什麼?
JavaScript RunTime(JavaScript執行環境),是將Chrome V8引擎移植到了伺服器上追求自治效能的技術,可以搭建http伺服器。
使用的語言還是JavaScript,將js的觸角伸到了伺服器端。
NodeJS有什麼特點?
Single Thread(單執行緒)
Non-Blocking I/O(非同步I/O,非阻塞I/O)
Event-Driven(事件驅動)
NodeJS適合開發什麼樣的業務?
適合I/O頻繁的業務:留言本、貼吧、微博等等。
不適合計算多的業務:語音識別、影象識別等等。
NodeJS如何安裝?
在windows下安裝了node,此時你的環境變數中就有了node資料夾的路 徑,此時用CMD命令就可以執行nodejs程式了。
如何執行NodeJS程式?
① 用CMD的cd命令進入專案資料夾
② 執行誰就node誰
內建模組
Nodejs中為了方便開發和最終的編譯的輕量,所以使用了“模組”(modules)的概念。
模組指的是功能相關的js檔案的集合,就稱為一個模組。一個module指的是一個檔案組,或者說一組檔案。
這一組檔案可以小到只有一個檔案,也就是說這一個module就只有一個js檔案;也可以大到很多檔案,甚至這一個module中還有其他module。
模組用require()進行引用,我們學習的內建模組有:
fs模組用來處理檔案 var fs = require("fs"); fs.readFile("./test.txt",(err,data)=>{ });
http模組,建立伺服器: var http = require("http"); http.createServer((req,res)=>{ req.url //使用者訪問的路徑 res.write(); res.end(); }).listen(3000,function(err){})
path模組,主要負責和檔案路徑有關係的事情: var path = require("path"); path.extname(); //獲得檔案擴充名 path.resolve(); //智慧合併
url模組,主要負責url地址的拆分等一些功能: var url= require("url"); url.parse();
Nodejs中的路由:
Nodejs和apache不一樣,apache有自動的路由,但是nodejs沒有自動路由。
必須用req.url來識別訪問的路徑,然後用fs.readFile()去讀取某一個檔案,然後res.end()出去。
Nodejs非常方便進行頂級路由設計,比如twitter的路由: http://www.twitter.com/telangpu/followers 此時並沒有一個叫做telangpu的資料夾,也沒有followers的子資料夾!
什麼是路由?
路由可以理解成根據請求不同的URL,對映到不同處理程式上。反過來,需要對每個不同的頁面定義不同的路由來實現區分介面。
簡單來說,路由就是給指定的頁面分配一個url地址。通過這個url地址,就能訪問到該頁面了。
比如寫了一個頁面:/static/public/game/index.html
伺服器域名地址是:www.iqianduan.cn 通過一些方式,給該頁面配置了一個路由地址/game
那麼,就可以通過http://www.iqianduan.cn/game訪問到上面這個index.html檔案了
支援RESTful的路由,遵循國際規範。
2.2 REPL環境
介紹Nodejs的REPL環境。
Node.js REPL(Read Eval Print Loop:互動式直譯器) 表示一個電腦的環境,類似 Window 系統的終端或 Unix/Linux shell,我們可以在終端中輸入命令,並接收系統的響應。
l 讀取 - 讀取使用者輸入,解析輸入了Javascript 資料結構並儲存在記憶體中。
l 執行 - 執行輸入的資料結構
l 列印 - 輸出結果
l 迴圈 - 迴圈操作以上步驟直到使用者兩次按下 ctrl+c 按鈕退出Node REPL。
這裡和Chrome的F12功能一樣,可以直接輸入語句,然後執行。
在REPL環境下,測試一下url.parse()語句:
url.parse()功能就是拆分url地址。
path.extname(url.parse("http://www.aaa.com/a/b/c.php?id=1&name=小明#12").pathname);
三、Nodejs的模組系統
3.1先複習HTML環境下的js檔案的關係
知識點1:在HTML中,script引用了誰,就會執行誰,瀏覽器一定能夠保證載入、執行順序的
<html> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript" src="a.js"></script> <script type="text/javascript" src="b.js"></script> <script type="text/javascript" src="c.js"></script> </body> </html>
知識點2:js檔案不能“關住”變數作用域
a.js檔案: var zhongguoyidong = 10086; //相當於給window新增了屬性 b.js檔案: alert(zhongguoyidong); //相當於訪問window的屬性
此時能夠彈出10086,也就是說a.js檔案中定義的變數,b.js檔案中能夠看見!
全域性變數是window物件的屬性。
知識點3:IIFE關閉某個js檔案時,這個js檔案想向外“暴露”某些物件
(function(){ var pi = 3.14; window.mianji = function(r){ return pi * r * r; } window.zhouchang = function(r){ return 2 * pi * r; } })();
主頁面:
<script type="text/javascript" src="a.js"></script> <script type="text/javascript"> alert(mianji(10)) alert(zhouchang(10)) </script>
看一種複雜的情況,a.js檔案和b.js檔案都向外暴露了相同的函式:
a.js:
(function(){ var pi = 3.14; window.mianji = function(r){ return pi * r * r; } window.zhouchang = function(r){ return 2 * pi * r; } })();
b.js
(function(){ var pi = 3.14; window.mianji = function(d,g){ return 0.5 * d * g; } })();
index.html
<script type="text/javascript" src="a.js"></script> <script type="text/javascript" src="b.js"></script> <script type="text/javascript"> alert(mianji(10,2)) alert(zhouchang(10)) </script>
b裡面的mianji函式,將a裡面的mianji函式覆蓋了。
3.2 Nodejs中的模組概念
┣ modules
│┣ a.js
┣01.js
nodejs通過require()函式引用自己寫js檔案,require誰,就立即執行誰。
a.js console.log("我是a.js檔案");
01.js require("./modules/a.js");
新增一個b.js檔案
┣ modules
│┣ a.js
│┣ b.js
┣01.js
require("./modules/a.js"); //定義了一個變數 require("./modules/b.js"); //輸出這個變數
a.js var aaa = 100;
b.js console.log(aaa);
執行01.js報錯。
Nodejs的js檔案是天生隔離作用域的,因為沒有全域性window物件的概念了。
即使將在01.js主檔案中,也不能使用這個aaa變數 require("./modules/a.js"); //天生有閉包 console.log(aaa) //報錯
3.3變數的暴露(exports.** = **)
如果js檔案中想要暴露什麼,使用exports物件:
┣ modules
│┣ a.js
┣01.js
a.js
var zhongguoliantong = 10000; exports.zhongguoliantong = zhongguoliantong; //向外暴露變數
01.js
var a = require("./modules/a.js"); //接收暴露的物件 console.log(a.zhongguoliantong);
注意兩點(約定俗成): 向外暴露的時候,變數本身叫什麼名,暴露的名字就叫什麼。 exports.zhongguoliantong = zhongguoliantong; require接收時,模組檔名(js檔名)是什麼,接收的變數就叫什麼名字 var a = require("./modules/a.js");
Nodejs的這種require + exports的模式叫CMD規範(Commond Module Definition),但不是nodejs發明的,
後面會介紹CMD和AMD規範(Common.js、Sea.js、require.js)
現在有兩個模組,都向外暴露mianji函式
┣ modules
│┣ yuan.js
│┣ sanjiaoxing.js
┣02.js
yuan.js
function mianji(r){ return 3.14 * r * r; } exports.mianji = mianji;
sanjiaoxing.js
function mianji(i,h){ return 0.5 * i * h; } exports.mianji = mianji;
02.js
var yuan = require("./modules/yuan.js"); var sanjiaoxing = require("./modules/sanjiaoxing.js"); console.log(yuan.mianji(10)); console.log(sanjiaoxing.mianji(10,3));
如果一個js檔案有多個物件要暴露(就是這個模組的API),此時寫多個exports.** = **即可。
function mianji(r){ return 3.14 * r * r; } function zhouchang(r){ return 2 * 3.14 * r; } exports.mianji = mianji; exports.zhouchang = zhouchang;
3.4預設暴露(module.exports = **)
┣ modules
│┣ People.js
┣03.js
People.js中,普通暴露的寫法
function People(name){ this.name = name; } People.prototype.changge = function(){ console.log(this.name + "在唱歌!"); } exports.People = People;
03.js
var People = require("./modules/People.js"); var xiaoming = new People.People("小明"); xiaoming.changge();
此時new的時候People.People這種寫法不優雅,因為模組用普通暴露,普通暴露接收的People將自動成為exports的JSON物件,People.People()才是函式。
怎麼辦?換一種暴露方法即可:
function People(name){ this.name = name; } People.prototype.changge = function(){ console.log(this.name + "在唱歌!"); } module.exports = People; var People = require("./modules/People.js"); var xiaoming = new People("小明"); xiaoming.changge();
這條語句和exports.** = **不同,module.exports = **寫法,接收的變數就成為你暴露的這個函式。
注意:一個資料夾不允許出現module.exports多次,只能出現一次。
總結:
一個js檔案如果有多個暴露(通過是多個API),使用exports.** = **的寫法
一個js檔案如果只要暴露一個物件,通常是類(建構函式),使用module.exports = **寫法
3.5注意事項
l 模組如果要引用另一個模組,使用相對路徑,相對自己出發,找到別人:
l require的模組中如果有非同步語句,還是遵循昨天的“服務員”工作模式:
┣ modules
┃ ┣ loop1.js
┃ ┣ loop1.js
┣ 04.js
04.js
var loop1 = require("./modules/loop1.js");
loop1.js
require("./loop2.js"); console.log("我是loop1檔案");
loop2.js有非同步語句:
var fs = require("fs"); console.log("我是loop2檔案") fs.readFile("./modules/test.txt",function(err,data){ console.log(data.toString()) })
原則上require按順序執行,但如果模組有非同步語句,此時不會傻等模組執行完畢。
四、神奇的node_modules資料夾和模組概念
node_modules是一個特殊的資料夾,只要放在這個資料夾中的js檔案,在被require的時候,不需要詳細寫清楚路徑,nodejs可以自動向上查詢找到它,node_modules還可以出現在專案目錄的任意父路徑層級上。但不會向下查詢,只向上查詢。
┣ node_modules
┃ ┣ yuan.js
┣ 05.js
05.js引用yuan.js的時候,沒有詳細些它的路徑,也能引用成功:
var yuan = require("yuan.js"); //而不是require("./node_modules")
console.log(yuan.mianji(10));
將node_modules資料夾放到day02資料夾外面,就是上一層路徑中,還可以執行:
┣ node_modules
┃ ┣ yuan.js
┣ day02
┣┣ 05.js
也就是說C:\node_study\day02\05.js檔案可以依法引用以下:
C:\node_study\day02\node_modules\yuan.js
C:\node_study\node_modules\yuan.js
C:\node_modules\yuan.js
進一步的深入:
┣ node_modules
┃ ┣ yuan.js
┃ ┣ sanjiaoxing
┃ ┃ ┣ index.js
┣┣ 05.js
var yuan = require("yuan.js"); var sanjiaoxing = require("sanjiaoxing"); console.log(yuan.mianji(10)) console.log(sanjiaoxing.mianji(10,2))
如果require的路徑沒有寫副檔名,表示引用的是node_modules資料夾中的sanjiaoxing資料夾中的index.js檔案。
小題目,下面require實際上require 了誰?
比如專案目錄是:C:\nodejs_study\day02\
require("./a.js"); C:\nodejs_study\day02\a.js require("./haha/a.js"); C:\nodejs_study\day02\haha\a.js require("./haha"); C:\nodejs_study\day02\haha\index.js require("a"); C:\nodejs_study\day02\node_modules\a\index.js require("a.js"); C:\nodejs_study\day02\node_modules\a.js
用shuxue資料夾,去統領所有的模組:
┣ node_modules
┃ ┃ shuxue
┃ ┃ ┣ yuan.js
┃ ┃ ┣ sanjiaoxing.js
┃ ┃ ┣ index.js
┣┣ 06.js
數學這個資料夾對外表示一種功能,就是數學的計算函式,此時shuxue就是一個模組。
模組是一根抽象的資料夾的關係概念,而不是物理的檔案位置概念:
node_modules/shuxue/index.js:
var yuan = require("./yuan.js"); var sanjiaoxing = require("./sanjiaoxing.js"); exports.yuan = yuan; exports.sanjiaoxing = sanjiaoxing;
06.js主檔案使用模組
var shuxue = require("shuxue"); console.log(shuxue.yuan.mianji(10)) console.log(shuxue.yuan.zhouchang(10)) console.log(shuxue.sanjiaoxing.mianji(10,2))
五、npm包管理工具
隨著 web 應用越來越複雜,專案的結構和程式碼量也變的愈加龐大,前端人員越來越需要在工程化的層面提高開發效率,前端開發是一個飛速發展的領域,市面上現在有各種各樣的工具來輔助我們開發,比如說我們在開發過程中就可能會用到下面這些工具:npm、webpack、babel等。
5.1 npm install命令
中文文件:https://www.npmjs.com.cn/
中文文件:http://www.runoob.com/nodejs/nodejs-npm.html
全 稱:node package management(node包管理器)。
大家在這裡共享自己編寫的模組。
NPM 使用介紹:
NPM是隨同NodeJS一起安裝的包管理工具,能解決NodeJS程式碼部署上的很多問題,常見使用場景有以下幾種:
l 允許使用者從NPM伺服器下載別人編寫的第三方包到本地使用。
l 允許使用者從NPM伺服器下載並安裝別人編寫的命令列程式到本地使用。
l 允許使用者將自己編寫的包或命令列程式上傳到NPM伺服器供別人使用。
由於新版的Nodejs已經整合了npm,所以之前npm也一併安裝好了。
可以通過CMD輸入"npm -v" 測試是否成功安裝。命令如下,出現版本提示表示安裝成功:
$ npm -v
比如現在有一個專案,要將數字換成大寫人民幣寫法,12345換成“一萬兩千三百四十五元整”。
我們去npm社群搜尋“大寫金額”:
我們覺得nzh這個模組號,決定用它。
下載方式是使用CMD命令,輸入:
npm install nzh //install表示安裝,nzh就是這個包(模組)的名字
語法:npm install 包名字
01.js 當然API都是從這https://www.npmjs.com/package/nzh抄的:
var Nzh = require("nzh"); var nzhcn = Nzh.cn; // 使用簡體中文, 另外有 Nzh.hk -- 繁體中文 console.log(nzhcn.encodeS(123456)); // 轉中文小寫 >> 十萬零一百一十一 console.log(nzhcn.encodeB(123456)); // 轉中文大寫 >> 壹拾萬零壹佰壹拾壹 console.log(nzhcn.encodeS("1.23456789e+21")); // 科學記數法字串 >> 十二萬三千四百五十六萬萬七千八百九十萬億 console.log(nzhcn.toMoney("100111.11")); // 轉中文金額 >> 人民幣壹拾萬零壹佰壹拾壹元壹角壹分
上面的程式碼誰背誰傻。
新的需求又來了,老闆說,我們要知道農曆,比如要查詢2018年8月8日的農曆是多少?
於是又去npm社群搜尋相關模組:
決定使用solarlunar ,此時npm下載:
npm install solarlunar
看API檔案,直接抄程式碼:
var solarLunar = require("solarLunar"); var solar2lunarData = solarLunar.solar2lunar(2018, 8, 8); // 陽曆轉為農曆 var lunar2solarData = solarLunar.lunar2solar(2018, 8, 8); // 農曆轉為陽曆 console.log(solar2lunarData) console.log(lunar2solarData)
需求:用JS程式批量改圖片尺寸
var fs = require('fs'); var gm = require('gm').subClass({imageMagick: true}); //讀取檔案目錄 fs.readdir("./images/", function(err,files){ //批量迴圈遍歷-修改尺寸 for(var i = 0;i < files.length;i++){ gm('./images/' + files[i]).resize(50,50).write('./img/'+ files[i], function(err){ if(err){ console.log("失敗"); } }); } })
之後,發現現在JS程式可以批量更改圖片尺寸了!
又來需求了,老闆讓我把這個月的銷售額(已經在程式的陣列中),生在Excel檔案中:
https://www.npmjs.com/package/node-xlsx
npm install node-xlsx
下載完畢node-xlsx後,參考API寫程式碼:
var xlsx = require("node-xlsx"); var fs = require("fs"); //資料 var data = [["月份","銷售額(萬)"],[1,90], [2,30], [3,190], [4,500]]; //生成Excel格式的資料 var buffer = xlsx.build([{name: "銷售表", data: data}]); //生成Excel檔案,並且將資料寫入 fs.writeFile("./銷售表.xlsx", buffer, function(err){ if(err){ console.log("生成失敗"); return; } console.log("生成成功") })
所以npm真的是好東西
l 資源很多
l 下載方便
l 依賴管理方便
5.2包依賴管理
package.json是npm安裝模組時的依據。
每個專案的根目錄下面,一般都有一個package.json檔案,定義了這個專案所需要的各種模組,以及專案的配置資訊(比如名稱、版本、許可證等資料)。npm install命令根據這個配置檔案,自動下載所需的模組,也就是配置專案所需的執行和開發環境。
使用場景:我需要A,A依賴B,B依賴C
常見的包管理工具都有迴圈依賴的功能,你只需要記住你要什麼東西
package.json檔案可以手工編寫,也可以使用npm init命令自動生成
建立一個身份證記錄自己的專案依賴了哪些npm包。
所以刪除node_modules資料夾,重新下載一次,這次要加上--save儲存到身份證中。
npm init
這個命令可以建立package.json檔案。
此時生成了一個package.json檔案,這是專案的身份證:
{ "name": "02-npm_study", //專案名稱 "version": "1.0.0", //版本號 "description": "這是我們的學習npm案例", //描述 "main": "app.js", //入口檔案 "scripts": { //除錯命令 "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "牛逼" //關鍵詞 ], "author": "rope", //作者 "license": "ISC" //版權協議 }
然後按照依賴,此時還是用npm install命令,但是要加上--save引數,表示記錄到package.json中
npm install nzh --save
或
npm install --save nzh
此時node_modules資料夾還是會下載這些模組,並且package.json檔案中多出了dependencies依賴項:
{ "name": "02-npm_study", "version": "1.0.0", "description": "這是我們的學習npm案例", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "牛逼" ], "author": "rope", "license": "ISC", "dependencies": { "gm": "^1.23.1", "node-xlsx": "^0.12.1", "nzh": "^1.0.3", "solarlunar": "^2.0.3" } }
專案身份證的意義在於,記錄你的專案依賴了什麼模組,可以使用以下命令一次性下載回來:
npm install
不指定任何包的名字,此時將會拉取所有package.json中宣告的dependencies依賴項
l 如何區分開發依賴和執行依賴(生產依賴)
當你的專案放到瀏覽器去執行的時候你還需要這個依賴嗎?如果需要那它就是生產(執行)依賴,反之是開發依賴。
5.3版本符號的意思
package.json檔案的詳細介紹:https://docs.npmjs.com/files/package.json
5.4淘寶映象
npm在中國大陸沒有映象,下載速度慢,淘寶為我們搭建了民間映象。
安裝淘寶映象特別簡單,直接使用:
npm install -g cnpm --registry=https://registry.npm.taobao.org
-g表示在全域性位置安裝
這條語句表示:在電腦安裝了一個叫cnpm的命令列工具,並且附加引數--registry為一個地址。
-g到底安裝在哪?用下面命令檢視具體安裝位置:
npm root -g
這裡相當於系統的一個底層位置,這可以安裝系統的CLI,也就是說-g安裝的不是專案依賴,也不是模組。而是系統的CLI,就是給CMD豐富了一些功能,比如豐富了cnpm命令。
不需要知道那麼多,總而言之,-g安裝的東西,一般都是用來CMD控制檯當命令用。
命令列介面(英語:Command-Line Interface,縮寫:CLI)是在圖形使用者介面得到普及之前使用最為廣泛的使用者介面,它通常不支援滑鼠,使用者通過鍵盤輸入指令,計算機接收到指令後,予以執行。也有人稱之為字元使用者介面(CUI)。
今後完全可以用cnpm代替npm使用。
cnpm install