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

嗨大家好,我是 Robin ~
这篇主要学习大家耳熟能祥的 NPM, NVM 。

以其他语言或是其他例子来说就像
Python -> pip
PHP -> composer
Robin -> handsome

看到最后一个是不是特别有Fu
如果不没使用过上述程式和工具没关係,
你只要知道 NPM 为你做了很多事。
我们感谢他(゚∀゚)

警告:
这篇内容看起来会稍微偏长一点,可能需要一点点耐心
或是想知道特定关键字内容也可以直接搜寻该关键字。

此篇学习目标 ◑ω◐ :

什么是NVM 和 NPMNVM 基本用法NPM 攻略之我全都要

有看到 NVM 和 NPM 光看标题的偏心程度吗?
因为我自身接触比较常使用 NPM ,
所以比较想特别研究 NPM,
如果有 NVM 一定要学的在底下留言跟我说~

什么是NVM 和 NPM

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)

但是其实实际时常遇到的步骤是以下

下载 或是 使用git clone 该专案执行该主程式出事... 喷错看Error message...啊...原来是我的local端没有装某些模组...无限轮迴 2-5 步骤 直到可以正常执行。

在 NPM 的淫威之下,你只需要

下载别人专案npm installEnjoy 该专案

而你想说...

和运表示:因为有纪录啊! 笨蛋~
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 listnpm llnpm la

列出来会发现...
我这边只有安装Express
结果...

怎么辣么多Σ(*゚д゚ノ)ノ
如上述所见,其实你安装的模组可能会依赖其他模组,其他模组又会依赖其他模组,所以就会变得很多层...这时候可以

但是其实可以改成这样下

npm list --depth=0

就会列出最上层的部分,看起来舒服多了。

安装 Package

以前 NPM 会有分三种方式安装

npm install <packageName>
安装该模组内容至 node_module但是不添加依赖至 package.jsondependenciesdevDependenciesnpm install <packageName> --save
安装该模组内容至 node_module 并添加依赖至 package.jsondependenciesnpm install <packageName> --save-dev
安装该模组内容至 node_module 并添加依赖至 package.jsondevDependencies

(这边旧版本是指 npm 5 以前,所以时代也有点久远)

现在差异在于 npm 已经将预设的 npm install改成有 --save
所以目前上述的 1 和 2 会相等。

所以现在新版大多数是使用

npm install <packageName>ornpm 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


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章