什么是Node.js的模块(Module)?
在Node.js中,模块是一个库或框架,也是一个Node.js项目。Node.js项目遵循模块化的架构,当我们创建了一个Node.js项目,意味着创建了一个模块,这个模块的描述文件,被称为package.json ——
【长城_changcheng】一般package.json放置在项目根目录下,其基本结构如下图所示:package.json 结构图
属性介绍
属性介绍属性介绍description
description字符串。用来描述当前项目的大致功能。name
name此项目包的名称。在不确定自己的包名能否使用之前,请先npm registry 一下,看看当前你喜欢的包名是否已经被占用。version
version当前项目包的版本号。每一次项目改动时,在即将发布时,都要同步的去更改项目的版本号。一般格式为:x.y.z。意思是:大版本.中版本.小版本keywords
keywords放简介,字符串。方便屌丝们在 npm search中搜索homepage
homepage项目官网的urlbugs
bugs你项目的提交问题的url和(或)邮件地址。这对遇到问题的屌丝很有帮助。
{ "url" : "http://github.com/owner/project/issues" , "email" : "project@hostname.com" }
{ "url" : "http://github.com/owner/project/issues" , "email" : "project@hostname.com" }你可以指定一个或者指定两个。如果你只想提供一个url,那就不用对象了,字符串就行。如果提供了url,它会被npm bugs命令使用。license
license你应该要指定一个许可证,让人知道使用的权利和限制的。最简单的方法是,假如你用一个像BSD或者MIT这样通用的许可证,就只需要指定一个许可证的名字,像这样:
{ "license" : "BSD" }
{ "license" : "BSD" }author
author项目作者。可以指定name,email,url字段信息。也可以单独使用字符串来表示。
{“ author ”: { "name" : "Barney Rubble" , "email" : "b@rubble.com" , "url" : "http://barnyrubble.tumblr.com/" } }
{“ author ”: { "name" : "Barney Rubble" , "email" : "b@rubble.com" , "url" : "http://barnyrubble.tumblr.com/" } }contributors
contributors项目相关贡献者。是数组。用于罗列对应的贡献人。可以是单独的字符串,也可以分别指定name,email,url等属性。
{"contributors ":[ { "name" : "Barney Rubble" , "email" : "b@rubble.com" , "url" : "http://barnyrubble.tumblr.com/" } ]}
{"contributors ":[ { "name" : "Barney Rubble" , "email" : "b@rubble.com" , "url" : "http://barnyrubble.tumblr.com/" } ]}files
filesfiles是一个包含项目中的文件的数组。如果命名了一个文件夹,那也会包含文件夹中的文件。(除非被其他条件忽略了)你也可以提供一个.npmignore文件,让即使被包含在files字段中得文件被留下。其实就像.gitignore一样。
{ "files": [ "bin/", "templates/", "test/" ]}
{ "files": [ "bin/", "templates/", "test/" ]}main
main
main字段是一个模块ID,它是一个指向你程序的主要项目。就是说,如果你包的名字叫foo,然后用户安装它,然后require("foo"),然后你的main模块的exports对象会被返回。这应该是一个相对于根目录的模块ID。对于大多数模块,它是非常有意义的,其他的都没啥。
{ "main": "bin/index.js"}
{ "main": "bin/index.js"}bin
bin很多包都有一个或多个可执行的文件希望被放到PATH中。(实际上,就是这个功能让npm可执行的)。要用这个功能,给package.json中的bin字段一个命令名到文件位置的map。初始化的时候npm会将他链接到prefix/bin(全局初始化)或者./node_modules/.bin/(本地初始化)。
{ "bin" : { "npm" : "./cli.js" } }
{ "bin" : { "npm" : "./cli.js" } }当你初始化npm,它会创建一个符号链接到cli.js脚本到/usr/local/bin/npm。如果你只有一个可执行文件,并且名字和包名一样。那么你可以只用一个字符串,比如
{ "name": "my-program" , "version": "1.2.5" , "bin": "./path/to/program" }
// 等价于
{ "name": "my-program" , "version": "1.2.5" , "bin" : { "my-program" : "./path/to/program" } }
{ "name": "my-program" , "version": "1.2.5" , "bin": "./path/to/program" }// 等价于{ "name": "my-program" , "version": "1.2.5" , "bin" : { "my-program" : "./path/to/program" } }man
man指定一个单一的文件或者一个文件数组供man程序使用。如果只提供一个单一的文件,那么它初始化后就是man 的结果,而不管实际的文件名是神马,比如:
{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : "./man/doc.1" }
{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : "./man/doc.1" }这样man foo就可以用到./man/doc.1文件了。如果文件名不是以包名开头,那么它会被冠以前缀,下面的:
{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : [ "./man/foo.1", "./man/bar.1" ] }
{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : [ "./man/foo.1", "./man/bar.1" ] }会为man foo和man foo-bar创建文件。man文件需要以数字结束,然后可选地压缩后以.gz为后缀。
{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : [ "./man/foo.1", "./man/foo.2" ] }
{ "name" : "foo" , "version" : "1.2.3" , "description" : "A packaged foo fooer for fooing foos" , "main" : "foo.js" , "man" : [ "./man/foo.1", "./man/foo.2" ] }会为man foo和man 2 foo创建。repository
repository指定你的代码存放的地方。这个对希望贡献的人有帮助。如果git仓库在github上,那么npm docs命令能找到你。scripts
scripts“scripts”是一个由脚本命令组成的hash对象,他们在包不同的生命周期中被执行。key是生命周期事件,value是要运行的命令。config
config"config" hash可以用来配置用于包脚本中的跨版本参数。在实例中,如果一个包有下面的配置
{ "name" : "foo" , "config" : { "port" : "8080" } }
{ "name" : "foo" , "config" : { "port" : "8080" } }然后有一个“start”命令引用了npm_package_config_port环境变量,用户可以通过npm config set foo:port 8001来重写他。dependencies
dependencies依赖是给一组包名指定版本范围的一个hash。这个版本范围是一个由一个或多个空格分隔的字符串。依赖还可以用tarball或者git URL。请不要将测试或过渡性的依赖放在dependencies。对于引用包的版本号格式,以下都是合法的:
{ "dependencies" :
{ "foo" : "1.0.0 - 2.9999.9999"
, "bar" : ">=1.0.2 <2.1.2"
, "baz" : ">1.0.2 <=2.3.4"
, "boo" : "2.0.1"
, "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
, "asd" : "http://asdf.com/asdf.tar.gz"
, "til" : "~1.2"
, "elf" : "~1.2.3"
, "two" : "2.x"
, "thr" : "3.3.x"
,"vue":"*", "element-ui":"" } }
{ "dependencies" :
{ "foo" : "1.0.0 - 2.9999.9999"
, "bar" : ">=1.0.2 <2.1.2"
, "baz" : ">1.0.2 <=2.3.4"
, "boo" : "2.0.1"
, "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
, "asd" : "http://asdf.com/asdf.tar.gz"
, "til" : "~1.2"
, "elf" : "~1.2.3"
, "two" : "2.x"
, "thr" : "3.3.x"
,"vue":"*", "element-ui":"" } }devDependencies
devDependencies
如果有人要用你的模块,但他们可能不需要你开发所使用的外部测试或者文档框架。在这种情况下,最好将这些附属的项目列在devDependencies中。这些东西会在根目录执行npm link或者npm install的时候初始化,并可以像其他npm配置参数一样管理。peerDependencies
peerDependencies你的模块可能要暴露一个特定的接口,并由host文档来预期和指定。比如:
{
"name": "tea-latte",
"version": "1.3.5"
"peerDependencies": {
"tea": "2.x"
} }
{
"name": "tea-latte",
"version": "1.3.5"
"peerDependencies": {
"tea": "2.x"
} }这能保证你的package可以只和tea的2.x版本一起初始化。试图初始化另一个有会冲突的依赖的插件将导致一个错误。因此,确保你的插件的需求约束越弱越好,而不要去把它锁定到一个特定的版本。此属性尽量避免使用bundledDependencies
bundledDependencies一组包名,他们会在发布的时候被打包进去engines
engines
指定项目工作的环境。除非用户设置engine-strict标记,这个字段只是建议值。
{ "engines" : { "node" : ">=0.10.3 <0.12", "npm" : "~1.0.20" } }
{ "engines" : { "node" : ">=0.10.3 <0.12", "npm" : "~1.0.20" } }engineStrict
engineStrict如果你确定你的模块一定不会运行在你指定版本之外的node或者npm上,你可以在package.json文件中设置"engineStrict":true。它会重写用户的engine-strict设置。除非你非常非常确定,否则不要这样做。如果你的engines hash过度地限制,很可能轻易让自己陷入窘境。慎重地考虑这个选择。如果大家滥用它,它会再以后的npm版本中被删除。os
os可以指定你的模块要运行在哪些操作系统中
"os" : [ "darwin", "linux" ]
"os" : [ "darwin", "linux" ]你也可以用黑名单代替白名单,在名字前面加上“!”就可以了:
"os" : [ "!win32" ]
"os" : [ "!win32" ]操作系统用process.platform来探测。虽然没有很好地理由,但它是同时支持黑名单和白名单的。cpu
cpu如果你的代码只能运行在特定的cpu架构下,你可以指定一个
"cpu" : [ "x64", "ia32" ]
"cpu" : [ "x64", "ia32" ]就像os选项,你也可以黑一个架构:
"cpu" : [ "!arm", "!mips" ]
"cpu" : [ "!arm", "!mips" ]cpu架构用process.arch探测。preferGlobal
preferGlobal如果包主要是需要全局安装的命令行程序,就设置它为true来提供一个warning给只在局部安装的人。它不会真正的防止用户在局部安装,但如果它没有按预期工作它会帮助防止产生误会。
{" preferGlobal ":true}
{" preferGlobal ":true}private
private如果你设置"private": true,npm就不会发布它。这是一个防止意外发布私有库的方式。如果你要确定给定的包是只发布在特定registry(如内部registry)的,用publishConfighash的描述来重写registry的publish-time配置参数。publishConfig
publishConfig这是一个在publish-time使用的配置集合。当你想设置tag或者registry的时候它非常有用,所以你可以确定一个给定的包没有打上“lastest”的tag或者被默认发布到全局的公开registry。任何配置都可以被重写,但当然可能只有“tag”和“registry”与发布的意图有关。