Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(转)Node.js 进阶-你应该知道的 npm 知识都在这! #82

Open
kekobin opened this issue Jul 7, 2020 · 0 comments
Open

Comments

@kekobin
Copy link
Owner

kekobin commented Jul 7, 2020

image

npm init

npm init --yes

可以省略手动回车,直接生成一个package.json文件。

dependenices

如果没有指定版本,直接写一个包的名字,则安装当前npm仓库中这个包的最新版本。如果要指定版本的,可以把版本号写在包名后面,比如npm i [email protected] -S。

  • 从npm 5.x开始,可以不用手动添加-S/--save指令,直接执行npm i packageName把依赖包添加到dependencies中去。

devDependenices

有一些包有可能你只是在开发环境中用到,例如你用于检测代码规范的 eslint ,用于进行测试的 jest ,用户使用你的包时即使不安装这些依赖也可以正常运行,反而安装他们会耗费更多的时间和资源,所以你可以把这些依赖添加到 devDependencies 中,这些依赖照样会在你本地进行 npm install 时被安装和管理,但是不会被安装到生产环境

二者简单对比

  • -D 会添加到 devDependencies 里面
  • -S 会添加到 dependencies--save-dev 也会添加到 devDependencies--save 会添加到 dependencies
  • 从npm 5.x开始,如果什么参数都不带,那么默认添加到 dependencies 中

bin

 "bin": {
    "vm2": "./bin/vm2"
  },

bin 字段指定了各个内部命令对应的可执行文件的位置。如果全局安装模块报,npm 会使用符号链接把可执行文件链接到 /usr/local/bin,如果项目中安装,会链接到 ./node_modules/.bin/。
上面的这种当你的包安装到全局时:npm 会在 /usr/local/bin 下创建一个以 vm2 为名字的软链接,指向全局安装下来的 vm2 包下面的 "./bin/index.js"。这时你在命令行执行 vm2 则会调用链接到的这个 js 文件。

main

一个常用的npm包

{
  "main": "lib/index.js",
}

main 属性指定程序的主入口文件,其他项目在引用这个 npm 包时,实际上引入的是 lib/index 中暴露出去的模块。

npm script

什么是 npm script 脚本?

在生成的 package.json 文件中,有一个 scripts 对象,在这个对象中,npm 允许使用 scripts 字段定义脚本命令。

"scripts": {
    "test": "test.js"
    "build": "tsc",
  },

scripts 对象中每一个属性,对应一段脚本。比如,test 命令对应的脚本是 node test.js。

命令行下使用 npm run 命令,就可以执行这段脚本。

查看当前项目的所有 npm 脚本命令,可以使用不带任何参数的npm run命令。

原理

我们每次在运行 scripts 中的一个属性时候(npm run),**实际系统都会自动新建一个shell(一般是Bash),在这个shell里面执行指定的脚本命令。因此 凡是能在 shell 中允许的脚本,都可以写在npm scripts中。

  • 特别的点,npm run 新建的 shell,会在当前目录的 node_modules/.bin 子目录加入到 PATH 变量,执行结束后,再将 PATH 变量恢复原样。
    也就是说,当前项目目录 node——modules/.bin 子目录中所有的脚本,都可以直接用脚本名称调用,不需要增加路径.(简单总结:通过 npm 启动的脚本,会默认把 node_modules/.bin 加到 PATH 环境变量中。)

例子

当前项目的依赖里面有 Mocha,只要直接写 mocha test 就可以了。

"test": "mocha test"

而不用写成下面这样。

"test": "./node_modules/.bin/mocha test"

这里有的小伙伴可能会有疑问,node_modules目录下的.bin文件是哪里来的?我之前也有这样的疑问,打开了一个 .bin/tsc,里面的内容是这样的

#!/usr/bin/env node
require('../lib/tsc.js')

npm install 安装的某个模块,如果模块在 package.json 中配置了 bin 属性,在安装时候会自动软链接到 node_modules/.bin 中,举个例子: 如 mocha 源码 配置了:

{
    "name":"mocha",
    "bin":{
        "mocha":"./bin/mocha"
    }
}

脚本默认值

正常情况下,npm 脚本是用户自己定义。但是 npm 本身对两个脚本提供了默认值,这两个脚本不用在 script 属性中定义,可以直接使用

"start": "node server.js"
"install": "node-gyp rebuild"
  • npm run start 的默认值是 node server.js ,前提是根目录下有 server.js 这个脚本
  • npm run install 的默认值是 node-gyp rebuild,前提是根目录下有 binding.gyp 文件

-node-gyp:node 下的 gyp。
npm 为了方便直接源码分发,用户装的时候需要自己进下编译,我们在开发 node 程序中需要调用一些其他语言编写的工具甚至 dll,这时候需要先编译下其他语言,否则会出现跨平台的问题。node-gyp 是用来编译原生 C++ 模块的,也可以编写自己写的 C++文件,node-gyp 在较新的 Node 版本中都是自带的,而且是最先版本。

  • gyp 文件:当 Node.js 项目中有需要和 C++ 交互的需求时,项目的根目需要创建 binging.gyp 文件,每个.gyp文件都描述了如何去构建项目,gyp文件的语法是 Python数据格式(Json格式),配置中数据是键-值对的形式。

钩子(生命周期)

好多语言或者框架我们学的时候都会考虑到生命周期,其实 package.json 中的 script 也是有生命周期的。
npm 脚本有两个钩子,pre 和 post,当我们执行start脚本时候,start 的钩子就是 prestart 和 poststart。
当我们执行 npm run start 的时候,npm 会自动按照下面的顺序执行

npm run prestart && npm run start && npm run poststart

那这个钩子有什么用呢,在实际开发中,我们可以做一些准备或者清理工作,下面是个例子(引用的阮一峰老师文章中的例子)

"clean": "rimraf ./dist && mkdir dist",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack"

env 环境变量

我们在执行 npm run 脚本时候, npm 会设置一些特殊的env环境变量。其中package.json中的所有字段,都会被设置为以npm_package_开头的环境变量。看个简单的例子

{
  "name": "npm-demo",
  "version": "1.0.0",
  "script": {
    "build": "webpack --mode=production"
  },
  "files": ["src"]
}

可以得到 npm_package_name、npm_package_version、npm_package_script_build、npm_package_files_0等变量。注意上面 package.json 中对象和数组中每个字段都会有对应的环境变量。
同时,npm 相关的所有配置也会被设置为以npm_config_开头的环境变量。
此外,还会设置一个比较特殊的环境变量npm_lifecycle_event,表示正在运行的脚本名称。比如执行npm run serve 的时候,process.env.npm_lifecycle_event值为serve,通过判断这个变量,可以将一个脚本使用在不同的npm scripts中。这里还要提一下上面说的钩子,npm_lifecycle_event可以和钩子配合使用,利用这个变量,在同一个脚本文件里面,为不同的 npm scripts 命令编写代码。请看下面的例子。

const TARGET = process.env.npm_lifecycle_event;

if (TARGET === 'service') {
  console.log(`Running the service task!`);
}

if (TARGET === 'preservice') {
  console.log(`Running the preservice task!`);
}

if (TARGET === 'postservice') {
  console.log(`Running the postservice task!`);
}

环境变量常用小技巧

1.env 命令可以列出所有环境变量

npm run env

2.在shell脚本中输出环境变量

echo PATH

3.在 shell 脚本设置环境变量

echo PATH = /usr/local/lib

执行顺序

npm 脚本执行多任务分为两种情况

  • 并行任务(同时的平行执行),使用&符号
$ npm run script1.js & npm run script2.js
  • 串行任务(前一个任务成功,才执行下一个任务),使用 && 符号
$ npm run script1.js && npm run script2.js

npm 配置

npm 的配置操作可以帮助我们预先设定好npm对项目的行为动作,也可以让我们预先定义好一些配置项以供项目中使用。所以了解npm的配置机制也是很有必要。

npm config

npm cli 提供了 npm config 命令进行 npm 相关配置,通过 npm config ls -l 可查看 npm 的所有配置,包括默认配置。npm 文档页为每个配置项提供了详细的说明 https://docs.npmjs.com/misc/config .
修改配置的命令为 npm config set , 我们使用相关的常见重要配置:

最常见的一个操作是 npm 太慢,设置淘宝镜像

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

npmrc 文件

除了使用 CLI 的 npm config 命令显示更改 npm 配置,还可以通过 npmrc 文件直接修改配置。
这样的 npmrc 文件优先级由高到低包括:

  • 工程内配置文件: /path/to/my/project/.npmrc
  • 用户级配置文件: ~/.npmrc
  • 全局配置文件: $PREFIX/etc/npmrc (即npm config get globalconfig 输出的路径)
  • npm内置配置文件:/path/to/npm/npmrc

npm 包发布

规范的 npm 模块目录
一个 node.js 模块是基于 CommonJS 模块化规范实现的,严格按照 CommonJS 规范,模块目录下除了必须包含包描述文件 - package.json 以外,还需要包含以下目录:

  • bin:存放可执行二进制文件的目录
  • lib:存放js代码的目录
  • doc:存放文档的目录
  • test:存放单元测试用例代码的目录

如何发布自己的 npm 包

1.先去 npm 注册个账号,然后在命令行使用

npm adduser #根据提示输入用户名密码即可

2.用命令发布你的包

  • 在推送之前,可以通过配置一个 .npmignore 文件来排除一些文件, 防止大量的垃圾文件推送到 npm, 规则上和你用的 .gitignore 是一样的。.gitignore 文件也可以充当 .npmignore 文件
npm publish

关于 npm 包的更新

更新 npm 包也是使用 npm publish 命令发布,不过必须更改 npm 包的版本号,即 package.json 的 version 字段,否则会报错,同时我们应该遵 Semver(语义化版本号) 规范,npm 提供了 npm version 给我们升级版本

# 升级补丁版本号
$ npm version patch

# 升级小版本号
$ npm version minor

# 升级大版本号
$ npm version major

本地开发的 npm 包如何调试

在本地开发的模块包的时候,可以使用 npm link 调试,将模块链接到对应的运行项目中去,方便地对模块进行调试和测试。具体使用步骤如下

  • 假如我的项目是 koalaNpmStudy,假如我的 npm 模块包名称是 npm-ikoala

  • 进入到 模块包 npm-ikoala 目录中,执行 npm link

  • 在自己的项目 koalaNpmStudy 中创建连接执行 npm link npm-ikoala

  • 在自己项目的 node_module 中会看到链接过来的模块包,然后就可以像使用其他的模块包一样使用它了。

  • 调试结束后可以使用 npm unlink 取消关联

  • npm link 主要做了两件事:
    1.为目标 npm 模块创建软链接,将其链接到全局 node 模块安装路径 /usr/local/lib/node_modules/。
    2.为目标 npm 模块的可执行 bin 文件创建软链接,将其链接到全局 node 命令安装路径 /usr/local/bin/。

参考

Node.js 进阶-你应该知道的 npm 知识都在这!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant