从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!
关于作者
- 张丹(Conan), 程序员Java,R,PHP,Javascript
- weibo:@Conan_Z
- blog: http://blog.fens.me
- email: bsspirit@gmail.com
转载请注明出处:
http://blog.fens.me/nodejs-cnpm-npm/
前言
随着Nodejs开发的项目越来越多,Node项目管理就成了一个需要思考的问题了。如果所有项目都开源统一用 NPM 进行管理也没什么问题,但总有一些是我们不希望的完全开放的代码,作为企业是核心秘密保留在公司内部,这个时候就需要在公司内网也搭建一套 NPM 依赖管理系统。
CNPM正好就提供了这个功能。从Github上CNPM的主页看,CNPM由国内Alibaba团队开发维护。
目录
- CNPM是什么?
- 搭建CNPM的服务器
- 设置私有注册库的三种方法
- CNPM的客户端使用
1. CNPM是什么?
CNPM 是一个Nodejs的库,致力于打造私有的 NPM 注册服务。当然,除了私有库功能以外,CNPM官网 (http://cnpmjs.org/) 还提供了NPM同步的服务。
从CNPM的架构图中,我们可以看出CNPM是对NPM做的镜像服务,CNPM会定期同步NPM的资源库,同时CNPM支持发布私有的库,这样就非常方便地集成了公有库和私有库,对于公司内部的开发者来说,基本感觉不到两种库的区别。
另外,我们使用NPM下载依赖包时,经常性地会遇到一些包下载失败的情况,主要原因了NPM的注册服务器在国外,国内的网络环境访问国外的IP并不是太好。所以,直接配置到国内的NPM镜像,可以减少NPM下载出错机会。
比如,最近发生的NPM下载时的“No compatible version found”错误,如果不想升级NPM的环境,那么你还选择用CNPM去进行依赖管理,关于错误的详细介绍,请参考文章 NPM下载出错 No compatible version found
2. 搭建CNPM的服务器
从官方文档中,我们看到CNPM服务器环境,只需要Node(0.11.12) + MySQL(>= 0.5.0),另外我们还需要Linux的环境,接下来就让我们动手自己搭建一个私有NPM的服务器。
我的系统环境:
- Linux: Ubuntu 12.04.2 64bit Server
- Node: v0.11.2
- Npm: 1.2.21
- MySQL: 5.6.11 MySQL Community Server (GPL)
- IP: 192.168.1.20
通过github下载项目源代码
# 下载项目,进入目录 ~ git clone https://github.com/cnpm/cnpmjs.org.git ~ cd cnpmjs.org
在我们开始安装依赖包之前,先要升级NPM的版本,不然会出现“No compatible version found”的错误。
~ sudo npm install npm -g /usr/local/bin/npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js npm@2.0.0-beta.0 /usr/local/lib/node_modules/npm
安装项目依赖
~ sudo npm install npm WARN engine koa-generic-session@1.1.3: wanted: {"node":">= 0.11.9"} (current: {"node":"0.11.2","np m":"2.0.0-beta.0"}) npm WARN engine koa-redis@0.1.1: wanted: {"node":">= 0.11.9"} (current: {"node":"0.11.2","npm":"2.0.0- beta.0"}) npm WARN engine koa-resource-router@0.3.3: wanted: {"node":"> 0.11.4"} (current: {"node":"0.11.2","npm ":"2.0.0-beta.0"}) npm WARN engine koa-rt@0.0.2: wanted: {"node":">= 0.11.9"} (current: {"node":"0.11.2","npm":"2.0.0-bet a.0"}) npm WARN engine koa-router@3.2.3: wanted: {"node":"> 0.11.4"} (current: {"node":"0.11.2","npm":"2.0.0- beta.0"}) npm WARN engine koa-static-cache@1.1.0: wanted: {"node":"> 0.11.4"} (current: {"node":"0.11.2","npm":" 2.0.0-beta.0"}) npm WARN deprecated lingo@0.0.5: This project is abandoned co-read@0.1.0 node_modules/co-read error-formater@1.0.3 node_modules/error-formater └── utility@0.1.16 (address@0.0.3) multiline@1.0.0 node_modules/multiline └── strip-indent@1.0.0 (get-stdin@1.0.0) jshint@2.5.5 node_modules/jshint ├── strip-json-comments@0.1.3 ├── underscore@1.6.0 ├── exit@0.1.2 ├── shelljs@0.3.0 ├── minimatch@0.4.0 (sigmund@1.0.0, lru-cache@2.5.0) ├── console-browserify@1.1.0 (date-now@0.1.4) ├── cli@0.6.4 (glob@3.2.11) └── htmlparser2@3.7.3 (domelementtype@1.1.1, domutils@1.5.0, entities@1.0.0, domhandler@2.2.0, readabl e-stream@1.1.13) koa-middlewares@1.2.0 node_modules/koa-middlewares ├── koa-conditional-get@1.0.2 ├── koa-rt@0.0.2 ├── koa-session@2.0.0 ├── koa-etag@1.3.1 (buffer-crc32@0.2.3) ├── koa-logger@1.2.2 (passthrough-counter@0.0.1) ├── koa-compress@1.0.7 (statuses@1.0.4, koa-is-json@1.0.0, compressible@1.1.1) ├── koa-safe-jsonp@0.2.0 (jsonp-body@0.1.0) ├── koa-rewrite@1.1.0 (path-to-regexp@0.0.2) ├── koa-static-cache@1.1.0 (fs-readdir-recursive@0.0.2, compressible@1.1.1, mime-types@1.0.2) ├── koa-redis@0.1.1 (redis@0.10.3) ├── koa-router@3.2.3 (koa-compose@2.3.0, methods@1.1.0, path-to-regexp@0.2.1) ├── koa-bodyparser@1.0.1 (co-body@1.0.0) ├── koa-favicon@1.1.0 (co-fs@1.2.0) ├── koa-resource-router@0.3.3 (koa-compose@2.2.0, path-to-regexp@0.0.2, debug@0.7.4, lingo@0.0.5, defa ults@1.0.0) ├── koa-generic-session@1.1.3 (buffer-crc32@0.2.3, uid-safe@1.0.1) ├── koa-csrf@2.1.3 (csrf@2.0.1) ├── koa-ejs@1.0.1 (ejs@1.0.0, co-fs@1.2.0, is-type-of@0.2.1) └── koa-onerror@1.0.3 (swig@1.4.2)
创建MySQL数据库,我本地的MySQL用户名为root,密码是mysql,可以通过下面语句创建。
~ mysql -uroot -pmysql -e 'DROP DATABASE IF EXISTS cnpmjs_test;' &&\ mysql -uroot -pmysql -e 'CREATE DATABASE cnpmjs_test;' &&\ mysql -uroot -pmysql 'cnpmjs_test' < docs/db.sql &&\ mysql -uroot -pmysql 'cnpmjs_test' -e 'show tables;' +-----------------------+ | Tables_in_cnpmjs_test | +-----------------------+ | dist_dir | | dist_file | | download_total | | module | | module_deps | | module_keyword | | module_log | | module_maintainer | | module_star | | module_unpublished | | tag | | total | | user | +-----------------------+
接下来,我们需要在项目的./config/index.js文件中,修改MySQL数据库的用户名和密码。
~ vi ./config/index.js 108 /** 109 * mysql config 110 */ 111 112 mysqlServers: [ 113 { 114 host: '127.0.0.1', 115 port: 3306, 116 user: 'root', 117 password: 'mysql' 118 } 119 ], 120 mysqlDatabase: 'cnpmjs_test', 121 mysqlMaxConnections: 4, 122 mysqlQueryTimeout: 5000, 123
启动CNPM服务器,默认会打开两个端口,7001用于NPM的注册服务,7002用于Web访问。
~ node --harmony_generators dispatch.js [Tue Sep 02 2014 15:17:54 GMT+0800 (CST)] [worker:25211:common/redis.js] Redis config can not found [Tue Sep 02 2014 15:17:54 GMT+0800 (CST)] [worker:25211] Server started, registry server listen at 127.0.0.1:7001, web listen at 127.0.0.1:7002, cluster: false [Tue Sep 02 2014 15:17:54 GMT+0800 (CST)] [worker:25211] mysql ready, got 13 tables
从日志中看到,这两个端口服务都绑定在127.0.0.1的本地网络中,我们需要修改配置文件 ./config/index.js文件,注释bindingHost一行,对外网开放。
~ vi ./config/index.js 39 /* 40 * server configure 41 */ 42 registryPort: 7001, 43 webPort: 7002, 44 //bindingHost: '127.0.0.1', // only binding on 127.0.0.1 for local access
第二次,启动CNPM服务器
~ node --harmony_generators dispatch.js [Tue Sep 02 2014 15:22:46 GMT+0800 (CST)] [worker:25259:common/redis.js] Redis config can not found [Tue Sep 02 2014 15:22:46 GMT+0800 (CST)] [worker:25259] Server started, registry server listen at undefined:7001, web listen at undefined:7002, cluster: false [Tue Sep 02 2014 15:22:46 GMT+0800 (CST)] [worker:25259] mysql ready, got 13 tables
通过浏览器访问:http://192.168.1.20:7002,没想到的情况,应用又崩溃了,这个坑深入了!!
[Tue Sep 02 2014 15:29:00 GMT+0800 (CST)] [worker:25404] Server started, registry server listen at undefined:7001, web listen at undefined:7002, cluster: false [Tue Sep 02 2014 15:29:00 GMT+0800 (CST)] [worker:25404] mysql ready, got 13 tables ==== JS stack trace ========================================= 2: arguments adaptor frame: 0->1 Security context: 0x185dd4b5e291 <JS Object>#0# 4: /* anonymous */ [/home/conan/nodejs/cnpmjs.org/node_modules/co/index.js:40] (this=0x2a1e646d07e1 <an Object>#1#,done=0x2d36f5fcdd31 <JS Function>#2#) 5: /* anonymous */ [/home/conan/nodejs/cnpmjs.org/node_modules/koa/lib/application.js:125] (this=0x2d36f5fab301 <a Server>#3#,req=0x2d36f5fcacc1 <an IncomingMessage>#4#,res=0x2d36f5fcc3f9 <a ServerResponse>#5#) 6: emit [events.js:100] (this=0x2d36f5fab301 <a Server>#3#,type=0x8305a126379 <String[7]: request>) 7: arguments adaptor frame: 3->1 8: onIncoming [_http_server.js:450] (this=0x2d36f5fc8029 <an HTTPParser>#6#,req=0x2d36f5fcacc1 <an IncomingMessage>#4#,shouldKeepAlive=0x185dd4b04161 <true>) //省略日志
经过检查发现,是Node版本的问题。重新下载编译安装Node,详细操作请参考文章准备Nodejs开发环境Ubuntu,升级后的版本为
- Node v0.13.0-pre
- NPM 1.4.21
第三次,启动CNPM服务器。
~ node --harmony_generators dispatch.js [Tue Sep 02 2014 16:00:25 GMT+0800 (CST)] [worker:14842:common/redis.js] Redis config can not found [Tue Sep 02 2014 16:00:25 GMT+0800 (CST)] [worker:14842] Server started, registry server listen at undefined:7001, web listen at undefined:7002, cluster: false [Tue Sep 02 2014 16:00:25 GMT+0800 (CST)] [worker:14842] mysql ready, got 13 tables
通过浏览器访问,CNPM服务:http://192.168.1.20:7002
终于正常了,这样就成功搭建了私有的NPM注册服务。
搜索一下,我之前在NPM发布的自己的包ape-algorithm,发现没有结果,根据界面提示CNPM应用会自动去NPM上同步。
第一次同步操作,会下载很多的包,大家要耐心等待啊。页面不能切换!
3. 设置私有注册库的三种方法
我们自己搭建的私有服务怎么用呢?
我们先建一个项目目录
~ /home/conan/nodejs ~ mkdir nodejs-cnpm && cd nodejs-cnpm
3.1 下载指定私有库
一种简单的方式就是,下载的时候指定我们自己的私有库,这样就会从我们自己的私有库中下载。如果私有库没有对应的库,CNPM会自动同步到NPM 找到我们要下载的库和版本,先在CNPM中存一份,然后再传给客户端一份,运行原理和Maven的原理一样。
执行下载的操作
~ npm install ape-algorithm --registry=http://192.168.1.20:7001 ape-algorithm@0.0.8 node_modules/ape-algorithm └── linklist@0.0.3 # 查看下载的库 ~ ls -l drwxrwxr-x 3 conan conan 4096 9月 2 16:36 node_modules
3.2 给项目设置私有库
如果这个项目所有依赖库都从公司内网下载,那么我们可以给整个项目设置私有库,就不需要每次下载的时候单独指定了。
首先,我们查看项目的默设置,通过npm config list命令。
~ npm config list ; cli configs registry = "https://registry.npmjs.org/" user-agent = "npm/1.4.21 node/v0.13.0-pre linux x64" ; node bin location = /usr/local/bin/node ; cwd = /home/conan/nodejs/nodejs-cnpm ; HOME = /home/conan ; 'npm config ls -l' to show all defaults.
registry属性是指向NPM的官司位置https://registry.npmjs.org/,我们可以通过npm config set registry命令来修改这个配置。
~ npm config set registry http://192.168.1.20:7001 # 再次查看项目设置 ~ npm config list ; cli configs registry = "http://192.168.1.20:7001/" user-agent = "npm/1.4.21 node/v0.13.0-pre linux x64" ; userconfig /home/conan/.npmrc registry = "http://192.168.1.20:7001/" ; node bin location = /usr/local/bin/node ; cwd = /home/conan/nodejs/nodejs-cnpm ; HOME = /home/conan
这个项目再下载新包时,就会通过我们私有库去下载。
3.3 给用户设置私有库
如果我们的开发环境在内网,不允许访问外网,那么我们可以设置全局的NPM库。
在当前用户所在的根目录,找到.npmrc文件,配置NPM私有库。
~ vi ~/.npmrc registry=http://192.168.1.20:7001
设置成功后,当前用户的所有NPM下载都会通过私有库来完成。
3.4 设置淘宝的开放库
我们除了使用自己的私有库,还可以使用淘宝的NPM库,这样可以有效地避免国内访问国外NPM库,网络不通的问题。
按照上面的方法,把registry配置为https://registry.npm.taobao.org 就行了。
registry = "https://registry.npm.taobao.org/"
4. CNPM的客户端使用
CNPM 不仅提供服务端的功能,还提供了客户端的访问功能,就像NPM一样。通过全局安装cnpm包,可以完全取代了npm的命令操作了。
安装cnpm客户端
~ sudo npm install -g cnpm /usr/local/bin/cnpm -> /usr/local/lib/node_modules/cnpm/bin/cnpm /usr/local/bin/cnpm-sync -> /usr/local/lib/node_modules/cnpm/bin/cnpm-sync /usr/local/bin/cnpm-check -> /usr/local/lib/node_modules/cnpm/bin/cnpm-check /usr/local/bin/cnpm-web -> /usr/local/lib/node_modules/cnpm/bin/cnpm-web /usr/local/bin/cnpm-user -> /usr/local/lib/node_modules/cnpm/bin/cnpm-user /usr/local/bin/cnpm-doc -> /usr/local/lib/node_modules/cnpm/bin/cnpm-doc /usr/local/bin/cnpm-search -> /usr/local/lib/node_modules/cnpm/bin/cnpm-search cnpm@1.0.0 /usr/local/lib/node_modules/cnpm ├── commander@2.3.0 ├── auto-correct@1.0.0 ├── giturl@0.0.3 ├── cross-spawn@0.1.7 ├── colors@0.6.2 ├── bagpipe@0.3.5 ├── open@0.0.5 ├── debug@1.0.4 (ms@0.6.2) ├── npm-request@0.0.4 (urllib@0.5.11) ├── npm@2.0.0-beta.2 └── urllib@0.5.17 (default-user-agent@0.0.1, debug@0.8.1, digest-header@0.0.1)
测试一下,通过cnpm安装gulp包。
~ cnpm install gulp > node-v8-clone@0.6.2 install /home/conan/nodejs/nodejs-cnpm/node_modules/gulp/node_modules/gulp-util/node_modules/vinyl/node_modules/node-v8-clone > node-gyp rebuild gulp@3.8.7 node_modules/gulp ├── tildify@0.2.0 ├── interpret@0.3.2 ├── pretty-hrtime@0.2.0 ├── deprecated@0.0.1 ├── archy@0.0.2 ├── minimist@0.2.0 ├── semver@3.0.1 ├── chalk@0.5.0 (escape-string-regexp@1.0.1, ansi-styles@1.1.0, supports-color@0.2.0, has-ansi@0.1.0, strip-ansi@0.3.0) ├── orchestrator@0.3.0 (sequencify@0.0.7, events@1.0.2, execify@0.0.3) ├── liftoff@0.12.0 (extend@1.2.1, minimist@0.1.0, resolve@0.7.4, findup-sync@0.1.3) ├── gulp-util@3.0.1 (lodash._reinterpolate@2.4.1, dateformat@1.0.8-1.2.3, minimist@1.1.0, multipipe@0.1.0, lodash.template@2.4.1, through2@0.6.1, lodash@2.4.1, vinyl@0.4.0) └── vinyl-fs@0.3.0 (map-stream@0.1.0, graceful-fs@3.0.2, lodash.defaults@2.4.1, mkdirp@0.5.0, through2@0.5.1, strip-bom@0.3.0, through2-map@1.4.0, glob-watcher@0.0.6, glob-stream@3.1.15, vinyl@0.2.0)
效果同NPM一样,gulp包被成功安装。
当我们要发布包到NPM的时候,由于CNPM默认同步时间差是30分钟,如果想马上同步,需要手动输入同步的命令。
同步gulp包。
~ cnpm sync gulp Start sync ["gulp"]. sync gulp, PUT http://r.cnpmjs.org/gulp/sync?publish=false&nodeps=false logurl: http://cnpmjs.org/sync/gulp#logid=10798 [2014-09-02 05:18:09] user: anonymous, sync gulp worker start, 1 concurrency, nodeps: false, publish: false [2014-09-02 05:18:09] [c#0] [gulp] pkg status: 200, start... [2014-09-02 05:18:09] [gulp] found 15 missing star users [2014-09-02 05:18:09] [gulp] all versions are exists [2014-09-02 05:18:09] [gulp] no versions need to deleted [2014-09-02 05:18:09] [gulp] saving 15 star users [2014-09-02 05:18:09] [gulp] saving 3/187 missing npm users: ["mittya","160mph","vivainio"] [2014-09-02 05:18:09] [c#0] [gulp] synced success, 0 versions: [2014-09-02 05:18:09] [c#0] setImmediate after, gulp done, start next... [2014-09-02 05:18:09] [done] Sync gulp module finished, 1 success, 0 fail Success: [ gulp ] Fail: [ ] sync gulp, PUT https://registry.npm.taobao.org/gulp/sync?publish=false&nodeps=false logurl: https://npm.taobao.org/sync/gulp#logid=8354 [2014-09-02 17:18:13] user: anonymous, sync gulp worker start, 1 concurrency, nodeps: false, publish: false [2014-09-02 17:18:14] [c#0] [gulp] pkg status: 200, start... [2014-09-02 17:18:14] [gulp] found 15 missing star users [2014-09-02 17:18:14] [gulp] all versions are exists [2014-09-02 17:18:14] [gulp] saving 15 star users [2014-09-02 17:18:14] [gulp] no versions need to deleted [2014-09-02 17:18:15] [gulp] saving 3/188 missing npm users: ["mittya","160mph","vivainio"] [2014-09-02 17:18:15] [c#0] setImmediate after, gulp done, start next... [2014-09-02 17:18:15] [c#0] [gulp] synced success, 0 versions: [2014-09-02 17:18:15] [done] Sync gulp module finished, 1 success, 0 fail Success: [ gulp ] Fail: [ ] Sync all packages done, successed: ["gulp"], failed: []
这样我们就完全地把CNPM私有库在公司内部用起来了。把包管理的问题解决了,让程序员可以踏踏实实地写代码才是最重要的!!
转载请注明出处:
http://blog.fens.me/nodejs-cnpm-npm/