iT邦幫忙

4

【我可以你也可以的Node.js】第九篇 - NPM、NVM 自己的版本自己控制

Robin 2020-04-12 23:59:5511828 瀏覽

嗨大家好,我是 Robin ~
這篇主要學習大家耳熟能祥的 NPM, NVM

以其他語言或是其他例子來說就像
Python -> pip
PHP -> composer
Robin -> handsome

看到最後一個是不是特別有Fu
如果不沒使用過上述程式和工具沒關係,
你只要知道 NPM 為你做了很多事。
我們感謝他(゚∀゚)

警告
這篇內容看起來會稍微偏長一點,可能需要一點點耐心
或是想知道特定關鍵字內容也可以直接搜尋該關鍵字。

此篇學習目標 ◑ω◐ :

  1. 什麼是NVMNPM
  2. NVM 基本用法
  3. NPM 攻略之我全都要

有看到 NVMNPM 光看標題的偏心程度嗎?
因為我自身接觸比較常使用 NPM
所以比較想特別研究 NPM
如果有 NVM 一定要學的在底下留言跟我說~

什麼是NVMNPM

NVM(Node Version Manager)

nvm is a version manager for node.js, designed to be installed per-user, and invoked per-shell. nvm works on any POSIX-compliant shell (sh, dash, ksh, zsh, bash), in particular on these platforms: unix, macOS, and windows WSL.

簡單來說就是可以讓你自己管理自己 Node 版本的工具,
想用哪個版本,就用哪個版本,而且操作容易。
(我個人感覺有點像是python的pipenv)。

NPM ( Node Package Manager )

npm(全稱 Node Package Manager,即「node包管理器」)是Node.js預設的、以JavaScript編寫的軟體套件管理系統。

就如同標題所說的
Robin -> handsome
簡單來說 Node 的應用程式基本上圍繞的都是第三方的模組,
所謂別人造的輪子~就是香

而這些第三方模組在管理方面就由 NPM 大大所管控
而每個人只需要參照 NPM 所產生的 package.json 紀錄的內容
就可以知道這個專案用了哪些模組。
聽起來是不是很色?


安裝 NPM and NVM

如果已經安裝完的可以直接跳過安裝的這節。

安裝 NPM

安裝可以看這篇,Node的安裝方式。
你會想說...
咦!? 這不是 Node 嗎?
我要裝的是 NPM !
對沒錯,通常在安裝 Node 過程中,
其實他已經幫你順便安裝了~
一個買一送一的概念。
形影不離就像Robin 離不開 handsome 這個字一樣

安裝NVM

官方直接是建議用 curl 或是 wget 的方式
廢話不多說~
直接打開你的 terminal

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.3/install.sh | bash
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

如果是 macOS 的同學 homebrew 也可以喔

brew install nvm

只是 homebrew
有網上的大大說好像有機率會有問題(我自己本身是沒遇到過)
所以還是盡量使用官方推薦的方法吧。


NVM

安裝某版本 Node(以 v12.16.1 為例)

nvm install v12.16.1


安裝完之後他會自動幫你把 Default 自動改成你剛才裝的版本。
這點要注意一下~
不過 Terminal 上也會很貼心的提醒你,所以不用太擔心。

切換某版本 Node(以 v12.15.0 -> v12.16.1 為例)

nvm use v12.16.1

目前我主要會用到就這兩個語法
如果有對他指令有興趣可以打 nvm --help 查看唷
看起來是不是真的很方便,說切就切。

NPM 攻略之我全都要

先講一下我還沒研究以前,
我不知道我平常下以下三種差異。
npm install <packageName>
npm install <packageName> --save
npm install <packageName> --save-dev
一整個就是

如果在螢幕前的你也一樣,恭喜你這篇你值得看下去xD

預防針
由於 NPM 真的很廣
我就盡力整理可能會用到的,
如果有漏講先講聲抱歉 QQ
雖然這篇有寫到部分內容,但是我這邊還是會統整再講一次。
那開始囉~

查看NPM版本

npm -v

專案初始化

npm init

當專案開始時,起手式就是npm init,當下了這行他就會問你...
安安~ 你好! 幾歲住哪?

如果你都想用預設之後再改相關設定可以使用

npm init -y

所以npm init 他會做什麼?

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See npm help json for definitive documentation on these fields
and exactly what they do.

Use npm install <pkg> afterwards to install a package and
save it as a dependency in the package.json file.

翻譯蒟蒻:

親愛的~我會引導你建立你的 package.json ,不用擔心和怕怕,如果看不懂那些相關設定詳情可以下這個指令 npm help json

當你之後想安裝 package 時,請使用 npm install <pkg> 然後我會幫你把這個項目增加至 package.json的相依項目,之後就可以靠這個檔案打天下囉~

npm init 所產生的 Package.json 內容

Package name

通常會以你的檔案夾名稱做為預設,就單純指你的專案名稱。
如果日後需要修改也可以更動,所以不用擔心。
通常規範是說,要用小寫,且名稱簡潔。

Version

就是該專案的版號,對於專案來說可以說是非常重要的,
使用別人的模組時也應該要特別注意該專案的版號。
正常來說專案有任何改動,版本號應該都要做更動。

Description

這個就跟它字面上的意思一樣,
這邊可以描述你的專案和使用方法等等的。
(如果沒有輸入這個部分的話會一直提示你)

他會提示著你,提示到你心底發寒

除此之外,這個也可以方便他人在 npm search 搜尋到你製作的 Package 唷

Entry point

簡單來說就是你這個專案,要執行的切入點,
也就是如果我要啟動這個專案我該執行哪個程式。
通常是app.js , index.jsserver. js

Test command

其實這個就是說專案的測試指令,預設是

"echo \"Error: no test specified\" && exit 1"

其實他就是在你的專案下command line 指令
打開 package.json 會發現

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
},

這個 script的地方還可以做很多事情,
當你使用

npm run test

他就會執行該Key值裡面的東西
舉例~ 我在 scripts 內增添一個在 Terminal print 出 "Hellow World" 的指令

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "helloWorld": "echo 'Hellow World'"
},

我就可以使用 npm run helloWorld執行該指令
結果:

你這時可能會想說
我在 Terminal 執行就好啦~幹嘛那麼多此一舉?
Good !
等等會有一個小節講 npm run <scriptKeyName>
這邊你只要知道在init的時候他幫你scripts 那邊多增加了一個 test 的 command。

Git repository

這個很簡單,就是紀錄你的專案 Git 原始碼位置。

Keywords

Put keywords in it. It’s an array of strings. This helps people discover your package as it’s listed in npm search.

這個用途跟主要就是讓其他使用者使用 npm search 能搜尋到你的 package。
(跟 Description 部分用途一樣)
這個概念有點像是 SEO 的 Tag xDD

Author

這個就是指專案作者,正常會用author-name <author@email.com>來表示

License

是指專案版權。
預設是ISC
詳細可以參閱這個ISC授權條款
除此之外也有其他的授權條款可以參閱這篇

安裝專案的相依

npm install

這個是我覺得 NPM 超強大的地方。
相信在讀這篇的你,不管使用何種語言都曾經需要安裝第三方的模組,
當使用其他人的專案通常是先讀該專案的 README
看需要安裝哪些 module (package)

但是其實實際時常遇到的步驟是以下

  1. 下載 或是 使用git clone 該專案
  2. 執行該主程式
  3. 出事... 噴錯
  4. 看Error message...
  5. 啊...原來是我的local端沒有裝某些模組...
  6. 無限輪迴 2-5 步驟 直到可以正常執行。

NPM淫威之下,你只需要

  1. 下載別人專案
  2. npm install
  3. Enjoy 該專案

而你想說...

和運表示:因為有紀錄啊! 笨蛋~
NPM表示:因為有紀錄啊! 笨蛋~
(開玩笑的)

因為 npm install 會根據該專案的 package.json 中的 Dependencies 項目安裝而這些項目怎麼來的?
等等會在 安裝package 的章節提到。
至於安裝的模組會存在該專案資料夾的node_module
你沒看錯!以往我們都是將模組安裝在local端的global,
但是在 Node 的世界希望每個專案都獨立,
雖然說這樣會造成記憶體的浪費,
但是卻能避免掉很多不必要的問題。

這時你可能會想說什麼問題?
例如說你 local 端有很多專案,那每個專案都需要某個模組,但是你以global的方式安裝,那代表你切換專案時,你也必須降版或升版某模組,才能讓該專案正常運行。

而在你下 npm install 的同時也會產生package.lock.json,這個部分主要是

package-lock.json的作用就是鎖定安裝依賴時包的版本,並且需要上傳到git,以保證其他人npm install時安裝的依賴能夠保持一致

什麼意思?
就是說 package.json 其實只能鎖定大版本,而小版本卻無法鎖定很細小的版本,那如果這些小版本會影響到你,而且這些小版本是很頻繁的更新的,那你大概專案也不用做了光 Debug 就飽了xDD

列出安裝的模組

npm list
npm ll
npm la

列出來會發現...
我這邊只有安裝Express
結果...

怎麼辣麼多Σ(*゚д゚ノ)ノ
如上述所見,其實你安裝的模組可能會依賴其他模組,其他模組又會依賴其他模組,所以就會變得很多層...這時候可以

但是其實可以改成這樣下

npm list --depth=0

就會列出最上層的部分,看起來舒服多了。

安裝 Package

以前 NPM 會有分三種方式安裝

  1. npm install <packageName>
    安裝該模組內容至 node_module但是不添加依賴至 package.jsondependenciesdevDependencies
  2. npm install <packageName> --save
    安裝該模組內容至 node_module添加依賴至 package.jsondependencies
  3. npm install <packageName> --save-dev
    安裝該模組內容至 node_module添加依賴至 package.jsondevDependencies

(這邊舊版本是指 npm 5 以前,所以時代也有點久遠)

現在差異在於 npm 已經將預設的 npm install改成有 --save
所以目前上述的 1 和 2 會相等。

所以現在新版大多數是使用

npm install <packageName>
or
npm install <packageName> --save-prod

npm install <packageName> --save-dev

如果想要像舊版本不添加至依賴可以用以下的方式

npm install <packageName> --no-save

至於 dependenciesdevDependencies 差異在哪請看下一個章節。

指定版本安裝

指定版本安裝只需要在後面加上@<版號>

npm install <packageName>@<版號>

安裝以Global 的方式

安裝在 local global的方式,非常簡單。

npm install <packageName> -g

(非常不建議使用這種方式,除非真的需要)
這邊分享一下我大約三個月以前的故事,
可以說是非常心酸,浪費了我一整天的時間QQ。

心酸小故事

因為當初對於 npm 不熟悉,所以將自動化測試的框架 Nightwatch 安裝至 global ,然後我一直都是以 global 的方式在執行我的測試,然後我也好巧不巧,不知道哪根筋不對,在該專案把 Nightwatch 升級了,但是 local 的版本少了一個大版本,於是該專案在 Jenkins 大噴錯,怎麼跑怎麼掛,但是我在 local 跑得又很歡樂,心裡覺得非常不可思議,因為 package.json 又顯示版本跟 Jenkins 上ㄧ樣啊。
非常沒道理!
最後追查了一整天才發現,原來我一直都是用 global 的方式跑。 所以一直在跑在舊的版本...(|||゚д゚)

聽起來是不是還好...
但是我還是心有餘悸,當時真的是很無助QQ

分享給你各位。

Dependencies 和 DevDependencies差異

這兩個最主要的差異是開發需要或是該生產專案需要

什麼意思?
例如你撰寫一個 API 的應用
你的用的 module 是 Express ,那這個就該算是 dependencies

那這個 API 需要測試,你可能會安裝 Jest 來測試,但是這不是這個專案所需要的,單純是開發所需,那這個就該算是 devDependencies

同理如果是前端的話可能就像是 webpack

解除安裝 Package

install 的相反是什麼?remove
只需要用 uninstall 就好囉

npm uninstall <packageName>

他也會順邊幫你的 package.json 處理好

如果要解除 global 的 Package 也只要在最後加上 -g 就可以囉

npm uninstall <packageName> -g

搜尋Package

npm 可以直接搜尋現在已經發布公開的 Package

npm search <keyword>

例如我想要找 mongoDB相關的 Package

就如同上面提到的 description 和 keywords 會影響到你被搜尋的結果。

Npm Start

這個真的是我覺得很黑人問號的一個地方,
我在很多地方都看到人家直接使用npm start就可以直接啟動他的專案,然後我自己開發的時候怎麼用他都會說無法執行,他說我的scripts 裡面沒有設定 start 這個key。

但是我檢查他們專案可以直接用的 package.json 也沒有啊!
結果查到資料...

npm start 預設會執行 server.js 檔案...
如果沒有的話就會依據 scripts 設定的執行

假如說你的 app.js想要藉由 npm start 執行,可以用上面提的方式增加進去 package.json
如下

"scripts": {
    "start": "node run app.js"
},

直接使用 Node 執行程式和使用 npm run 的差異

最大的差異在於,直接使用 Node <fileName> 可能會吃到你 global 安裝的 package,不會是該專案所需的版本。
而使用 npm run <scriptKeyword>就不用擔心上述的問題。
(之前因為這個,找了很久原因 Orz)

題外話

2020年3月16 日,GitHub CEO Nat Friedman 宣布 GitHub 已簽署收購 NPM(npm 背後的公司)的協定,並表示 npm 加入 GitHub 後會繼續免費提供公共軟體註冊中心服務。

當時看到這則新聞,我同事問我為什麼跪在電腦前。
我只能說 GitHub 拔拔就是厲害~

總結

在研究過程中,有看到 yarn 這個第三方的套件,
看很多文章比較起來是各方面都優於 NPM
不過那些文章發布時間都是有一段時間的,
我也還沒實際接觸 yarn ,所以也不敢斷定哪個好哪個不好。
所以也不敢斷定哪個好哪個壞~
如果有近期用兩者比較的你也可以分享給我
不過不論哪個好或壞,這篇研究起來讓我對 NPM 有一個飛越性的成長。
然後這篇真的有點多希望對於讀者的你有幫助( • ̀ω•́ )
看滿多文章都是分篇去寫,想說來一個懶人包,一篇學到底。

參考文獻

NVM
NPM 使用介绍
The package.json guide
為什麼我從npm到yarn再到npm?
Difference between npm install something vs. npm install something --save vs. npm install something --save-dev
React Day7 - NPM
從零開始: 使用NPM套件
npm-package.json
Specifics of npm's package.json handling


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

我要留言

立即登入留言