新一代的js套件管理工具yarn - 取代npm的工具

談一下突然爆紅的Yarn,這是Facebook最近發布的一款依賴包安裝工具。

比較npm有什麼看得見的優勢? 首先,他非常快,快到見鬼XD

之前裝babel-preset-es2015一直是個痛,改用yarn裝居然不到10秒…

yarn緩存了每次你下載的模塊,所以同樣模塊同樣的版本不會發送第二次下載請求,在開始安裝一個包之前會先用checksums來驗證,你不用擔心本地的緩存的包被破壞了導致安裝失敗
yarn也可以通過並行的網絡請求最大限度利用網絡資源,你可以參考官方對比 npm 的區別 Compare Yarn Performance

另外,npm自己本身也有參與這個專案,所以…斷然改用吧!

yarn官方網站

yarn.jpg

如何安裝

1
npm i yarn -g

如何使用

定義package.json

1
yarn init

安裝套件,比方express

1
yarn add express

現在不需要家 –save 參數也會新增到package.json

移除套件

1
yarn remove express

基本上大部分都跟npm用法類似,你也可以用 yarn -h 查詢用法

根本無痛轉移,大家衝吧!

node-rados安裝與使用 - nodejs與Ceph通訊

最近開始使用nodejs與公司的Ceph串接資料,中間需要透過一個叫做node-rados的掛件工具,不過一開始就在安裝時踩了不少坑,這裡做一下備忘,也提醒之後要使用的人。

  • Ceph 叢集式檔案伺服器
  • Rados Ceph存取框架

雖說nodejs與Ceph,可以透過node-rados這個工具掛件,可以很簡便的通訊,但是還是得先確認兩件事。

注意事項

  1. 目前librados-dev僅直接支援Linux,Windows要安裝非常麻煩(有好心人士作了Windows版本),而且問題很多,我還是建議直接用Linux
  2. 編譯的nodejs,我試過很多版本都不行,目前我使用node v0.12.9,開發的話用nvm去切換版本吧。(不然把服務作在一個docker裡面也是一個辦法)

整個流程大致為這樣

  1. 安裝node-gyp
  2. 安裝編譯node-rados
  3. 準備Ceph定義檔

安裝node-gyp

以下教程依據Ubuntu 14,首先安裝node-gyp,有很多相互依賴的套件,請依照以下順作。

1
2
3
4
5
apt-get install python-software-properties
apt-get update
apt-get install build-essential libncurses-dev autoconf automake libtool
apt-get install make
npm install -g node-gyp

安裝node-rados

記得node版本v0.12.9,當初在這卡了很久..

1
2
apt-get install librados-dev
npm install rados

準備Ceph定義檔

ceph.conf Ceph服務器設定檔,主機位置與key檔位址

1
2
mon host = 192.168.1.100
keyring = ceph.client.admin.keyring

開始使用

上述準備好了之後就可以開始直接利用nodejs與Ceph串接

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
var rados = require('./build/Release/rados'); //編譯後rados函式庫位置
//開啟一個ceph服務,傳入你的ceph名稱,帳號,最後是你的設定檔位置
var cluster = new rados.Rados( "ceph", "client.admin", "./ceph.conf");
var err = cluster.connect();
if (err) {
// 連線失敗
console.log("Error " + err);
throw err;
}
//印出目前使用的Ceph的fsid
console.log( "fsid : " + cluster.get_fsid() );
//取回目前Ceph的pool列表
console.log( "ls pools : " + cluster.pool_list() );
//建立一個通訊流,pool name是rbd
var ioctx = new rados.Ioctx(cluster, "rbd");
//同步寫入Buffer資料,資料ID為myfile
ioctx.write_full("myfile", new Buffer("01234567ABCDEF"));
//取回myfile資料長度
var len = ioctx.stat("myfile").psize;
//同步取回myfile資料
var buf = ioctx.read("myfile", len);
//關閉服務
cluster.shutdown();

以上基本用法,詳細可以看官方範例

基於Thrift的Node.js微服物通訊

最近公司開始要把各服務器的通訊方法改為Thrift,開始試著利用Thrift實作Node.js的通訊架構。

Apache Thrift 是 Facebook 實現的一種高效的、支持多種編程語言的遠程服務調用的框架,傳輸數據採用二進制格式,相對 XML 和 JSON 體積更小,對於高並發、大數據量和多語言的環境更有優勢。

講白了就是資料傳輸速度比傳統的Rest架構快非常多。可參考這篇Microservice Showdown – REST vs SOAP vs Apache Thrift (And Why It Matters)

這玩意很單純的利用tcp去傳輸資料,當然使省去很多瑣碎的多餘資料,省資源,效率更高,很適合用在整合散部各處的node.js微服物器。

但是Thrift也不是沒有缺點,省去了很多瑣碎的手續,相對資料的安全性就會降低,首先一大問題就是tcp連線可能隨時會中斷,所以要你要想要作長連線,最好還是乖乖地使用標準的socket協定,基本上還是建議使用在網路比較穩定的區網內服務通訊。

如果你有一個大型服務,需要收集(或請求)分散各處的微型服務,而這些服務都在同一個主機或是穩定的網路區域,就很適合利用Thrift作為通訊架構。

cc.png

以下實作利用Thrift再在Node.js服務器中通訊的方法

  1. 首先建立一個nodejs專案,然後安裝thrift掛件

    1
    npm i thrift
  2. 建立一個介面定義檔

Thrift其實最棒的地方就是支援很多語言,你只要寫一個.thrift定義檔,就可以幫你輸出各種語言的介面函示庫,c、java、php、ruby、python、js等等主流語言。

先做一個基本的定義檔 demoApi.thrift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 介面定義檔
*/
/* 各語言命名空間 這邊不用改*/
namespace cpp demoApi
namespace d demoApi
namespace java demoApi
namespace php demoApi
namespace perl demoApi
namespace haxe demoApi
/* 定義呼叫的方法介面與參數 */
service DemoApi {
void apiCall() /* 定義一個apiCall方法 */
}

這裡定義一個 DemoApi 的服務,這個服務裡面有一個apiCall方法,apiCall沒有接受參數,也沒有回傳值,所以前面加個viod。

  1. 編譯介面檔

demoApi.thrift 只是一個,定義文件,必須透過編譯器再編譯成各種語言的介面函示庫。

首先下載編譯器

下載後編譯你的demoApi.thrift定義檔,語法如下

1
thrift --gen <language> <Thrift filename>

以下針對node.js作編譯

1
hrift -r --gen js:node demoApi.thrift

編譯完成後產生介面函示庫gen-nodejs資料夾,這個就是node.js的介面函示庫。目前裡面應該會有兩隻檔案
DemoApi.js 方法介面的定義
demoApi_types.js 結構的定義(目前我們沒有定義任何結構)

4.開始撰寫nodejs各通訊端點

介面函示庫好了後就可以開始使用了,首先寫Server端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var thrift = require("thrift");
/*
* 匯入 thrift產生的函式庫
*/
var DemoApi = require("./gen-nodejs/DemoApi");
/**
* 定義一個 DemoApi 服務器
*/
var server = thrift.createServer(DemoApi, {
/**
* 最單純的通訊,呼叫定義的apiCall方法,定義的方法請參照demo.thrift
*/
apiCall: function (result) {
console.log("apiCall()");
result(null);
}
});
/**
* 偵聽8080 port
*/
server.listen(8080);

再來是Client端

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
var thrift = require("thrift");
/*
* 匯入 thrift產生的函式庫
*/
var DemoApi = require("./gen-nodejs/DemoApi");
/**
* 通訊協定定義
*/
var transport = thrift.TBufferedTransport();
var protocol = thrift.TBinaryProtocol();
/**
* 連線
*/
var connection = thrift.createConnection("localhost", 8080, {
transport: transport,
protocol: protocol
});
/**
* 連線錯誤事件
*/
connection.on('error', function (err) {
console.error(err);
});
/**
* 打開一個DemoApi服務通訊流程
*/
var client = thrift.createClient(DemoApi, connection);
/**
* 最單純的通訊,呼叫定義的apiCall方法,定義的方法請參照demo.thrift
*/
client.apiCall(function (err, response) {
console.log('apiCall()');
connection.end(); //事情都作完記得關閉連線,很重要!!!
});

好了之後你可以分別執行server與client,順利的話應該可以看到執行的console.log結果

接下來我們試著傳送一些資料,目前Thrift可以定義的類型如下

  • bool
  • i8 (byte)
  • i16(16位元整數)
  • i32(32位元整數)
  • i64(64位元整數)
  • double(64位元浮點數)
  • string(字串)
  • binary(byte array)

我們在定義檔demoApi.thrift上加上一個新的方法

1
2
3
4
service DemoApi {
void apiCall(), /* 逗號隔開 */
i32 add(1:i32 num1, 2:i32 num2) /* 新增add這個方法 */

add這個方法傳入兩個32位元整數,最前面的i32代表回傳的型態

加上後記得再編譯一次

1
hrift -r --gen js:node demoApi.thrift

Servre端

1
2
3
4
5
6
7
8
apiCall: function (result) {
console.log("apiCall()");
result(null);
},
add: function (n1, n2, result) {
console.log("add(", n1, ",", n2, ")");
result(null, n1 + n2);
}

Client端

1
2
3
client.add(1, 1, function (err, response) {
console.log("1+1=" + response);
});

這個方法是把傳入的兩個數字相加後再return回去。

再次執行後應該可以看到對應的結果!

其他資料型態與完整範例請至我的gitlab

https://gitlab.com/cainplay/Thrift_demo

讓你更優雅的使用Webpack - webpack-dashboard

看膩了webpack的建構輸出嗎?可以考慮試試加上webpack-dashboard讓你的wedpack輸出更優雅!

如果你有在用webpack-dev-servery作為測試服務的話,你應該會更喜歡它!

原來的webpack輸出
qa1.png

加上webpack-dashboard後的輸出
qa2.png

是不是感覺清楚清新很多!

使用方式

首先安裝

1
npm install webpack-dashboard --save-dev

然後在你的webpack.config.js中加上

1
2
3
var Dashboard = require('webpack-dashboard');
var DashboardPlugin = require('webpack-dashboard/plugin');
var dashboard = new Dashboard();

最後添加這個plugins

1
2
3
plugins: [
new DashboardPlugin(dashboard.setData)
]

試著啟動你的webpack-dev-server,再加上quiet參數(主要是去除多餘的輸出)

1
webpack-dev-server --quiet

webpack-dashboard目前還處於初期階段,有興趣的人可以試著玩看看。

利用Jsdoc幫Javascript產出漂亮的文檔

利用Jsdoc幫自己寫的js庫產生文件真的是很方便,只要你在寫code時,依照jsdoc規範寫好註解後,就可以幫你產生漂亮的文檔。

自己本身開發是用Sublime Text 3, 可以搭配安裝Doc​Blockr這個Sublime packages 當可以幫你在寫code時做好符合jsdoc規範的版型。

安裝與使用方式請至Doc​Blockr官網都有詳細解說

大致上就是在code上面輸入 /** 後按下 tab 見就會幫你產生註解版型

c1.gif

原本自己搭配grunt-jsdoc使用,一直都很順利,不過最近公司專案都統一使用gulp,所以改用了 gulp-jsdoc ,但是發現不支援新的 Jsdoc3 語法,查了一下發現可以另外使用 gulp-jsdoc3。

gulp-jsdoc3

使用方式

安裝所需掛件

1
2
3
npm i gulp-cli -g
npm i gulp --save-dev
npm i gulp-jsdoc3 --save-dev

加上你的 gulpfile.js檔案

1
2
3
4
5
6
7
var gulp = require('gulp');
var jsdoc = require('gulp-jsdoc3');
gulp.task('doc', function (cb) {
gulp.src(['./README.md', './src/*.js'], { read: false })
.pipe(jsdoc(cb));
});

gulp.src後面傳入的陣列README.md是文件檔的首頁內容,可以把你要製作文件檔案填入陣列。

輸出文檔

1
gulp doc

之後你應該可以看到文件資料夾

基本上gulp-jsdoc3裡面有綁定一個ink-docstrap版型,說真的我不是很喜歡這個樣式,jsdoc有很多現成的樣板可以挑選,我自己是喜歡jaguarjs-jsdoc這個版型

jaguarjs-jsdoc

雖說jsdoc3可以自己定義樣板,不過我使用gulp-jsdoc3卻一直無法設定更變樣式,就算我自訂義了conf.json,也頂多變json成預設樣式,(如果有人知道怎麼設定再麻煩告訴我)

最後乾脆直接把gulp-jsdoc3定義的預設版型改掉,不過每開一個專案就改一次真的很煩,最後乾脆整個再包一個npm掛件,這樣使用時就不用自己手動去換,有需要的人可以去npm下載包裝好的

leedian-jsdoc

使用方式跟gulp-jsdoc3一樣,只是預設版型改成我喜歡的jaguarjs-jsdoc

另外當然也是可以自訂jaguarjs-jsdoc的版面設定
比方開一個conf.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"tags": {
"allowUnknownTags": true
},
"source": {
"includePattern": ".+\\.js(doc)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"opts": {
"recurse": true
},
"templates": {
"cleverLinks": true,
"monospaceLinks": true,
"default": {
"outputSourceFiles": true
},
"applicationName": "My SDK",
"openGraph": {},
"meta": {}
}
}

你的 gulpfile.js檔案

1
2
3
4
5
6
7
8
var gulp = require('gulp');
var jsdoc = require('leedian-jsdoc');
gulp.task('doc', function (cb) {
var config = require('./conf.json');
gulp.src(['./README.md', './src/*.js'], { read: false })
.pipe(jsdoc(config, cb));
});

最後附上一些Jsdoc規範

Jsdoc中文文檔

有了這些你也可以產出漂亮又專業的文件

使用Cordova包裝你的Web,建立你的第一個APP

Cordova是一個開放源碼移動開發框架。它允許您使用標準的web技術如HTML5、CSS3和JavaScript進行跨平臺開發。

前身是Phonegap,這樣說可能很多人心裡有底了。或許有些人會說,用這種方式包裝WedView成為APP效能不是很差嗎?

實際上以目前手機的硬體與效能,已經跟以前不一樣了,甚至有些幾乎接近個人電腦(而且將來還可能會更好),加上code好好寫的話,性能也不至於到不能看的程度(實際上很多性能不好的APP都是因為code沒有好好寫,比方沒有好好的使用硬體加速,或是記憶體與事件流程沒有好好管理..)

雖說性能依然不能跟原生做比較,但是由於開發成本差異實在太大了,某些情況下直接使用Cordova包裝成APP說真的也可以是一種選擇。

如果你已經是一個Web開發者,Cordova真的可以幫你省下非常說的時間。

本篇針對在Windows下第一次使用Cordova輸出一個Android APP做說明。(在這之前你可能需要先學會如何使用nodejs工具命令)。Cordova使用上真的相當容易,比較麻煩的就是安裝流程繁瑣,最近因為工作需要,又再把環境建立起來,順便寫下來給需要的人參考。

安裝Crodova

安裝Cordova全域命令

1
npm i -g cordova

安裝JAVA開發工具箱(JDK)

以下針對Android,都是繁瑣的步驟,按照步驟過了這裡就可以快樂開發了XD

首先安裝jdk

Java SE Development Kit 8 Downloads

下載windows版本,安裝後設定下面這些系統變數,不會的看這裡

  • PATH 加上你剛剛的jdk路徑
1
C:\Program Files\Java\jdk1.8.0_101\bin

這是我的別照抄了,就是你剛剛裝的路徑,進去bin資料夾

  • 增加 JAVA_HOME 變數

新增一個變數叫做JAVA_HOME設為jdk路徑

1
C:\Program Files\Java\jdk1.8.0_101

這是我的別照抄了,就是你剛剛裝的路徑

安裝Android SDK

這步驟下載花很多時間,忍耐一下…

  • 首先下載安裝Android sdk tools

SDK Tools Release Notes

這個工具會幫你管理Android sdk,之後SDK用它來幫你下載。

  • 加上Android sdk tools系統變數

Path 加上Android sdk tools的路徑

1
2
C:\Users\user\AppData\Local\Android\Sdk\tools
C:\Users\user\AppData\Local\Android\Sdk\platform-tools

一樣別照抄,我不知道你的tools裝在哪裡,有兩個路徑,別漏掉了。

  • 新增一個 ANDROID_HOME 變數

新增 ANDROID_HOME 變數

1
C:\Users\user\AppData\Local\Android\Sdk

一樣別照抄,設為你的tools路徑,很多人都少了這個…

到這裡後,安裝全都完成了,Android sdk tools預設幫你安裝最新的SDK,不過Cordova可能不會用最新的,你可以再使用Android sdk tools安裝需要的sdk版本

終於可以開始輸出第一個專案試試XD

建立一個Android專案

  • 建立一個專案,以下針對Android
1
cordova create hello com.myName.hello HelloWorld

說明一下上面的內容

cordova create hello 建立一個專案資料夾叫做hello

com.myName.hello 這是一個命名空間,在手機上每個app都會有自己的命名空間,一般而言會像網址反向。

HelloWorld 你的APP名稱

  • 新增Android平台

剛剛的動作,你應該已經產生了一個hello專案資料夾

1
2
cd hello
cordova platform add android

建立一個android平台的專案包(另外當然還有ios,win8….這裡不多說明)

  • 打包app

我們先打包一個空專案

1
cordova build

耐心等等待一下,如果沒有錯誤,那恭喜你,你已經建立好開發環境了

如果遇到錯誤,一班都是以下問題

  1. path等的一些系統變數,忘了設定,或是設錯
  2. Android sdk tools裝的SDK版本不對,這個看錯誤訊息應該可以知道他要什麼版本 (platform android target 問題)

你可以把輸出的apk裝在你的手機上看看,應該會看到一個cordova首頁的畫面。

logo.png

聰明的你應該知道其實就是打包 hello\www 裡面的內容

另外每次輸出都要安裝很麻煩,你可以打開手機的偵錯模式,然後接上你的電腦,之後只要

1
cordova run

就可以直接裝到你的手機上

如果還有不清楚可以去參考官網

nodejs使用redis緩存key值

Redis 是開源的記憶體 Key-Value 資料庫實作,自己目前使用上絕大部分是拿來當成session的緩存,(配合express-session),實務上可能還會再搭配MongoDB或者其他的關聯性資料庫。

但是有時候專案實在不大,有時還是會偷偷拿來用

關於redis使用,這裡做一下備忘順便給初學者參考。

安裝

Linux

1
2
3
4
wget http://download.redis.io/releases/redis-3.2.1.tar.gz
tar xzf redis-3.2.1.tar.gz
cd redis-3.2.1
make

Windows
到這裡來下載安裝

啟動服務

執行安裝目錄下的 redis-server

window 版本可能得指定conf檔案

1
redis-server redis.windows.conf

這個.conf是 redis 的一些參數設定

nodejs使用

安裝模組

1
npm install redis

連線

1
2
3
4
5
6
var redis = require('redis');
//預設連線本機的6379 port,也可以指定 redis.createClient(port, host);
var client = redis.createClient();
client.on('connect', function() {
console.log('connected');
});

新增key並查詢

1
2
3
4
client.set('keyName', 'myName'); //新增
client.get('keyName', function(err, reply) { //查詢
console.log(reply); //輸出 myName
});

如果沒有key就會是 null

存的key值,都會變轉成字串

其他請自行參閱

如何在Hexo預設模板增加comments的Widget

上週用Hexo架設了部落格後,寫文章真的方便很多,由於我對面版面,沒什麼要求,所以直接使用Hexo的預設版型landscape,不過發現並沒有和讀者互動的comments,爬了下文章,看來得自己增加Widget設定。

網友上推薦直接掛上https://disqus.com/的功能,這也是hexo預設的comments widget,這裡做一下備忘

  1. 首先到https://disqus.com/註冊一個帳號,然後記下你的ID
  2. 在 根目錄下的 _config.yml 中增加
    1
    2
    # Disqus
    disqus_shortname: 你的ID

完成後記得編譯你的版型,發布後你應該可以看到你的comments Widget

另外disqus widget的詳細設定,在你註冊disqus後,可以到官網調整

如何在Hexo預設模板增加comments的Widget

上週用Hexo架設了部落格後,寫文章真的方便很多,由於我對面版面,沒什麼要求,所以直接使用Hexo的預設版型landscape,不過發現並沒有和讀者互動的comments,爬了下文章,看來得自己增加Widget設定。

網友上推薦直接掛上https://disqus.com/的功能,這也是hexo預設的comments widget,這裡做一下備忘

  1. 首先到https://disqus.com/註冊一個帳號,然後記下你的ID
  2. 在 根目錄下的 _config.yml 中增加
    1
    2
    # Disqus
    disqus_shortname: 你的ID

完成後記得編譯你的版型,發布後你應該可以看到你的comments Widget

另外disqus widget的詳細設定,在你註冊disqus後,可以到官網調整

如何利用Commander建立自己的Node命令

commander模組可以製作自己的nodejs命令,類似grunt bower的全域指令服務

新增一個npm專案

如果要上傳至npm服務,方便起見可以先開一個github專案,方便之後npm publish

好了之後clone下來,初始化專案

1
npm init

建構命令

安裝 commander

1
npm i commander --save

範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.0.1')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq-sauce', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineapple');
if (program.bbqSauce) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);

詳細內容說明請至官網看..

重點第一行的#!/usr/bin/env node指定node執行

修改 package.json

增加 bin 屬性

1
2
3
{
bin: { mycom: "./index.js"}
}

這代表自己命名一個 mycom 命令,會進入 index.js 這隻程式

上傳至npm

1
npm bublish

使用方式

安裝

1
npm install 你建立的模組 -g

目前試過沒有安裝-g全域無法使用,區域使用方式之後再補上..

執行自己的命令

1
mycom