前端十万个为何(之一):咱们为何须要npm?

现代前端开发已经离不开Node了。你们都知道在安装Node时会附赠一个命令行工具Node Package Manager,即npm。或许你已经照着教程输入过好多遍”npm install xxx”,而且你发现npm的命令林林总总几十条,package.json的配置项使人眼花缭乱,但不知你有没有认真想过,咱们为何须要npm?若是没有它,世界会怎样?php

个人理解,npm所作的一切都是为了解决软件工程界一个一直以来的追求:代码复用。抓住这个核心,也就抓住了正确理解和使用npm的钥匙。css

为何要复用代码呢?由于基于已有的成熟代码快速开发新的应用,能够极大地提升开发效率,正所谓“站在巨人肩膀上”“不要重复造轮子”。html

So,在Node环境下要复用JS代码,咱们有哪些方案呢? 前端

1. 刀耕火种——copy&paste
复制粘贴代码的思路很直接,但现在还在的这样搞的同窗应该是从原始社会穿越来的吧。。这个方案最大的缺点倒还不是代码冗余,而是一旦所复制的原始代码发生了变化,那就必须手动修改每一处复本,在稍有规模的项目里根本不可行。 vue

2. 耕牛犁地——CommonJSnode

Node实现了一个模块系统CommonJS,实在是JSer的一大福音。借助它,咱们没必要再复制粘贴代码了:假如一个做者开发了一个名为lib1的库,他只需代码写在一个名叫lib1.js的文件里,用module.export语句导出;而使用者只需把lib1.js下载到本身工程目录,require一下即可直接用啦!(此时lib1也被称为一个“依赖”)webpack

但这里仍然存在两个大问题:git

一,若是lib1.js自己也复用了别的代码,好比lib2.js、lib3.js...那你在下载lib1.js的时候,必须手动把它所依赖的这些模块文件也一并下载;可要是lib2.js还依赖lib5.js、lib6.js....呢?一棵庞大的、深不见底的依赖树很难手工管理。程序员

2、lib1.js的做者修复了几个bug,但没有一个机制能让他通知你升级旧的模块文件。github

做为一名职业素养良好的程序员,看到这些问题的第一反应是否是“写个脚本”?哈哈,不用麻烦了,由于已经有人替咱们写好了,这个脚本工具就是npm。 

3. 机械化耕做——npm
有了上面“自力更生”的原始体验,再看看npm提供的依赖安装、卸载、升级、发布等一条龙服务,是否是很爽?

Npm制定了一个包规范,所谓规范就是一些格式和约定,好比约定从package.json文件里读取这个包的全部信息,包括它的名字、版本号、它依赖于哪些别的包等;又好比约定node_modules目录专门用来存放第三方依赖,Node为此提供的支持是内置的require方法默认会到这个目录下去检索模块,而无需手动指定路径。有了这些规范,一个包的开发、依赖安装、发布等都步骤都标准化了,省心省力。

能够说,JavaScript从一门“玩具”语言,到现在能够胜任大型项目开发,模块化和npm是其进化路上的重要一步。


后记

你们都知道前端有“三板斧”,但刚才我一直在谈JS,彻底没提到另外两板斧。这是由于npm只是“Node模块管理器”,Node上又没有HTML和CSS,npm天然管不到。那么除了能够直接支持Node端的开发之外,npm又如何为浏览器端开发提供支持呢?

答案是:npm生态圈提供了不少强大的前端开发工具,好比Webpack、Babel、ESLint等。特别是Webpack、Browserify、rollup这类构建工具,能够接手浏览器端的依赖管理重任,以及不少其余的附加功能。这些内容,且待下回分解。。

前端十万个为何(之一):咱们为何须要npm?

标签:重要   col   以及   检索   xxx   存在   你在   语句   16px   

原文:http://www.cnblogs.com/leegent/p/7244660.html

 

==========

什么是 NPM 为何要使用 NPM 如何使用 NPM 安装 使用 npm init npm set npm info npm search npm list npm install 本地模式和全局模式 安装不一样版本 dependencies 依赖 devDependencies 开发依赖 npm run scripts 脚本 pre- 和 post- 脚本 npm bin 建立全局连接 建立包 包的发布 参考连接 个人经常使用命令

什么是 NPM

npm 之于 Node.js ,就像 pip 之于 Python, gem 之于 Ruby, pear 之于 PHP 。

npm 是 Node.js 官方提供的包管理工具,他已经成了 Node.js 包的标准发布平台,用于 Node.js 包的发布、传播、依赖控制。npm 提供了命令行工具,使你能够方便地下载、安装、升级、删除包,也可让你做为开发者发布并维护包。

为何要使用 NPM

npm 是随同 Node.js 一块儿安装的包管理工具,能解决 Node.js 代码部署上的不少问题,常见的场景有如下几种:

容许用户从 npm 服务器下载别人编写的第三方包到本地使用。 容许用户从 npm 服务器下载并安装别人编写的命令行程序到本地使用。 容许用户将本身编写的包或命令行程序上传到 npm 服务器供别人使用。

npm 的背后,是基于 couchdb 的一个数据库,详细记录了每一个包的信息,包括做者、版本、依赖、受权信息等。它的一个很重要的做用就是:将开发者从繁琐的包管理工做(版本、依赖等)中解放出来,更加专一于功能的开发。

如何使用 NPM

安装

npm 不须要单独安装。在安装 Node 的时候,会连带一块儿安装 npm 。可是,Node 附带的 npm 可能不是最新版本,最后用下面的命令,更新到最新版本。

 
1
$ sudo npm install npm@latest -g

若是是 Window 系统使用如下命令便可:

 
1
npm install npm -g

也就是使用 npm 安装本身。之因此能够这样,是由于 npm 自己与 Node 的其余模块没有区别。 而后,运行下面的命令,查看各类信息。

 
1
2
3
4
5
6
7
8
9
10
11
# 查看 npm 命令列表
$ npm help
 
# 查看各个命令的简单用法
$ npm -l
 
# 查看 npm 的版本
$ npm -v
 
# 查看 npm 的配置
$ npm config list -l

使用

npm init

npm init 用来初始化生成一个新的 package.json 文件。它会向用户提问一系列问题,若是你以为不用修改默认配置,一路回车就能够了。
若是使用了 -f(表明force)、-y(表明yes),则跳过提问阶段,直接生成一个新的 package.json 文件。

?
1
$ npm init -y

npm set

npm set 用来设置环境变量

 
1
2
3
4
$ npm set init-author- name 'Your name'
$ npm set init-author-email 'Your email'
$ npm set init-author-url 'https://yourdomain.com'
$ npm set init-license 'MIT'

上面命令等于为 npm init 设置了默认值,之后执行 npm init 的时候,package.json 的做者姓名、邮件、主页、许可证字段就会自动写入预设的值。这些信息会存放在用户主目录的 ~/.npmrc文件,使得用户不用每一个项目都输入。若是某个项目有不一样的设置,能够针对该项目运行 npm config。

npm info

npm info 命令能够查看每一个模块的具体信息。好比,查看 underscore 模块的信息。

 
1
$ npm info underscore

上面命令返回一个 JavaScript 对象,包含了 underscore 模块的详细信息。这个对象的每一个成员,均可以直接从 info 命令查询。

 
1
2
3
4
5
$ npm info underscore description
 
$ npm info underscore homepage
 
$ npm info underscore version

npm search 命令用于搜索 npm 仓库,它后面能够跟字符串,也能够跟正则表达式。

 
1
$ npm search <搜索词>

npm list

npm list 命令以树形结构列出当前项目安装的全部模块,以及它们依赖的模块。

 
1
2
3
4
5
6
7
$ npm list
 
# 加上 global 参数,会列出全局安装的模块
$ npm list - global
 
# npm list 命令也能够列出单个模块
$ npm list underscore

npm install

使用 npm 安装包的命令格式为:
npm [install/i] [package_name]

本地模式和全局模式

npm 在默认状况下会从 https://npmjs.org 搜索或下载包,将包安装到当前目录的 node_modules 子目录下。

若是你熟悉 Ruby 的 gem 或者 Python 的 pip,你会发现 npm 与它们的行为不一样,gem 或 pip 老是以全局模式安装,使包能够供全部的程序使用,而 npm 默认会把包安装到当前目录下。这反映了 npm 不一样的设计哲学。若是把包安装到全局,能够提供程序的重复利用程度,避免一样的内容的多分副本,但坏处是难以处理不一样的版本依赖。若是把包安装到当前目录,或者说本地,则不会有不一样程序依赖不一样版本的包的冲突问题,同时还减轻了包做者的 API 兼容性压力,但缺陷则是同一个包可能会被安装许屡次。

咱们在使用 supervisor 的时候使用了 npm install -g supervisor 命令,就是以全局模式安装 supervisor 。

这里注意一点的就是,supervisor 必须安装到全局,若是你不安装到全局,错误命令会提示你安装到全局。若是不想安装到默认的全局,也能够本身修改全局路径到当前路径 npm config set prefix "路径" 安装完之后就能够用 supervisor 来启动服务了。

supervisor 能够帮助你实现这个功能,它会监视你对代码的驱动,并自动重启 Node.js 。

通常来讲,全局安装只适用于工具模块,好比 eslint 和 gulp 。关于使用全局模式,多数时候并非由于许多程序都有可能用到了它,为了减小多重副本而使用全局模式,而是由于本地模式不会注册 PATH 环境变量

“本地安装”指的是将一个模块下载到当前项目的 node_modules 子目录,而后只有在项目目录之中,才能调用这个模块。

本地模式和全局模式的特色以下:

模式 可经过 require 使用 注册 PATH
本地模式
全局模式
 
1
2
3
4
5
6
# 本地安装
$ npm install <package name = "" >
 
# 全局安装
$ sudo npm install - global <package name = "" >
$ sudo npm install -g <package name = "" ></package></package></package>

npm install 也支持直接输入 Github 代码库地址。

安装以前,npm install 会先检查,node_modules 目录之中是否已经存在指定模块。若是存在,就再也不从新安装了,即便远程仓库已经有了一个新版本,也是如此。

若是你但愿,一个模块无论是否安装过, npm 都要强制从新安装,可使用 -f 或 –force 参数。

 
1
$ npm install <packagename> --force</packagename>

安装不一样版本

install 命令老是安装模块的最新版本,若是要安装模块的特定版本,能够在模块名后面加上 @ 和版本号。

 
1
2
3
$ npm install sax@latest
$ npm install sax@0.1.1
$ npm install sax@ ">=0.1.0 <0.2.0"

install 命令可使用不一样参数,指定所安装的模块属于哪种性质的依赖关系,即出如今 packages.json 文件的哪一项中。

–save:模块名将被添加到 dependencies,能够简化为参数-S。
–save-dev:模块名将被添加到 devDependencies,能够简化为参数-D。

 
1
2
3
4
5
$ npm install sax --save
$ npm install node-tap --save-dev
# 或者
$ npm install sax -S
$ npm install node-tap -D

dependencies 依赖

这个能够说是咱们 npm 核心一项内容,依赖管理,这个对象里面的内容就是咱们这个项目所依赖的 js 模块包。下面这段代码表示咱们依赖了 markdown-it 这个包,版本是 ^8.1.0 ,表明最小依赖版本是 8.1.0 ,若是这个包有更新,那么当咱们使用 npm install 命令的时候,npm 会帮咱们下载最新的包。当别人引用咱们这个包的时候,包内的依赖包也会被下载下来。

 
1
2
3
"dependencies" : {
     "markdown-it" : "^8.1.0"
}

devDependencies 开发依赖

在咱们开发的时候会用到的一些包,只是在开发环境中须要用到,可是在别人引用咱们包的时候,不会用到这些内容,放在 devDependencies 的包,在别人引用的时候不会被 npm 下载。

 
1
2
3
4
5
6
7
8
9
10
11
"devDependencies" : {
     "autoprefixer" : "^6.4.0" ,0 ",
     " babel-preset-es2015 ": " ^6.0.0 ",
     " babel-preset-stage-2 ": " ^6.0.0 ",
     " babel-register ": " ^6.0.0 ",
     " webpack ": " ^1.13.2 ",
     " webpack-dev-middleware ": " ^1.8.3 ",
     " webpack-hot-middleware ": " ^2.12.2 ",
     " webpack-merge ": " ^0.14.1 ",
     " highlightjs ": " ^9.8.0"
}

当你有了一个完整的 package.json 文件的时候,就可让人一眼看出来,这个模块的基本信息,和这个模块所须要依赖的包。咱们能够经过 npm install 就能够很方便的下载好这个模块所须要的包。

npm install 默认会安装 dependencies 字段和 devDependencies 字段中的全部模块,若是使用 --production 参数,能够只安装 dependencies 字段的模块。

 
1
2
3
$ npm install --production
# 或者
$ NODE_ENV=production npm install

一旦安装了某个模块,就能够在代码中用 require 命令加载这个模块。

 
1
2
var backbone = require( 'backbone' )
console.log(backbone.VERSION)

npm run

npm 不只能够用于模块管理,还能够用于执行脚本。package.json 文件有一个 scripts 字段,能够用于指定脚本命令,供 npm 直接调用。
package.json

 
1
2
3
4
5
6
7
8
9
10
11
12
{
   "name" : "myproject" ,
   "devDependencies" : {
     "jshint" : "latest" ,
     "browserify" : "latest" ,
     "mocha" : "latest"
   },
   "scripts" : {
     "lint" : "jshint **.js" ,
     "test" : "mocha test/"
   }
}

scripts 脚本

顾名思义,就是一些脚本代码,能够经过 npm run script-key 来调用,例如在这个 package.json 的文件夹下使用 npm run dev 就至关于运行了 node build/dev-server.js 这一段代码。使用 scripts 的目的就是为了把一些要执行的代码合并到一块儿,使用 npm run 来快速的运行,方便省事。
npm run 是 npm run-script 的缩写,通常都使用前者,可是后者能够更好的反应这个命令的本质。

 
1
2
3
4
5
6
7
8
9
// 脚本
"scripts" : {
     "dev" : "node build/dev-server.js" ,
     "build" : "node build/build.js" ,
     "docs" : "node build/docs.js" ,
     "build-docs" : "npm run docs & git checkout gh-pages & xcopy /sy dist\\* . & git add . & git commit -m 'auto-pages' & git push & git checkout master" ,
     "build-publish" : "rmdir /S /Q lib & npm run build &git add . & git commit -m auto-build & npm version patch & npm publish & git push" ,
     "lint" : "eslint --ext .js,.vue src"
}

npm run 若是不加任何参数,直接运行,会列出 package.json 里面全部能够执行的脚本命令。
npm 内置了两个命令简写, npm test 等同于执行 npm run test,npm start 等同于执行 npm run start。

 
1
"build" : "npm run build-js && npm run build-css"

上面的写法是先运行 npm run build-js ,而后再运行 npm run build-css ,两个命令中间用 && 链接。若是但愿两个命令同时平行执行,它们中间能够用 & 链接。

写在 scripts 属性中的命令,也能够在 node_modules/.bin 目录中直接写成 bash 脚本。下面是一个 bash 脚本。

 
1
2
3
4
#!/bin/bash
 
cd site/main
browserify browser/main.js | uglifyjs -mc > static /bundle.js

假定上面的脚本文件名为 build.sh ,而且权限为可执行,就能够在 scripts 属性中引用该文件。

 
1
"build-js" : "bin/build.sh"

pre- 和 post- 脚本

npm run 为每条命令提供了 pre- 和 post- 两个钩子(hook)。以 npm run lint 为例,执行这条命令以前,npm 会先查看有没有定义 prelint 和 postlint 两个钩子,若是有的话,就会先执行 npm run prelint,而后执行 npm run lint,最后执行 npm run postlint。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
{
   "name" : "myproject" ,
   "devDependencies" : {
     "eslint" : "latest"
     "karma" : "latest"
   },
   "scripts" : {
     "lint" : "eslint --cache --ext .js --ext .jsx src" ,
     "test" : "karma start --log-leve=error karma.config.js --single-run=true" ,
     "pretest" : "npm run lint" ,
     "posttest" : "echo 'Finished running tests'"
   }
}

上面代码是一个 package.json 文件的例子。若是执行 npm test,会按下面的顺序执行相应的命令。
1. pretest
2. test
3. posttest

若是执行过程出错,就不会执行排在后面的脚本,即若是 prelint 脚本执行出错,就不会接着执行 lint 和 postlint 脚本。

npm bin

npm bin 命令显示相对于当前目录的,Node 模块的可执行脚本所在的目录(即 .bin 目录)。

 
1
2
3
# 项目根目录下执行
$ npm bin
./node_modules/.bin

建立全局连接

npm 提供了一个有趣的命令 npm link,它的功能是在本地包和全局包之间建立符号连接。咱们说过使用全局模式安装的包不能直接经过 require 使用。但经过 npm link 命令能够打破这一限制。举个例子,咱们已经经过 npm install -g express 安装了 express,这时在工程的目录下运行命令:

 
1
npm link express ./node_modules/express -> / user / local /lib/node_modules/express

咱们能够在 node_modules 子目录中发现一个指向安装到全局的包的符号连接。经过这种方法,咱们就能够把全局包当作本地包来使用了。

除了将全局的包连接到本地之外,使用 npm link 命令还能够将本地的包连接到全局。使用方法是在包目录(package.json 所在目录)中运行 npm link 命令。若是咱们要开发一个包,利用这种方法能够很是方便地在不一样的工程间进行测试。

建立包

包是在模块基础上更深一步的抽象,Node.js 的包相似于 C/C++ 的函数库或者 Java、.Net 的类库。它将某个独立的功能封装起来,用于发布、更新、依赖管理和版本控制。Node.js 根据 CommonJS 规范实现了包机制,开发了 npm 来解决包的发布和获取需求。
Node.js 的包是一个目录,其中包含了一个 JSON 格式的包说明文件 package.json。严格符合 CommonJS 规范的包应该具有如下特征:
。package.json 必须在包的顶层目录下;
。二进制文件应该在 bin 目录下;
JavaScript 代码应该在 lib 目录下;
。文档应该在 doc 目录下;
。单元测试应该在 test 目录下。

Node.js 对包的要求并无这么严格,只要顶层目录下有 package.json,并符合一些规范便可。固然为了提升兼容性,咱们仍是建议你在制做包的时候,严格遵照 CommonJS 规范。

咱们也能够把文件夹封装为一个模块,即所谓的包。包一般是一些模块的集合,在模块的基础上提供了更高层的抽象,至关于提供了一些固定接口的函数库。经过定制 package.json,咱们能够建立更复杂,更完善,更符合规范的包用于发布。

Node.js 在调用某个包时,会首先检查包中 packgage.json 文件的 main 字段,将其做为包的接口模块,若是 package.json 或 main 字段不存在,会尝试寻找 index.js 或 index.node 做为包的接口。

package.json 是 CommonJS 规定的用来描述包的文件,彻底符合规范的 package.json 文件应该含有如下字段:

name: 包的名字,必须是惟一的,由小写英文字母、数字和下划线组成,不能包含空格。
description: 包的简要说明。
version: 符合语义化版本识别规范的版本字符串。
keywords: 关键字数组,一般用于搜索。
maintainers: 维护者数组,每一个元素要包含 name 、email(可选)、web(可选)字段。
contributors: 贡献者数组,格式与 maintainers 相同。包的做者应该是贡献者数组的第一个元素。
bugs: 提交 bug 的地址,能够是网址或者电子邮件地址。
licenses: 许可证数组,每一个元素要包含 type(许可证的名称)和 url(连接到许可证文本的地址)字段。
repositories: 仓库托管地址数组,每一个元素要包含 type(仓库的类型,如 git)、URL(仓库的地址)和 path(相对于仓库的路径,可选)字段。
dependencies: 包的依赖,一个关联数组,由包名称和版本号组成。

包的发布

经过使用 npm init 能够根据交互式回答产生一个符合标准的 package.json。建立一个 index.js 做为包的接口,一个简单的包就制做完成了。
在发布前,咱们还须要得到一个帐号用于从此维护本身的包,使用 npm adduser 根据提示完成帐号的建立。

完成后可使用 npm whoami 检测是否已经取得了帐号。

若是你的包未来有更新,只须要在 package.json 文件中修改 version 字段,而后从新使用 npm publish 命令就好了。
若是你对已发布的包不满意,可使用 npm unpublish 命令来取消发布。

须要说明的是:json 文件不能有注释

个人经常使用命令

 
1
2
3
npm version  查看npm和node的版本
npm list --depth=0 [-g]  查看[全局]安装的包
npm root [-g]  查看[全局的]包的安装路径
相关文章
相关标签/搜索