【学习】CommonJS规范和实现

2024-06-07 15:32
文章标签 实现 学习 规范 commonjs

本文主要是介绍【学习】CommonJS规范和实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面

一言以蔽:CommonJS是服务器端模块的规范,Node.js采用了这个规范。

commonJS简介

根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象。

举个例子 example.js

console.log("evaluating example.js");
var invisible = function () {console.log("invisible");
}
exports.message = "hi";
exports.say = function () {console.log(message);
}

我们可以通过 require 加载这个模块

var example = require('./example.js');

这时,变量example就对应模块中的exports对象,于是就可以通过这个变量,使用模块提供的各个方法。

{message: "hi",say: [Function]
}

require方法默认读取js文件,所以可以省略js后缀名。

var example = require('./example');

注意 js文件名前面需要加上路径,可以是相对路径(相对于使用require方法的文件),也可以是绝对路径。如果省略路径,node.js会认为,你要加载一个核心模块,或者已经安装在本地 node_modules 目录中的模块。如果加载的是一个目录,node.js会首先寻找该目录中的 package.json 文件,加载该文件 main 属性提到的模块,否则就寻找该目录下的 index.js 文件。

【例】最简单的模块

模块 addition.js

exports.do = function(a, b){ return a + b };

上面的语句定义了一个加法模块,做法就是在exports对象上定义一个do方法,那就是供外部调用的方法。使用的时候,只要用require函数调用即可。

var add = require('./addition');
add.do(1,2);   // 输出3

【例】稍复杂些的例子

模块 foobar.js

function foobar(){this.foo = function(){console.log('Hello foo');}this.bar = function(){console.log('Hello bar');}
}
exports.foobar = foobar;

调用该模块的方法如下:

var foobar = require('./foobar').foobar,test   = new foobar();
test.bar(); // 输出 'Hello bar'

有时,不需要exports返回一个对象,只需要它返回一个函数。这时,就要写成module.exports

module.exports = function () {console.log("hello world")
}

AMD规范与CommonJS规范的兼容性

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

AMD规范使用define方法定义模块(最典型的就是requireJS了)

define(['package/lib'], function(lib){function foo(){lib.log('hello world!');} return {foo: foo};
});

当然,AMD规范允许输出的模块兼容CommonJS规范,这时define方法需要写成下面这样:

define(function( require, exports, module )var someModule = require( "someModule" );var anotherModule = require( "anotherModule" );    someModule.doTehAwesome();anotherModule.doMoarAwesome();exports.asplode = function() {someModule.doTehAwesome();anotherModule.doMoarAwesome();};
});

package.json定义

根据commonJS规范,每个nodeJS模块都必须有个package.json文件,也方便分享到npm社区。

name

必须字段,在package.json中最重要的就是name和version字段。他们都是必须的,如果没有就无法install。name和version一起组成的标识在假设中是唯一的。改变包应该同时改变version。
name是这个东西的名字。注意:
1、不要把node或者js放在名字中。因为你写了package.json它就被假定成为了js,不过你可以用”engine”字段指定一个引擎(见后文)。
2、这个名字会作为在URL的一部分、命令行的参数或者文件夹的名字。任何non-url-safe的字符都是不能用的。
3、这个名字可能会作为参数被传入require(),所以它应该比较短,但也要意义清晰。
4、在取名字之前,你最好去 npm registry 查看一下这个名字是否已经被使用了。

version

必须字段,在package.json中最重要的就是nameversion字段。他们都是必须的,如果没有就无法installnameversion一起组成的标识在假设中是唯一的。改变包应该同时改变version。

version必须能被 node-semver解析,它被包在npm的依赖中。(要自己用可以执行npm install semver)

description

可选字段,模块描述,必须是字符串。npm search的时候会用到。

keywords

可选字段,放简介,字符串。方便屌丝们在 npm search中搜索。

homepage

可选字段,项目官网的url。

注意 这和“url”不一样。如果你放一个“url”字段,registry会以为是一个跳转到你发布在其他地方的地址,然后喊你滚粗。 嗯,滚粗,没开玩笑。

bugs

可选字段,你项目的提交问题的url和(或)邮件地址。这对遇到问题的屌丝很有帮助。
差不多长这样:

{ "url" : "http://github.com/owner/project/issues","email" : "project@hostname.com"
}

你可以指定一个或者指定两个。如果你只想提供一个url,那就不用对象了,字符串就行。如果提供了url,它会被npm bugs命令使用。

License

可选字段,你应该要指定一个许可证,让人知道使用的权利和限制的。
最简单的方法是,假如你用一个像BSD或者MIT这样通用的许可证,就只需要指定一个许可证的名字,像这样:

{ "license" : "BSD" }

如果你有更复杂的许可条件,或者想要提供给更多地细节,可以这样:

"licenses" : [{ "type" : "MyLicense", "url" : "http://github.com/owner/project/path/to/license"}
]

在根目录中提供一个许可证文件也蛮好的。

people fields: author, contributors

都是可选字段。author是一个人。contributors是一堆人的数组。person是一个有name字段,可选的有url、email字段的对象,像这样:

{ "name" : "Barney Rubble","email" : "b@rubble.com","url" : "http://barnyrubble.tumblr.com/"
}

或者可以把所有的东西都放到一个字符串里,npm会给你解析:

"Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)

email和url在两种形式中都是可选的。也可以在你的npm用户信息中设置一个顶级的maintainers字段。

files

可选字段,files是一个包含项目中的文件的数组。如果命名了一个文件夹,那也会包含文件夹中的文件。(除非被其他条件忽略了)你也可以提供一个.npmignore文件,让即使被包含在files字段中得文件被留下。其实就像 .gitignore一样。

main

可选字段。main字段配置一个文件名指向模块的入口程序。如果你包的名字叫foo,然后用require(“foo”),main配置的模块的exports对象会被返回。这应该是一个相对于根目录的文件路径。对于大多数模块,它是非常有意义的,其他的都没啥。

bin

可选字段。很多的包都会有执行文件需要安装到PATH中去。这个字段对应的是一个Map,每个元素对应一个{ 命令名:文件名 }。

{ "bin" : { "npm" : "./cli.js" } }

directories

用于指示包的目录结构

directories.lib

指示库文件的位置。

directories.bin

和前面的bin是一样的,但如果前面已经有bin,那么这个就无效。除了以上两个,还有Directories.doc& Directories.man & Directories.example。

repository

可选字段。用于指示代码存放的位置。

"repository" :{ "type" : "git","url" : "http://github.com/npm/npm.git"}"repository" :{ "type" : "svn","url" : "http://v8.googlecode.com/svn/trunk/"}

scripts

可选字段,object。Key是生命周期事件名,value是在事件点要跑的命令。参考npm-scripts。

config

可选字段,object。Config对象中的值在Scripts的整个周期中皆可用,专门用于给Scripts提供配置参数。

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",}
}

版本格式可以是下面任一种:

version 完全匹配>version 大于这个版本>=version大于或等于这个版本<version<=version~version 非常接近这个版本^version 与当前版本兼容1.2.x X代表任意数字,因此1.2.1, 1.2.3等都可以http://... Unix系统下使用的tarball的URL。* 任何版本都可以""任何版本都可以version1 - version2  等价于 >=version1 <=version2.range1 || range2 满足任意一个即可git... Git地址user/repo

devDependencies

可选字段。如果只需要下载使用某些模块,而不下载这些模块的测试和文档框架,放在这个下面比较不错。

peerDependencies

可选字段。兼容性依赖。如果你的包是插件,适合这种方式。

bundledDependencies

可选字段。发布包时同时打包的其他依赖。

optionalDependencies

可选字段。如果你想在某些依赖即使没有找到,或则安装失败的情况下,npm都继续执行。那么这些依赖适合放在这里。

engines

可选字段。既可以指定node版本:

{ "engines" : {"node" : ">=0.10.3 <0.12" } }

也可以指定npm版本:

{ "engines" : {"npm" : "~1.0.20" } }

engineStrick

可选字段,布尔值。如果你肯定你的程序只能在制定的engine上运行,设置为true。

os

可选字段。指定模块可以在什么操作系统上运行:

"os" : [ "darwin","linux" ]
"os" : [ "!win32" ]

cpu

可选字段。指定CPU型号。

"cpu" : [ "x64","ia32" ]
"cpu" : [ "!arm","!mips" ]

preferGlobal

可选字段,布尔值。如果你的包是个命令行应用程序,需要全局安装,就可以设为true。

private

可选字段,布尔值。如果private为true,npm会拒绝发布。这可以防止私有repositories不小心被发布出去。

publishConfig

可选字段。发布时使用的配置值放这。

默认值

"scripts":{"start": "node server.js"}

如果你的包里有server.js文件,npm默认将执行: node server.js.

"scripts":{"preinstall":"node-gyp rebuild"}

如果包里有binding.gyp,npm默认在preinstall命令时,使用node-gyp做编译。

参考资料

@参考 《CommonJS规范》
@参考 《Specifics of npm’s package.json handling》
@参考 《package.json 字段全解析》

这篇关于【学习】CommonJS规范和实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1039570

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、