前端工程之npm

package.json是npm package的配置文件,存储当前项目相关的信息。如果下载npm中的包,包内会自带该文件。

具体属性

{
  "name" : "underscore",  //当前包(项目)的名字
  "description" : "JavaScript's functional programming helper library.",
  "homepage" : "http://documentcloud.github.com/underscore/",
  "keywords" : ["util", "functional", "server", "client", "browser"],
  "author" : "Jeremy Ashkenas",
  "contributors" : [],
  "dependencies" : [],//生产依赖
  "devDependencies”:[],//开发依赖
  "repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"},
  "scripts": {
    "build": "node build.js"
  }
  "main" : "underscore.js",   //当前项目(包)的入口文件,该文件的导出对象作为该模块的导出对象 
  "version" : "1.1.6"
}

main:the main entry point for the libary; when someone runs require(<library name>), require resolves this call to require(<package.json:main>).

dependencies :used to list all the dependencies of your project that are available on npm. When someone installs your project through npm, all the dependencies listed will be installed as well. Additionally, if someone runs npm install in the root directory of your project, it will install all the dependencies to ./node_modules.

devDependencies :these are dependencies not required for normal operation, but required/recommended if you want to patch or modify the project. If you built your unit tests using a testing framework, for example, it would be appropriate to put the testing framework you used in your devDependencies field. To install a project's devDependencies, simply pass the --dev option when you use npm install.

scripts:每一个属性,对应一段脚本。每当执行npm run xxx 时就会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令。npm run新建的Shell会将当前目录的node_modules/.bin子目录append到PATH变量,执行结束后,再恢复原样。所以当前目录的node_modules/.bin子目录里面的所有脚本,都可以直接用脚本名调用,在没有全局安装时也不必加上路径。所以只要是 Shell可以运行的命令,都可以写在 npm 脚本里面。

  传入参数:npm run <command> [-- <args>] ,所以在scripts中要用 -- 双中线分隔传给npm命令的参数和传给脚本的参数。node server.js --port=8888 转换成  npm run server -- --port=8888 

  执行多个脚本:并行执行多个命令使用&符号,顺序执行(前一个任务成功才执行下一个任务)使用&&符号。

全局安装vs本地安装:

Global packages are for anything that you need to access from the shell. By contrast local packages are for using within your apps.

npm install xxx -g :属于全局安装将包安装在C:UsersadminAppDataRoaming pm ode_modules目录下,同时在node_modules平级目录生成批处理文件,这样可以在任何地方执行xxx的CIL命令。否则需要cd到项目的cmd命令所在目录再执行/双引号包含可执行命令的全路径,很繁琐。全局安装时的包不可以通过 require() 来引入。

@IF EXIST "%~dp0
ode.exe" (
  "%~dp0
ode.exe"  "%~dp0
ode_modulesgulpingulp.js" %*
) ELSE (
  @SETLOCAL                 //变量本地化
  @SET PATHEXT=%PATHEXT:;.JS;=;%    //删除js后缀的默认执行文件,不直接执行gulp.js
  node  "%~dp0
ode_modulesgulpingulp.js" %*    //在命令行输入gulp时,实际上调用的是这条命令:用node解释器调用批处理文件所在目录下的js文件
)
npm install xxx –save-dev :属于本地安装将包安装在项目根目录下的node_modules目录下的.bin目录下,生成对应的cmd命令,在项目根目录下可以直接运行。可以通过 require() 来引入本地安装的模块。

  


@IF EXIST "%~dp0
ode.exe" (
  "%~dp0
ode.exe"  "%~dp0..._gulp@3.9.1@gulpingulp.js" %*        //"执行其他目录下的文件"  "node执行的js文件地址"   %*其他任意变量
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0..._gulp@3.9.1@gulpingulp.js" %*  //%~dp0代表的是bat文件所在的文件目录,不可变;指向当前项目依赖的gulp模块的js
)
如果不安装全局包,则在pro目录下是不能执行对应的命令行命令,必须cd到.bin目录下,或者通过npm link命令或通过package.json的scripts字段设置:
"scripts" : {
  "build" : "webpack ./entry.js bundle.js""deploy": "export NODE_ENV=production && `npm bin`/webpack --config webpack.config.production.js && npm start",
}

然后运行npm run build命令。

require()查找文件的顺序

当require一个文件模块时,先从当前执行文件平级的的node_modules目录中查找;然后查找上一级的node_modules目录;依次迭代,直到根目录下的node_modules目录。如果还没有查找到指定模块的话,就会去NODE_PATH注册的路径中查找

require绝对路径的文件,查找时不用去遍历每一个node_modules目录,其速度最快。

为什么要全局安装和本地安装两次?

本地安装可以让每个项目依赖独立的包,不受全局包的影响,保证不同版本的包之间的相互依赖,可以通过require()使用引入的模块。是npm的默认安装模式。

全局安装并不依赖引入的模块。它会在'C:UsersadminAppDataRoaming pm'生成对应的cmd文件,保证在任何地方都可以通过命令行执行该程序,不用cd到项目目录执行。如全局安装gulp是为了在任何地方都可以执行gulp任务,本地安装gulp则是为了调用gulp插件的功能。

npm 常用命令

安装模块

npm install      //安装package.json中定义的所有依赖的包
npm install [<@scope>/]<name>@<version>    //安装指定版本的包,如不指定版本,默认安装最新的包
alias: npm i
options: 
-S|--save    //保存版本信息到package.json文件的dep字段中
-D|--save-dev    //保存版本信息到package.json文件的devDep字段中
npm install --production  # 添加了production参数后将仅仅安装package.json中dependencies 里面的包,不会安装devDependencies 里的模块,否则get all dependencies & devDependencies installed。一个模块不能同时在两种环境中安装。

卸载模块

npm uninstall <pkg>
aliases: remove, rm, r, un, unlink
options:
-S|--save    //删除package.json中dev字段对应的信息
-D|--save-dev //删除package.json中devDep字段对应的信息

更新模块

npm outdated [<pkg>]    //列出所有过时的包
npm update [-g] [<pkg>...]    //更新指定到包到最新版本;如果未指定,则更新所有包,包括全局和本地
aliases: up, upgrade
options:同上

其他命令

npm config get prefix              //获取全局模块安装路径;
where node                           //获取node所在路径;
npm <command> -h              //查看该命令的所有使用帮助信息;
npm view package@2.3.1 [version|dependencies] //查看远程包内的package.json信息
npm config ls –l                    //查看npm内置的配置参数
npm install 或者 npm install –save-dev   //自动将所在目录的package.json中的模块安装到node-modules文件夹下,不用一个一个安装模块。
npm ls xxx [–depth=0]                 //查看本地安装的模块版本信息,只看当前目录,不遍历子目录。注意:子模块的devdependency依赖包不会被安装,只安装dep包。

cnpm

因为npm是从国外服务器下载,经常出现异常,可以使用淘宝团队开发的镜像cnpm,cnpm跟npm用法一样。

安装命令:npm install cnpm -g --registry=https://registry.npm.taobao.org

create-react-app安装模块慢,可以设置永久使用cnpm:

$:npm config set registry https://registry.npm.taobao.org

$:npm config set registry http://registry.npmjs.org   #官方地址

使用nrm管理registry地址:

1.安装nrm:npm install -g nrm

2.注册registry地址:

  nrm add npm http://registry.npmjs.org

  nrm add cnpm https://registry.npm.taobao.org

3.切换registry地址

  nrm use npm/cnmp

依赖包版本管理 

包版本号为X.Y.Z三位,代表主版本号、次版本号和补丁版本号。当代码变更时,按以下原则更新版本号:
主版本号:有不兼容的API 修改时; 
次版本号:有向下兼容的功能性新增时;
补丁版本号:做了向下兼容的bug修正时。

依赖包版本号管理(固定写死需要手动更新):
~匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x的包,但是不包括1.3.0。
^匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,但是不包括2.0.0。

配置npm仅安装精确版本号的模块: npm config set save-exact true

package-lock.json

npm 5.0新增特性。package-lock.json is automatically generated for any operations where npm modifies either the node_modules tree, or package.json. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.如果package.json中使用了~或^指定版本,在重新npm i时会安装可用的最新版本,同时package-lock.json也会改变。但是如果之前的版本固定,package-lock.json也会固定。
It stores an exact, versioned dependency(including nested dependencies) tree rather than using starred versioning like package.json itself (e.g. 1.0.*). This means you can guarantee the dependencies for other developers or prod releases, etc. It also has a mechanism to lock the tree but generally will regenerate if package.json changes.
This is intended to lock down your full dependency tree. Let's say typescript v2.4.1 requires widget ~v1.0.0. When you npm install it grabs widget v1.0.0. Later on your fellow developer (or CI build) does an npm install and gets typescript v2.4.1 but widget has been updated to widget v1.0.1. Now your node module are out of sync. This is what package-lock.json prevents.(控制嵌套依赖包的版本)
忽略项目开发过程中有些依赖已经发生的更新而锁定当前项目所有依赖包的版本号,避免后来者新拉项目时因重新安装的依赖包版本不同而出现bug。(同事甲:为什么我的电脑上是正常的?!) 
原文地址:https://www.cnblogs.com/kevin2chen/p/6647274.html