关于不同业务场景抽取公有模块与搭建npm私有仓库结合处理前端包耦合问题的解决方案

一、背景


 目前我在前端 Vue 组件化开发中碰到这样一种情况,有两个不同的项目的业务场景,其中一些模块是在上一个项目 A 中使用的,并且可以作为共用的模块在下一个项目 B 中使用(或进行少量修改)

 但是目前B项目的开发的前端代码是在A项目下新增 local/B 包,存放相关B项目代码。

 我始终认为这样的开发方式是种不好的解决方法,理由如下:

  • 1、增加了 A 项目和 B 项目两个不同业务场景的耦合
  • 2、增加了整个前端包体积,导致压缩打包时间加长
  • 3、前端代码中增加 A、B 各自业务场景冗余的组件代码与路由,维护困难
  • 4、拓展不易,如果将来还有更多项目需要开发,如果仅因为一两个共用组件模块,仍然使用这种方式,无异于加剧这些缺点
  • 5、与组件化开发思想背道而驰,不能很好利用新项目新框架的特性

 这边找到了一个解决方案,抽取出公共组件封装成 Node 模块,放入自己搭建的私有的 npm 仓库中,当不同业务场景需要使用这个公共组件时,只需通过 npm install 引入该组件使用即可。

 当我们需要修改公共组件代码时,只需要单独修改该公共组件代码,并打包提交 npm 私有仓库。同时更新不同业务场景的 package.json 引用版本即可完成修改。

二、轻量级 NPM 私有仓库-Sinopia


 Sinopia 项目地址
 Sinopia 项目是一个本地部署的轻量级 NPM 私有存储仓库,其可以存储本地私有 NPM 模块包,并且可以缓存远程项目包到本地仓库。其有以下有点:

  • 零配置,无需配置即可使用,安装简便
  • 可上传私有模块
  • 无需使用数据库等 DB ,默认自带一个小数据库,完全够一个小前端团队使用
  • 自动缓存已使用的远程仓库上项目到本地,加快包获取速度
  • 可对远程仓库中的包进行修改并提交到本地(如果远程仓库包中有 Bug ,但远程项目未修改,可本地修改提交本地,给其他项目使用)
     我们可以将其类比成 Maven 本地仓库服务

2.1 安装与使用 Sinopia


2.1.1 获取 Sinopia 及安装


 前提在你的服务器有Node相关环境

1
2
$ npm install -g sinopia
$ sinopia

 非常简单完成私有仓库的搭建。

2.1.2 修改 Sinopia 远程仓库获取地址


 由于某些原因,获取 npmjs.org 项目时经常报错超时,故可以把 Sinopia 获取远程仓库地址改为淘宝镜像源。如下:
 修改 Node 全局模块,打开 yourpath/node_modules/sinopia/conf/default.yaml:
 node_modules 路径文件
 其中修改该文件中间的,uplinks 参数:

1
uplinks:
  npmjs:
    #url: https://registry.npmjs.org/
    url: https://registry.npm.taobao.org/

 随后重启 Sinopia 即可完成远程仓库地址修改。

2.1.3 修改本地 npm registry 地址


 在自己的机器上设置 npm registry 地址,将其设置成远程私有仓库服务器地址,端口:4873

1
npm config set registry http://localhost:4873/

 注:此处是在本地测试,故将地址设为localhost,依据你的私有仓库服务器地址进行相应修改

2.1.4 Sinopia 提供 docker 镜像使用


 Sinopia docker

2.1.5 Sinopia 在服务器上永久运行


 使用 Node 包 forever 让 Sinopia 一直运行
 forerver 项目地址
 
 首先安装 forever 包:

1
$ sudo npm install -g forever

 确认之前有运行 Sinopia ,生成其 Config 文件,之后就能永久运行 Sinopia:

1
$ forever start `which sinopia`

 我们可在访问 http://localhost:4387 查看 Sinopia 效果:
 Sinopia Page

三、 抽取组件模块,并在私有 npm 仓库发布


 完成 Sinopia 搭建之后可以,进行 Node 模块构建,并上传到私有仓库,成为公共模块。最终的效果,可在不同项目中使用 npm 安装共有模块,效果流程如下:
 上传本地模块到私有仓库
 在 Sinopia 中查看
 在项目中安装上传的本地包
 在项目的package.json中查看

3.1 组件构建模块并发布的过程


 我们以项目中的一个共有组件模块举例,完成共有模块的抽取,发布和更新的全过程。

3.1.1 构建本地模块并发布


 首先我们简单地抽取共有模块,到一个新的目录,这里选用 人员标签 这个模块。构建出来的共有模块目录结构如下:
 模块目录结构
src/index.vue 即是我们抽取出得共用组件。
 我们首先 npm 初始化这个文件夹:

1
npm init

 里面设置该模块的各种信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "ssa_assistant_label",
"version": "0.0.1",
"description": "ssa_assistant_label_component",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
,

"keywords": [
"ssa_assistant_label_component"
],

"author": "guojohnny",
"license": "ISC"
}

 向私有仓库添加用户:

1
2
3
4
$ npm adduser  --registry http://localhost:4873/
Username: johnny
Password:
Email: (this IS public) johnny@XXX.com

 如果已经在私有仓库中创建过了用户,直接登陆即可:

1
2
3
4
$ npm login
Username: johnny
Password:
Email: (this IS public) johnny@XXX.com

 最后使用以下命令就能发布本地模块到私有仓库中了:

1
$ npm publish

 截图如下:
 publish 发布模块
 在每次上传时最好修改version版本号,不然会自动覆盖原有模块的那个版本
 我们可以看一下我们上传的模块
 在 Sinopia Page 中查看新发布的模块
 通过这些步骤,我们可以轻松发布一个私有的模块。

3.1.2 上传模块的使用


 当我们上传完成组件模块后,在不同的项目中,都能够使用到这个组件,与其他获取 npm 上的模块过程没有其他区别。

1
npm install --sav-dev ssa_assistant_label

 npm就会自动去 Sinopia 中获取该共有组件了
 在项目package.json 中查看引用模块
 我们就可以在该项目中这样使用这个共有模块(举例):

1
2
3
4
5
6
7
import ssaAssistantLabel from 'ssa_assistant_label/src/index.vue'
....
new Vue({
components: {
ssaAssistantLabel
}
})

 在项目package.json 中查看引用模块
 最后出来的效果,和在项目中使用没有差别:
 在项目模块效果

3.1.3 更新、删除模块


 当我们需要修改这个共有模块时,只需改变改好的模块中的 package.json 文件中的版本号上传到私有仓库即可。
 更新项目模块效果
 当我们要删除一个模块时,也非常容易:
 删除项目模块效果
 删除项目模块效果

四、在不同项目中使用


 通过以上步骤,我们就可以在不同的项目中使用共有模块。这样就避免了,不同业务场景项目的互相组件耦合,减少了项目体积与维护难度。
 当我们有需求要对当前共有模块进行修改,只需修改这个私有仓库中的版本,同时改变不同项目中引用的共有模块版本,即可完成修改。如果某一项目不修改,则可以不用更新引用组件版本。

五、Day2 正式往服务器上搭建问题处理


5.1 Sinopia gyp error


 出现问题描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
gyp ERR! build error
gyp ERR! stack Error: make failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:269:23)
gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:98:17)
gyp ERR! stack at Process.ChildProcess._handle.onexit (child_process.js:797:12)
gyp ERR! System Linux 3.13.0-52-generic
gyp ERR! command "node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/user/ocean-wisdom/node_modules/keystone/node_modules/keystone-utils/node_modules/limax/node_modules/cld
gyp ERR! node -v v0.10.25
gyp ERR! node-gyp -v v2.0.1
gyp ERR! not ok
npm info cld@2.4.3 Failed to exec install script
npm ERR! Linux 3.13.0-52-generic
npm ERR! argv "node" "/usr/local/bin/npm" "install" "--loglevel=info"
npm ERR! node v0.10.25
npm ERR! npm v2.12.1
npm ERR! code ELIFECYCLE

npm ERR! cld@2.4.3 install: node-gyp rebuild
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the cld@2.4.3 install script 'node-gyp rebuild'.
npm ERR! This is most likely a problem with the cld package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-gyp rebuild
npm ERR! You can get their info via:
npm ERR! npm owner ls cld
npm ERR! There is likely additional logging output above.
npm info preuninstall cld@2.4.3
npm info uninstall cld@2.4.3
npm info postuninstall cld@2.4.3
npm info preuninstall limax@1.1.0
npm info uninstall limax@1.1.0
npm info postuninstall limax@1.1.0
npm info preuninstall keystone-utils@0.2.0
npm info uninstall keystone-utils@0.2.0
npm info postuninstall keystone-utils@0.2.0
npm info preuninstall keystone@0.3.12
npm info uninstall keystone@0.3.12
npm info postuninstall keystone@0.3.12

npm ERR! Please include the following file with any support request:
npm ERR! /home/user/ocean-wisdom/npm-debug.log

 具体原因是,有些 Sinopia 的引用模块需要使用 C++ 编译,而服务器上不存在导致的:
解决办法:

1
npm -g install sinopia --no-optional --no-shrinkwrap

 这样就能成功安装上 Sinopia 了
解决方法出自issue

5.2 bash:sinopia command not found


 如果运行找不到命令,请先source一下配置:

1
source /etc/profile

5.3 在自己浏览器客户端不能访问:http://10.*.*.*:4873


 出现这个问题,是因为 Sinopia 的监听端口未全部开启
 请修改 sinopia文件夹下的 config.yaml 文件,增加:

1
listen: 0.0.0.0:4873

 重启服务即可

5.4 pm2 start sinopia


 pm2 服务器上永久启动 Sinopia ,会在你的 Node 目录下新建 sinopia 包,所以导致之前修改的listen地址不对了,在Node目录下重新修改一下 config.yaml 即可,再重启 pm2 就行