yumからのインストールを行うと場合によっては、yumがおかしくなるため現状は他の方法が望ましい。これは、node.js がyumリポジトリから削除されたため、一度、yumでインストールすると、yum がnode.jsの情報をyumリポジトリに見にいくのだが、データが無いといって停止する。
OpenSSLのバージョンが古いとインストールに失敗することがある。
# wget http://nodejs.org/dist/v0.12.2/node-v0.12.2.tar.gz # tar zxvf node-v0.12.2.tar.gz # cd node-v0.12.2 <- 展開名は自分で確認 # ./configure --prefix=/usr/local/node <- 必要であれば、prefix を指定 # make # make install
※gyp_node でエラーがでる場合は、このページのパッチを行うとコンパイルは通るようになる。
nvm(Node Version Manager)を使ってインストール
# git clone git://github.com/creationix/nvm.git ~/nvm # . ~/nvm/nvm.sh # nvm install v0.6.14
最初にnvmをインストールしてからnode.jsをインストールする。nvm(Node.js Version Manager)するには、下記スクリプトで行う。
# curl -o- https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
or wget
# wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
これを行ったあと、環境設定ファイルに読み込まれるので、再ログインするか環境設定ファイルの読み直しを行わないと、コマンドは使えない。
# nvm ls-remote
このコマンドでインストールしたい node.js のバージョンを確認する。
# nvm install stable
これで最新の安定版がインストールされる。
切り替えたいバージョンをインストールして、use で切り替える。
# nvm install v8.12.0 # nvm use v8.12.0
基本バージョンを指定
# nvm alias default v10.11.0
# npm install -g yarn
ノード自体のバージョン確認
# node -v
ノードで利用されている V8 エンジンのバージョン確認
# node -e 'console.log(process.versions.v8)'
# git clone git://github.com/ry/node_chat.git # cd node_chat # node server.js
このツールは、サーバーで動くプログラムを、手元のブラウザを使ってステップ実行させることのできる遠隔デバッガーという認識が一番わかりやすいだろう。 参考
socket.ioは、主にサーバと、クライアントとの間にsocket(トンネルのイメージ)で繋げて、双方でデータを簡単にやり取りできる。(要はサーバーから、非同期にクライアントにデータが送れる。通常のWEBアプリでは、ページの更新タイミングでないとサーバからデータが取得できない)
# npm install socket.io
必要に応じて
# npm install -g websocket.io # npm install mysql
ポートIO(socket.io本体)の定義に、「.of('/name')」という行を複数設定することで、コネクションを振り分ける事ができるので、サーバープログラムを再起動し直すことなく、サーバー側の機能を増やしていく事ができる。(例:.of('/login') や、.of('/shopping')など画面毎や機能毎にわける)
’’SERVER''
var io = require('socket.io').listen(80); // chat画面用 var chat = io .of('/chat') .on('connection', function (socket) { socket.emit('a message', { that: 'only' , '/chat': 'will get' }); chat.emit('a message', { everyone: 'in' , '/chat': 'will get' }); }); // ニュース画面用 var news = io .of('/news') .on('connection', function (socket) { socket.emit('item', { news: 'item' }); });
CLIENT
<script src="http://localhost/socket.io/socket.io.js"></script> var chat = io.connect('http://localhost/chat') , news = io.connect('http://localhost/news'); chat.on('connect', function () { chat.emit('hi!'); }); news.on('news', function () { news.emit('woot'); });
セッションIDは、connection が張られた時に、クライアント毎にユニークな番号を自動的に作成することで、クライアントの識別が行える。
// セッションIDの人にのみメッセージを送るサンプル。 var io = require('socket.io').listen(80); io.sockets.on("connection", function (socket) { socket.on("message", function (data) { io.sockets.emit("message", {value: data.value}); // 全員にメッセージ io.sockets.socket(socket.id).emit('message', { value: data.value }); // 送った人のみ送信。 }); });
ver 0.7.x以降のsocket.ioでは、チャネル機能が搭載された。基本的にはnamespaceを使う事で、同様の機能は提供されるが、namespaceではコーディング時にグループが決定されている必要があり、ダイナミックなグルーピングには、チャネルが向いている。
io.set( 'transports', [ 'flashsocket', 'websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling' ]);
これは、下記のようなメッセージ用のdataオブジェクト変数を作る際に、
io.emit(message, data);
このdataを、初期処理で配列型にすると、後からの代入でもその後も配列型にされてしまい、データ送信ができなくなる。(一見すると同じに見える)
<送信出来ない例>
var data = []; data.param1 = "test"; data.param2 = "param2 etc";
<送信できる例>
var data = {}; data.param1 = "test"; data.param2 = "param2 etc";
Socket.io は、ブラウザとの通信に利用する場合などには、非常に便利ではあるが、スマホなどの組込みアプリから通信するには、socket.io 互換のライブラリが必要となる。(これは、socket.io で websocket を利用する設定しても、通常の websocket との親和性が低く、あまり使えない。)そのため、websocket ライブラリは大抵のスマホで、ライブラリがあるので、websocket ライブラリを使うのも良い。現在、node.js で websocket のライブラリは、2つあるが速度も含めてあまり大差がないので、このみで選んでも良い。(若干の機能の違いがあるが、一般的には考慮の必要はないだろう)
インストールは基本的に以下の形でよい。
# npm install ws
※ npm に、-g オプションをつけると正しく起動しない場合がある。
JavaのTomcatなどのアプリ管理を統括した、サーバープログラムと違い、nodeは只のインタプリタにしかすぎない。よって、アプリにバグや問題が合った時には、nodeごとプロセスが落ち、他のユーザーにも影響は発生する。またアプリ1ソケットという考え方のnodeでは、違うソケットを利用する、違うアプリは別々に起動するような概念が近い。逆説的には1つのアプリだけを起動する場合に利用するべきと考える。しかし、落ちたまま放置では問題がある場合が多く、その場合は、deamontools というプロセス管理ソフトと組み合わせると良い。
forever を利用し、node がバックグランドで起動し、落ちた場合も再起動されるようにする。
# npm install forever -g --unsafe-perm # forever server.js
# npm install pm2 -g # pm2 start server.js
<全停止>
pm2 stop all
<リロード>
pm2 reload all
# pm2 delete 0 <- 最後の数字は削除するタスク ID
# pm2 list
基本的に、deamontools のインストールは、deamontoolsのページで確認してもらうとして、ここではnodeとの組み合わせ時の設定を説明したい。
deamontoolsをインストールし、プロセスが起動していることを確認後、自動起動させるサービスを登録するために、以下のコマンドを入力する。
# cd /service # mkdir node;chmod +t ./node;mkdir ./node/log
NODE_PATH ... node modules がインストールされているパスの設定(通常設定不必要) NODE_ENV ..... リリース版(production)、デバッグ版(development)などの引数を渡したい時に主に利用。
環境変数の'PATH'を取得する方法。
var env = process.env; var path = env.PATH;
通信に利用するライブラリ
var io = require('socket.io')( 8080, { transport: 'flashsocket,websocket,htmlfile,xhr-polling,jsonp-polling' });
代わりにmiddlewareという概念が導入された。これは、ハンドウェイクから接続までの間に処理を入れることが出来る。 (0.9 の時は、set("authorization") で、似たような専用機能だったものを 1.0 では middlewareとして汎用化した) また middleware はnamespace単位。
下記は同じ意味(デフォルトネーム)また、すべてのクライアントは必ずデフォルトネームに最初に接続。
io.use( function( socket, next){} ); io.of('/').use( function( socket, next){} );
fooネームスペース
io.of('/foo').use( function( socket, next){} );
fooネーム空間へのアクセス方法(クライアント) var socket = io('http://localhost:8080/foo');
サイズが大きいものは不向き(データを一旦メモリに読み込むため)但し、前段にデータ分割などを入れれば可能かも。 <オブジェクトにバイナリの埋め込み>
socket.emit( 'bdata', { data: new ArrayBuffer( 10 )} );
<複数バイナリ>
socket.emit( 'bdata', [ binary1, binary2 ] );
flashsocket がサポートされなくなった。
var io = require( 'socket.io' ).listen(server, {transports:[ 'polling','websocket' ]});
再接続時にupgradeを再度行わない為のモード
rememberUpgrade: false
よってクッキーやセッションの復元が出来るように。
io.use( function( socket, next ){ console.log( socket.request ); next(); });
実態は只のブロードキャスト <実際にはredisアダプタが利用される>
var redis = require( 'socket.io-redis' ); io.adapter( redis( {host: 'localhost', port: 6379} ));
1.0 では標準でデバッグ出力しなくなった。よってアプリ起動時に出力レベルを決める。この場合*なので、全モジュール出力。
# DEBUG=* node myapp.js
httpなどのプロトコルを記入しないと、file:// になってしまう。
<クライアント>
socket = io.connect( "http://my-server.com/", options );
var util = require('util'); console.log( util.inspect( display_obj ) );
Eclipseの plugin install メニューから、以下のURLを入力しインストール。
http://chromedevtools.googlecode.com/svn/update/dev/.
Eclipseのメニュー、[File]-[New]-[Project]-[JavaScript]-[JavaScript Project]でプロジェクトの作成。
# node --debug-brk=5858 test.js <- 5858 はポート番号
eclipseのメニューから、[run] -> [debug configuration] でIPとPORTをしていして、debug ボタンで開始。
io.engine.clientsCount : クライアントの接続数 socket.request.cooki : cookie データの取得
<0.9以前>
io.sockets.socket(socket.id).emit( 'message', "message to client" );
<1.0以降>
io.to( socket.id ).emit( 'message', "message to client" );
という正体不明のエラーがでる。どうやら node.js を利用してindex.htmlなどを提供したあと、socket.io に接続すると、chromeでのみ発生する正体不明のバグ。firefoxでは発生しない。特にページにボタンが置いてあり、その上にマウスカーソルを移動させるだけで、このエラーのログがバンバン吐出される。(どうも、クロスサイトの認識あたりがあやしいような気配)
通常の webocket におけるポートの共有は、(nginxの場合)
location / { proxy_pass http://localhost:8000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
このような形での http アップグレートして proxy_pass で飛ばしてあげれば問題ないが、socket.io を利用しての接続の場合は、XHRやポーリングなどの他のプロトコルでの接続などもあるために、/socket.io/ という location が予約されているので、上記の location の部分を、
localtion/socket.io/ {
という形に変更してやることで、socket.io の、back proxy化が可能となる。
JavaScriptの変数スコープは、this問題と絡んでわかりづらいので、ここで簡単に説明する。また、一般的に説明されている、定義は関数範囲というのは、ここでは割愛する。
<読み込みファイル(MyFunc)内> var test; <- 外部から一切アクセス付加 var Myfunc(){ test = "only file inside" <- ファイル内だけのスコープ this.test = "instance value"; <- 下記で説明する new 後にアクセス可能 }
var Myfunc = require("MyFunc"); var my = new Myfunc(); my.test = "new word"; <- このように、this.test が操作可能
詳しくはhttp://qiita.com/takeharu/items/809114f943208aaf55b3ここ。
ただし、プロトタイプチェーンに関しては、http://d.hatena.ne.jp/cou929_la/20100929/1285770930ここを参照。
node用のパッケージ管理ツール。yarnなどもあるが今の所、npmが主流。
# npm init -y
# npm install <パッケージ名>
installコマンドでカレントフォルダの ./node_modules にインストールされる。(但し -g オプションの場合はグローバル環境に行われる)
オプション | 概要 |
-g | グローバル環境に追記され、コマンドパスも通る。 |
--save | package.json の dependencies に追記される。 |
--save-dev | package.json の devDependencies に追記される。 |
--save-optional | package.json の optionalDependencies に追記される。 |
package.json と package-lock.json の2つが作られる。基本は package.json に利用されるパッケージの環境情報に関する設定が記述されるが、package-lock.json にはパッケージ同士のバージョン依存が管理される。(package-lock.jsonは npm5 から採用された)
※下位モジュールでのpackage-lock.jsonは無視される。
package.json に明記される。dependencies(製品環境)には、製品用のパッケージ情報を記述し、devDependencies(開発環境) にはビルド時だけしか使われないようなツールやライブラリを記述されるのが一般的。また npm install オプションで、--production を指定すると、製品環境にのみインストールされる。
# npm install
パッケージ名を指定しないと、package.json に記述されているモジュールを自動的にすべて再インストールする。(Railsの bundle installと同じ)
パッケージ名に、「 - . _ 」 が利用されても無視して結合した文字列でパッケージ名のユニーク性を検証するため、package-code と、package_code、package.code などは、すべて packagecode というパッケージの扱いとなる。
また @scope/mypackage というように、@の次にスコープを指定できる。たとえば自分の組織名であったり、またはパッケージの所属するグループであったり、パッケージのhグループ分けと考えてよいだろう。/ の次は今までと同じパッケージ名となる。
これらのパッケージ名のルールは、増え続けるパッケージや類似品に対する規約のようなものとなる。ちなみに、ソースから参照する場合は
require('@scope/mypackage')
というように指定可能となる。
npmと一緒にインストールされる。npm install -g のように、-g オプションでインストールされたコマンドは、OSのパスに通されるが、環境汚染があるため -g を使わない場合に、個別プロジェクトにインストールされたコマンドが実行できる。
webpack-cli は webpackコマンドを利用するために必須インストール。 webpack-dev-server は
インストール
# npm install webpack-cli webpack-dev-server
webpackの設定ファイルは webpack.config.jsに記述される。最低限下記の設定は必要となる。(output で path を指定しないと、dist フォルダに出力される)
module.exports = { entry: "./src/main.js", output: { filename: "bundle.js" } }
開発用(source.map有)と製品用(minify)を mode で分ける。(webpack4 からの機能)
module.exports = { mode: "development", <- "production"だと製品版 devtool: 'source-map' <- sourcemapファイル(.map)を作成する。 }
webpackの設定ファイルを作成しなくとも
# npx webpack src/main.js dist/bundle.js
のように指定することは可能。
webpack よりも簡単にビルドできる。ビルド後自動的に web サーバーが起動する。
# parcel index.html
このようにTOP htmlを指定するだけで、ソースを解析して関係するファイルをまとめてくれるため、設定ファイルが必要無い。
オプション | 概要 |
-p | 開発用webサーバーのポート番号指定 (初期値は1234) |
watch | HMR(hot module replacement)のみ。開発用webサーバーは起動しない |
build | 本番環境向けのバンドルのみ行う。HMR, 開発用webサーバーは起動しない |
これも webpack のように、./dist フォルダにビルドファイルが保存される。
※厳密には parcel にも package.json に設定を記述して細かい設定ができるようである。
簡単なテストにすぐに使えるWEBサーバー
# python -m SimpleHTTPServer 8888
起動したカレントフォルダ直下をルートディレクトリとして起動する。
# ./autogen.sh # ./configure <- arm用の場合 --host=arm # make # make install
# git clone https://chromium.googlesource.com/external/gyp # python setup.py install
# vi nginx.conf upstream web_sockets { ip_hash; <- これが無いと接続時同じサーバーにならない。 least_conn; server host01:9090 weight=5; server host02:9090; <- 複数記述でロードバランス } server { location /ws { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass http://web_sockets; proxy_cache_bypass $http_upgrade; <- これで http を、websocket対応に。 proxy_read_timeout 24h; <- これを付けないと 60秒で勝手に切断される。 } }
<nginx.confのproxyに以下を追加>
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
<node.js側で>
var ip = req.headers["x-forwarded-for"];