记npm包开发全过程
概述
- 为什么开发npm包?
- 如何开发?
- 如何写单元测试?
- package.json
- 如何发布模块?
- 如何使用?
为什么开发npm模块?
NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。
npm官网
如何开发?
接下来由带领大家完成一个简单的npm包,功能:读写文件
是不是很复杂呢???
npm init
创建基础目录或文件
- mkdir tests lib
- touch index.js README.md
.
├── README.md //说明文档
├── index.js //主入口
├── lib //功能文件
├── package.json //包信息
└── tests //测试用例
开发功能
- cd lib/
- touch file.js utils.js
utils.js文件内容
var Promise = require("es6-promise").Promise;
/**
* 提供各种工具方法
* @type {{*}}
*/
module.exports = {
/**
* 获取Defer对象
* @return {[type]} [description]
*/
getDefer: function (){
var deferred = {};
deferred.promise = new Promise(function(resolve, reject){
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
},
/**
* promise when方法
* @param promises promise数组
* @returns {[type]} [description]
*/
when: function(promises) {
var deffered = this.getDefer();
Promise.all(promises).then(function(data) {
deffered.resolve(data);
}, function(err) {
deffered.reject(err);
});
return deffered.promise;
}
}
注:npm install es6-promise --save --verbos
file.js内容
var fs = require('fs');
var path = require('path');
var utils = require('./utils.js');
module.exports = {
/**
* 写文件
* @param file 文件路径
* @param data 数据
*/
writeFile: function(file, data) {
var deferred = utils.getDefer();
file = path.resolve(file);
fs.writeFile(file, data, 'utf-8', function(err) {
if(err){
deferred.reject(err);
}else {
deferred.resolve(true);
}
});
return deferred.promise;
},
/**
* 读文件
* @param file 文件路径
*/
readFile: function(file) {
var deferred = utils.getDefer();
file = path.resolve(file);
fs.readFile(file, 'utf-8', function(err, data) {
if(err){
deferred.reject(err);
}else {
deferred.resolve(data);
}
});
return deferred.promise;
}
};
主函数index.js内容
var file = require('./lib/file.js');
module.exports = {
writeFile: file.writeFile,
readFile: file.readFile
}
注:主要是在被使用时暴露的接口
功能开发基本完毕
此时我们并不知道我们实现的功能是否可行、可用
我们需要进行单元测试
如何写单元测试?
单元测试原则
- 对全新的代码或修改过的代码进行单元测试
- 单元测试根据单元测试计划和方案进行,排除测试的随意性
- 必须保证单元测试计划、单元测试方案、单元测试用例等经过评婶
- 当测试用例的测试结果与预期结果不一致时,单元测试的执行人员需如实记录实际的测试结果
- 只有当测试计划中的结束标准达到时,单元测试才能结束
- 对被测试单元需达到的一定的代码覆盖率要求
书写测试用例
npm install -g mocha --verbos
npm install --save-dev chai --verbos
测试utils.js
var utils = require('../lib/utils.js');
var expect = require('chai').expect;
describe('utils:工具方法测试', function() {
//defer对象测试
describe('utils.getDefer', function() {
var deferred = utils.getDefer();
it('defer成功', function() {
deferred.resolve(true);
return deferred.promise.then(function(data) {
expect(data).to.be.equal(true);
});
});
it('defer失败', function() {
deferred.reject(true);
return deferred.promise.then(function() {}, function(data) {
expect(data).to.be.equal(true);
});
});
});
//when测试
describe('utils.when', function() {
var deferred1 = utils.getDefer();
var deferred2 = utils.getDefer();
var deferred3 = utils.getDefer();
var deferred4 = utils.getDefer();
it('when成功', function() {
deferred1.resolve(true);
deferred2.resolve(true);
return utils.when([deferred1.promise, deferred2.promise]).then(function(data) {
expect(data).to.be.deep.equal([true, true]);
});
});
it('when失败', function() {
deferred3.resolve(true);
deferred4.reject(false);
return utils.when([deferred3.promise, deferred4.promise]).then(function() {},function(data) {
expect(data).to.be.equal(false);
});
});
});
});
注:mocha tests/utils.js
测试file.js
var file = require('../lib/file.js');
var expect = require('chai').expect;
describe('file:功能测试', function() {
//writeFile功能测试
describe('file.writeFile', function() {
it('写文件:成功', function() {
var path = 'README.md';
var data = '说明文档';
return file.writeFile(path, data).then(function(flag) {
expect(flag).to.be.equal(true);
});
});
it('写文件:失败', function() {
var path = 'write-test.txt';
var data = '我是写入的数据';
return file.writeFile(path, data).then(function(){}, function(err) {
expect(true).to.be.equal(true);
});
});
});
//readFile功能测试
describe('file.readFile功能测试', function() {
it('读文件:成功', function() {
var path = 'README.md';
return file.readFile(path).then(function(data) {
expect(data).to.be.equal('说明文档');
});
});
it('读文件:失败', function() {
var path = 'write-test.txt';
return file.readFile(path).then(function(){}, function(err) {
expect(true).to.be.equal(true);
});
});
});
});
注:mocha tests/file.js
持续测试...
一遍遍测试,查看测试结果,都要输入命令很无语~~
新技能:mocha --watch tests
还能做什么?
通过上面测试感觉好了不少,有没有更好的展现形式呢?
- 测试结果生成html报表(mocha --reporter mochawesome tests)
- 能不能看看测试覆盖率呢?(istanbul cover ./node_modules/mocha/bin/_mocha -- -t 2000 --recursive -R spec tests/)
注:
npm install --save-dev mochawesome --verbos
npm install --save-dev mocha --verbos
sudo npm install -g istanbul --verbos
package.json
经过上述操作之后我们发现,package.json发生了变化
{
"name": "read-write-file",
"version": "1.0.0",
"description": "简单的读写文件",
"main": "index.js",
"scripts": {
"test": "mocha --reporter spec --timeout 2000 --recursive tests/"
},
"keywords": [
"read",
"write"
],
"author": "黑MAO",
"license": "MIT",
"dependencies": {
"es6-promise": "^3.0.2"
},
"devDependencies": {
"chai": "^3.4.1",
"istanbul": "^0.4.1",
"mocha": "^2.3.4",
"mochawesome": "^1.2.1"
}
}
回顾
发现不爽的地方,要执行一对命令,还有一些参数特别长,不容易记忆
该怎么办呢?
scripts脚本
npm 提供简单的执行脚本,可以通过npm run * 执行scripts写的简单脚本
于是乎~~
常用脚本
"scripts": {
"watch": "mocha --watch tests/",
"test": "mocha --reporter spec --timeout 2000 --recursive tests/",
"test-cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -t 2000 --recursive -R spec tests/",
"test-html": "mocha --reporter mochawesome tests/"
},
命令行
命令行模式又是怎么做的呢?
"bin": {
"writeFile": "./bin/writeFile.js",
"readFile": "./bin/readFile.js"
},
注:
开发模式可以使用:
sudo npm link(添加命令行模式)
sudo npm unlink(取消命令行模式)
截至现在,我们的一个npm包就开发完成了~
是不是也没有想想中那么复杂呢?
如何发布?
- npm adduser(用户名、密码、邮箱)-- 注册帐号
- npm whoami(查看当前帐号)
- sudo npm publish(发布到npmjs.org)-- 注意:sudo权限
如何使用?
npm install read-write-file
var file = require('read-write-file');
var path = 'test.txt';
var data = '我是测试文本';
file.writeFile(path, data).then(function() {
return file.readFile(path);
}).then(function(txt) {
console.log('测试结果:'+txt);
});
注:sudo install -g read-write-file可以使用命令行形式
终
到目前为止,一个npm包就开发完成了~
参考资料:
- mocha教程 http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
- nodejs教程 http://nqdeng.github.io/7-days-nodejs/
记npm包开发全过程的更多相关文章
- npm包开发与发布
把通用的功能开发成npm包,便用使用和维护,更重要的是可以分享给广大的开发者,是不是很激动人心! 那么,步骤如下: 1.创建项目 创建项目目录,npm init ,根据需要输入配置信息(建完后也可以在 ...
- npm包开发(whale-makelink)
whale-makelink是一个npm工具,是强业务的工具,可以将当前工程目录下的项目文件夹,在README中生成项目的链接地址.Demo. 一.npm init 使用npm init生成packa ...
- 如何开发一个npm包并发布
一.安装nodejs 不多说了,网上教程多得是 二.创建自己的npm包 目录结构 npm-test a.js b.js package.json 开发 为了简单便于理解,就开发一个简单地hello程序 ...
- VS Code项目中通过npm包的方式共享代码片段的方案实现
VS Code项目中通过npm包的方式共享代码片段的方案实现 上周在 "VS Code项目中共享自定义的代码片段方案" 的文章中提到过一个共享代码片段的方案,上周经过调研后并没有发 ...
- [麻雀虽小]记 简易Markdown阅读器 开发全过程
[麻雀虽小]记 简易Markdown阅读器 开发全过程 [TOC] 序言 项目地址: https://github.com/didikee/MDReader 测试文章地址: 2017 Android ...
- 在2018年如何优雅的开发一个typescript语言的npm包?
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由小明plus发表 很多时候,我们可能想要用 typescript 语言来创建一些模块,并提交到 npm 供别人使用, 那么在 2018 ...
- 从零系列--开发npm包(一)
一.目的 主要是纪录和回顾自己开发的一些步骤以及遇到的一些问题和解决方案 二.准备工作 1.IDE 选择 VS Code 2.安装node 环境 (https://nodejs.org/zh-cn/) ...
- 如何开发一个npm包并发布到npm中央仓库
转自: https://liaolongdong.com/2019/01/24/publish-public-npm.html 如何开发一个npm包并发布到npm中央仓库需求背景:平时在项目工作中可能 ...
- 快速开发一个npm包(轮子)
动机 很多人都想写一个自己的轮子,可是开始动手的时候你总会遇到以下问题 一个基本的 js 库应该如何编写 基本的前端项目都要哪些文件 又要怎么打包发布到 npm 上 你的 es6 语法如何才能让别人识 ...
随机推荐
- Swift学习笔记 - 函数与闭包
import Foundation //1.函数的定义与调用//以 func 作为前缀,返回箭头 -> 表示函数的返回类型func sayHello(name: String) -> St ...
- 关键字explicit
今天在<C++ Standard Library>中看到 explicit 的作用,在这里做一下笔记,以备下次再次忘记该关键字的作用. By using the keyword expli ...
- java集合框架01
List 接口存储一组不唯一(可以重复),有序(插入顺序)的对象 01. ArrayList实现了长度可变的数组,在内存中分配连续的空间.遍历元素和随机访问元素的效率比较高 通过看ArrayList的 ...
- codevs 2241 排序二叉树
/* WTF 写了好久了 开始的时候题目读错了 建图建错了 搜索写的也不好 感觉会T 总之 第一次写的很low 贴一下吧 */ #include<iostream> #include< ...
- JY01-KX-01
复习: 1.a标签跳转 <p id="地址"></p> <a href="#地址"></a> 预习: 1.out ...
- PHP 开发工具【2】
关于PHP的开发工具其实网站上可以搜索到非常多,对于初学者来说,太多的选择反而不知道怎么去选. 本文是基于window平台上,针对PHP初学者定制了一套非常好用的开发工具. PHP开发工具其实包括以下 ...
- java swing 音乐播放器-乐乐音乐
乐乐音乐1.0(本地版) 乐乐音乐是基于musique 开源播放器开发的java swing音乐播放器,实现了mp3.flac.ape.wav等多种音频格式的播放和ksc歌词的解析.制作和显示. 完成 ...
- java学习——集合框架(Collection,List,Set)
集合类的由来: 对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定,就使用集合容器进行存储. 集合特点:1,用于存储对象的容器.2,集合的长度是可变的.3,集合中不可以存储基本数据类型值. ...
- Class类相关
Class类是java.lang包中的类,该类的实例可以帮助程序创建其他类的实例或者取得其他类的对象的内部信息 使用class类获得一个类相关的class类(注意得到的是class类,不是相关的类) ...
- 【C++学习之路】派生类的构造函数(三)
三.多层继承的派生类 1.多层继承的派生类只需在构造函数的初始化列表中写出直接基类的构造函数即可 class student { public: student(int n, string nam) ...