编写一个供浏览器端使用的NPM包
此文已由作者吴维伟授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
在编写程序时,总会有一些代码是我们不愿意一遍又一遍重复地去写的,比如一些UI或交互相似组件,或是一些相似的流程或逻辑。以前,面对这样的情况,我会将可以复用的部分抽象出来,做成可以复用的模块,放在专门存放公用模块的文件夹中,便于查找和引用。但是这样只能解决单个项目中公用模块复用的问题,如果你的模块需要被多个项目复用,那么就需要另寻它法了。本文讨论的是通过发布npm包来实现模块复用时有哪些注意事项。
新建一个包
在项目根目录下执行下面的命令,初始化package.json文件。
$ npm init
文件中各字段的含义可以参考官方文档。
其中需要注意的是:
name指定包名,在发布包时包名不能与已有包名重复。在发布前可以通过npm info packageName查看包名是否已存在。
main指定加载包时默认加载的文件。
files指定发布包时需要发布的文件。一般来说,.git, node_modules, test等文件不应该发布到npm仓库中。
dependencies指定需要依赖的第三方包。在安装此包时,这些第三方包也同时会被安装。为了提高包的安装速度,不必要的依赖不要放在dependencies中。
打包
为什么需要打包
业务项目的打包过程中,为了提高打包速度,某些处理过程会过滤第三方包,如babel。而且业务项目中可能没有处理第三方库中某些特性的能力,如第三方包中使用了coffeescript。所以作为一个能被良好复用的第三方包,需要在发布前,对自己的源码进行编译打包。
注意事项
可以选择webpack进行打包。在打包过程中,与业务项目不同的是:
将output.libraryTarget配置为commonjs
业务项目中打包后的文件只需要被执行,并不需要对外导出变量。为了能够以commonjs规范对外导出变量,需要将output.libraryTarget配置为commonjs点击查看如何配置
打包时过滤第三方包
作为一个NPM包,可能会依赖一些第三方包,如React。如果直接进行打包,打包后的文件会包含React的代码。一般依赖这个NPM包的业务项目也会依赖React,所以最终React的代码会被打包两次。所以建议在打包时对第三方包进行过滤,并把用到的第三方包声明在dependencies中,使依赖的第三方包随业务项目一起打包。
点击查看如何过滤第三方包
使用babel-plugin-transform-runtime
我们通常会使用babel来编译代码。在编译的过程中,babel会额外注入一些代码,使编译后的代码有更好的兼容性,如继承,Promise, Map, Set等功能的实现。为了防止这些额外的代码被重复加入,可以在编译时使用babel-plugin-transform-runtime插件,使这些额外的功能从第三方包(babel-runtime)中导入,而不是直接添加实现代码。同时在打包时也要对babel-runtime进行过滤,使babel-runtime随业务项目一起打包。
点击查看如何使用transform-runtime
按需加载
有时一个NPM包会提供很多功能,而依赖它的业务项目只需要其中一部分。这个时候,NPM包需要提供按需加载的功能,即在打包时只会将引用的部分模块打包进来,从而减少打包后文件的体积。
babel-plugin-import的使用
babel-plugin-import插件可以实现按需加载的功能。
{
"plugins": [
["import", {
"libraryName": "abc",
"style": true
}]
]}
上面的代码是babel配置文件的一部分,声明对abc模块使用按需加载的功能。它对下面的一段代码进行编译:
// 从模块中导入var1, var2, var3 3个变量,只使用了var1import {var1, var2, var3} from 'abc'console.log(var1)
编译结果:
import { style as _style } from 'abc/lib/var1/style';import _default from 'abc/lib/var1';
console.log(_default);
编译前,导入整个abc包。编译后,只导入了使用了的var1。babel-plugin-import支持更灵活的配置,点击查看详情。
点击查看如何配置babel
为了使babel-plugin-import能够按需加载我们的NPM包,在打包时需要有一些相应的配置。如上面的abc包,需要对var1, var2, var3等模块分别打包。所以打包后的文件除了abc/index.js外,还需要有abc/lib/var1/index.js, abc/lib/var1/style.js等
测试
对于一个公用模块,最重要的应该是它的稳定性。一个每次升级都可能带来新bug的公用模块并不是我们想要的。相比于业务项目,公用模块提供的功能变化较小,这样单元测试就有了用武之地。想象之中,公用模块的迭代过程是这样的:
明确模块提供的功能,并针对这些功能编写测试用例。
进行功能开发,通过测试用例。
如果需要修复bug或新增功能,针对bug或新功能编写测试用例,通过用例。
如何进行单元测试
断言库
断言库主要用于对数据进行比较,判断其是否与预期相符。对于不满足预期的断言,会抛出一个异常.
assert.equal('a', 'b')如上面的断言会抛出一个异常AssertionError: 'a' == 'b'断言库推荐使用Chai,支持多种风格的断言。
测试框架
测试框架可以对测试用例进行分类管理。每一个测试用例在一个单独的闭包中执行,如果在这个闭包中捕获到异常,则认为这个测试用例没有通过。
// 一个分类describe('type1:', function () { // 一个用例(通过)
it('case 1:', function () {
assert.equal('a', 'a')
}) // 一个用例(未通过)
it('case 2:', function () {
assert.equal('a', 'b')
})
})
测试框架推荐使用mocha
测试执行器
推荐使用karma,它可以集成webpack、 mocha、 chai、 浏览器,对测试代码进行打包,并在浏览器环境下执行测试用例,最后在控制台输出结果。
文档
一个公用模块应该有一个API文档,但是手动维护一个文档的成本过高。所幸现在有一些工具可以根据代码中的注释自动生成API文档,你需要做的只是根据规范添加代码注释。
点击查看注释规范生成网页形式的文档生成markdown形式的文档
网易云免费体验馆,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 一行代码搞定Dubbo接口调用
【推荐】 HBase原理–所有Region切分的细节都在这里了
编写一个供浏览器端使用的NPM包的更多相关文章
- 编写一个 Chrome 浏览器扩展程序
浏览器扩展允许我们编写程序来实现对浏览器元素(书签.导航等)以及对网页元素的交互, 甚至从 web 服务器获取数据,以 Chrome 浏览器扩展为例,扩展文件包括: 一个manifest文件(主文件, ...
- 一个在浏览器端将html 转为pdf 的js 插件 jsPDF
<!DOCTYPE html> <html> <head> <title>test</title> <meta http-equiv= ...
- 从0到1发布一个npm包
从0到1发布一个npm包 author: @TiffanysBear 最近在项目业务中有遇到一些问题,一些通用的方法或者封装的模块在PC.WAP甚至是APP中都需要使用,但是对于业务的PC.WAP.A ...
- Html5浏览器端less应用
之前的一个布局是用rem来做的 我上一段代码 div { margin: 0.833333333rem 0; } /* 去处a标签的下划线*/ a { text-decoration: none; } ...
- Node.js 最早 npm 包 request 将被废弃
相信 Node.js 开发者对 Request 都不会陌生,这是一个 Node.js 模块,以 npm 包的形式提供,是一个简单的 HTTP 客户端,通过它可方便地实现 HTTP 请求. 可以看到,r ...
- SeaJS:一个适用于 Web 浏览器端的模块加载器
什么是SeaJS?SeaJS是一款适用于Web浏览器端的模块加载器,它同时又与Node兼容.在SeaJS的世界里,一个文件就是一个模块,所有模块都遵循CMD(Common Module Definit ...
- 2道acm编程题(2014):1.编写一个浏览器输入输出(hdu acm1088);2.encoding(hdu1020)
//1088(参考博客:http://blog.csdn.net/libin56842/article/details/8950688)//1.编写一个浏览器输入输出(hdu acm1088)://思 ...
- Java基础---Java---网络编程---TCP的传输、客户端和服务端的互访、建立一个文本转换器、编写一个聊天程序
演示TCP的传输的客户端和服务端的互访 需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息. 客户端: 1.建立Socket服务,指定要连接方朵和端口 2.获取Socket流中的输出流,将数 ...
- JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识
JAVA WEB快速入门系列之前的相关文章如下:(文章全部本人[梦在旅途原创],文中内容可能部份图片.代码参照网上资源) 第一篇:JAVA WEB快速入门之环境搭建 第二篇:JAVA WEB快速入门之 ...
随机推荐
- python正则表达式模块re:正则表达式常用字符、常用可选标志位、group与groups、match、search、sub、split,findall、compile、特殊字符转义
本文内容: 正则表达式常用字符. 常用可选标志位. group与groups. match. search. sub. split findall. compile 特殊字符转义 一些现实例子 首发时 ...
- IO事件驱动模型
1:IO事件驱动模型简介 通常,我们写服务器处理模型的程序时,有以下几种模型: (1)每收到一个请求,创建一个新的进程,来处理该请求: (2)每收到一个请求,创建一个新的线程,来处理该请求: (3)每 ...
- 简单易懂的程序语言入门小册子(3):基于文本替换的解释器,let表达式,布尔类型,if表达式
let表达式 let表达式用来声明一个变量. 比如我们正在写一个模拟掷骰子游戏的程序. 一个骰子有6个面. 所以这个程序多次用到了6这个数字. 有一天,我们忽然改变主意,要玩12个面的骰子. 于是我们 ...
- 合理配置SQLSERVER内存
合理配置SQLSERVER内存 原文地址:https://www.cnblogs.com/lyhabc/archive/2012/09/28/2707857.html SQLSERVER是个很喜欢内存 ...
- 搭建iSCSI文件服务器故障转移群集
故障转移群集(Failover Cluster)可以提供一个高可用性应用程序或服务的网络环境,本章将接受如何搭建iSCSI SAN文件服务器故障转移群集. 故障转移群集概述 我们可以将多台服务器组成一 ...
- Request获取客户端IP
获取客户端的IP地址的方法是:request.getRemoteAddr() ,这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了. ...
- Centos7系统特性之systemd
1.centos系列的系统启动流程(内核级别的启动流程): POST(加电自检)---> Boot Sequence(BIOS)---> Boot loader (MBR)---> ...
- synchronized 的局限性 与 Lock 的优点
我们已经知道,synchronized 是Java的关键字,是Java的内置特性,在JVM层面实现了对临界资源的同步互斥访问,但 synchronized 粒度有些大,在处理实际问题时存在诸多局限性, ...
- MongoDB修改与聚合二
1.修改方法 一 语法 里面有三个大的语句:一个是查询条件:一个是修改字段:一个是其他参数(目前就有两个) db.table.update( 条件, 修改字段, 其他参数 ) update db1.t ...
- luogu P5151 HKE与他的小朋友
嘟嘟嘟 看到\(i\)变成了\(A_i\),我突然想起了置换这个东西.于是马上到网上学了一遍轮换乘法. 手模后发现轮换乘法满足结合律,但不满足交换律. 于是就可以快速幂啦. 需要注意的是每一次相乘是\ ...