Node.js项目拆包工程化
背景
在我们开发的过程中,经常会遇到这样的问题,开发完了一些代码或者一个接口,别的小伙伴过来问你,代码可不可以给他复用,接口可以给他调用。这说明代码的复用和抽象对团队协作是很重要的。举个例子,如下图

在这幅图中A服务先开发的,B服务开发的时候与A服务功能相似,尽量使用A服务的接口以提高效率,那么B服务是依赖A服务的,这样会产生如下痛点
- 如果B服务有需求,A服务不满足,则需求要先提给A服务,如果A服务的小伙伴没时间开发...那么B服务只能等待,因为这是一种依赖关系。
- 代码复用,因为是通过接口,所以也谈不上复用
要想解决这个两个痛点,通用的思路是将A服务做下沉抽象,找团队专门做,或者约定规范A服务组和B服务组共同维护一个下沉的服务 ,这里我们使用node.js来开发A、B项目,通过包来代替web服务,可以提供一种不一样的思路,通过对node.js项目的工程化,优化A、B项目的依赖,使开发A服务的同时对B服务进行开发支持
思路
如何一边开发A服务一边对外提供支持?node.js抽象的形式就是包,也就是说我们一边开发A服务一边对外发布公用的包,我们来看下面这幅图

这是一个koa项目的目录,问题来了,除了node_modules,这个项目里面可以有几个包,有人会说一个项目就是一个包,我们先写一个简单的例子,如下图

在routes里面添加一个路由地址,调用services里面的方法
const router = require('koa-router')()
const FooService = require('services').FooService
router.get('/queryFoo', async (ctx, next) => {
let fooService = new FooService()
ctx.body = await fooService.queryFoo()
})
module.exports = router
写一个service
class FooServices {
async queryFoo () {
return 'foo'
}
}
module.exports = FooServices
下面开始改造:
在services里面加入index.js和package.json,将FooService.js通过index.js曝露出来,这样services我们就拆成了一个包了

然后直接把services扔到node_modules里面,修改下routes里面的index.js的引入
const router = require('koa-router')()
const FooService = require('services').FooService //修改
router.get('/queryFoo', async (ctx, next) => {
let fooService = new FooService()
ctx.body = await fooService.queryFoo()
})
module.exports = router
那么routes可不可以变成包、models可以不可以,当然可以,虽然不用这么极端的把一切都拆成包,但把services拆成包,效果是很不错的,如下图

在这里我们可以这样定义, A服务在开发的同时,也开发一个公用的下沉式的服务包,开发完services后,A组可以继续开发controller、view层,B组在services基础之上就可以开始开发了,不需要等A服务都开发完成,更高效,团队间的配合更加灵活。
实现
上面只是提供了一种想法,实现这个想法还需要一个过程,先说产生了什么问题:
问题1,如果我们把services单独拆出来变成一个项目,可以...但是我们开发的时候回很郁闷,会遇到: 修改services发包、下包、调试、修改、发包、下包、调试...真是好麻烦啊~~~
那么如何在一个项目里面解决包依赖,我们来看一种实现的思路:
先编写一个js脚本,将services文件夹通过创建符号链接,链接到node_modules
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const rootPath = process.cwd();
fs.symlinkSync(`${rootPath}/services`, `${rootPath}/node_modules/services`, 'dir');
随便配置个命令将调用脚本命令配置到package.json中
"scripts": {
"start": "node bin/www",
"dev": "./node_modules/.bin/nodemon bin/www",
"prd": "pm2 start bin/www",
"test": "echo \"Error: no test specified\" && exit 1",
"l": "node bin/link"
}
使用命令执行脚本
npm run l

建立符号链接后,修改services里面的代码,node_modules里的services也会跟着变,这样我们就解决了上面的问题。
注意:这里只是提供思路,要完善功能,请有兴趣的小伙伴自己实现。
问题2,上面的项目里我们只同时多开发一个包,如果在一个项目里面同时开发几十个包,引包和发布,岂不是每次都要做几十次,这个问题还好,更恐怖的是,如果这几十个包还有引用关系....想象不出来,那么看下面的例子,

在services里面有两个包,下面我们用zz-foo-services引用下zz-bar-services,多个services之间的引用是十分常见的。

问题来了,zz-bar-services就没有发布,从哪引用啊,难不成又建个脚本用来建符号链接,那要是包多,几十个包都有依赖关系,怎么建链接啊~~~
这里我们就需要使用lerna来帮我们管理一个项目的多个包的包依赖、包发布等,例如babel项目的开发就是使用lerna进行包管理、发布的,下面我们来看下lerna的用法。
安装 lerna
npm i -g lerna
初始化
在项目根目录执行命令
lerna init
在根目录建一个packages,是lerna管理的跟目录,我们把刚才的包移动到这个目录下,如下图

使用命令将packages里面的包的依赖安装好
lerna bootstrap
这个命令会执行npm i,还有创建符号链接

如上图,zz-foo-services已经被链接进来了。
注意:这里packages里面的包链接到node_modules,有兴趣的小伙伴自己动手试试。
问题3 多包的版本管理,这里我们使用lerna publish命令将包批量发布出去,这里我们不举例子,有兴趣的小伙伴可以自己都动手试试。
总结
通过对node.js的项目工程化的处理,我们可以在一个项目里面同时开发多个包,管理多个包,使得更紧密的团队协作,包的高效拆分,包的管理与优化的开发过程,本文中笔者只是提供了工程化的部分思路,要想产出最佳实践还需要做很多的优化。

Node.js项目拆包工程化的更多相关文章
- [Node.js] Node.js项目的持续集成
原文地址:http://www.moye.me/2016/03/03/nodejs_ci_by_jenkins 引子 持续集成 (Continuous Integration,简称CI)是一种软件工程 ...
- WebStorm中Node.js项目配置教程(1)——创建项目
Node.js绝对是一个web开发的热点话题,作为web神器的WebStorm也是开发Node.js的佼佼者. 接下来就Node.js项目在WebStorm的配置操作就行详细的讲解,首先是创建项目.两 ...
- Node.js项目APM监控之New Relic
现在上一个项目,如果没有APM监控服务或应用的运行性能参数,等于是一架没有盲降系统的飞机正在盲降,结果会很悲催.出现了访问失效等问题时,都很难判定是性能瓶颈还是一个藏的深的bug,汇报的时候一顿眼晕, ...
- 如何线上部署node.js项目
来源:http://blog.csdn.net/chenlinIT/article/details/73343793 前言 最近工作不是很忙,在空闲时间学习用node+express搭建自己的个人博客 ...
- 基于 Token 的身份验证:JSON Web Token(附:Node.js 项目)
最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twitter,Google+,Github 等等,比起传统的身份验证方法,Token 扩展性更强, ...
- 15个Node.js项目列表
前言: Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台,是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascri ...
- Node.JS 项目打包 JXCore
哈哈,又回来了 当你开发完成了Node.JS项目,你应该需要打包发行吧 好,JXCore就是干这个的啦! 嗯,可能你会这样来安装 1. curl http://jxcore.com/xil.sh | ...
- Node.js 项目的配置文件
在 Node.js 中可以通过process.env来访问当前的环境变量信息,比如: { PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin', T ...
- WebStorm中Node.js项目配置教程——项目设置
上一章讲解了Node.js项目在WebStorm中的两种创建方式,当完成Node.js项目创建以后,剩下的就是涉及配置设置工作. 为了确保Node.js全局和Node.js核心模块的代码完成功能,打开 ...
随机推荐
- vue+elementUI表格列显示隐藏遇到bug
在最近的项目中,有需求要做到根据字段显示列,原来以为简单的v-if可以解决. 在开发的过程中遇到问题, <el-table ref="multipleTable" :data ...
- 干货 | 10分钟玩转PWA
关于PWA PWA(Progressive Web App), 即渐进式web应用.PWA本质上是web应用,目的是通过多项新技术,在安全.性能.体验等方面给用户原生应用的体验.而且无需像原生应用那样 ...
- Windows Server 2012 配置远程桌面帐户允许多用户同时登录
网上找了很多关于设置远程桌面最大连接数的文章,大都是说先要到控制面板的管理工具中设置远程桌面会话主机等,大体和我之前的文章<设置WINDOWS SERVER 2008修改远程桌面连接数>里 ...
- Netty使用(一)
什么是Netty Netty由JBOSS提供的基于Java NIO的开源框架,Netty提供异步非阻塞.事件驱动.高性能.高可靠.高可定制性的网络应用程序和工具, 可用于开发服务端和客户端. 配置服务 ...
- mui框架下拉刷新和上拉刷新
当初写的时候,是用的谷歌浏览器测试的,都可以正常刷新,下载到手机上面,在ios是可以刷新的,在安卓上面就刷新不了,就是拉不动,后来慢慢排除不是HTML的原因,是上下拉代码有问题,刚开始看的时候也没问题 ...
- orm单表查询和模糊查询
一.单表查询 1. 返回queryset对象的查询 all() 以列表形式返回全部queryset对象 filter(**kwargs) 筛选 exclude(**kwargs) 排除 reverse ...
- selenium批量执行脚本操作
import unittest import os from HTMLTestRunner import HTMLTestRunner # 待执行用例的目录 def allcase(): #引入执行用 ...
- web应用与web框架
一.web应用 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. import socket def handle_request(client ...
- pointer-events: none 的两个应用场景
简介 pointer-events: none 真是个神奇的属性. 该属性有什么用?借用 CSS3 pointer-events:none 应用举例及扩展 的总结来说: pointer-events: ...
- UWP关于图片缓存的那些破事儿
看似简单的功能,实施起来却是有着一堆大坑. 按着基本功能来写吧 1.选择图片并显示到Image控件中 2.图片序列化为byte数组以及反序列化 3.本地存储与读取 1.选择图片: 逻辑就是使用File ...