前置き(Node.jsの前に)
プログラミング言語について
エンジニアの皆さんは、どのプログラミング言語をお使いでしょうか?
よく挙げられるのがNativeコードを吐き出すCPP、Objective-C、バイナリコンパイル型のC#、Java、 LLのPython、PHP、Ruby、Perlあたりだと思います。 最近だと、SwiftやGo lang等も候補にあがりそうです。
それでは、JavaScriptはどうでしょうか?
がちがちのサーバサイドアプリケーションエンジニアや、
インフラ・ネットワーク・データベース・セキュリティ専業エンジニア以外のアプリケーションエンジニアの大多数の方は、この言語を使って、コードを書いた事があると思います。
「JavaScriptはプログラミング言語じゃないよ」という方もいらっしゃるかもしれませんが、 私は、JavaScriptは立派なプログラミング言語であり、非常に汎用的、かつ将来性のある言語だと思いますし、 一番好きなプログラミング言語でもあります。
最近では、JavaScriptを中心に組むWeb Front-end Engineerという職種もあり、 もりもりJavaScriptを駆使して、Webのフロント側を作っている専業の方もいる程です。
JavaScriptについて
元々のJavaScript
そもそもJavaScriptは、かなり昔にNetscape社がクライアントのWebブラウザ内で、 決められた動的な制御を実行するために、策定された言語です。
当初はクライアントマシンも非力で、実行エンジンも良いものではなく、 APIも少なく、使いにくかったので、かなり限定的な使い方しか出来ませんでした。
しかし、ブラウザ内で動くというのはかなり画期的で、Netscapeの動きを見て、
ライバルのMicrosoftがInternet Explorer(IE)に慌てて同様の機能を盛り込んでリリースしました。
※ 余談ですが、IEに盛り込んだJavaScriptは、正式名称はJavaScriptという名称ではなくJScriptという、JavaScriptの方言の1つです
しかし、IEのJScriptが独自拡張や、互換性のない記述をしていたり、 言語仕様が一致しない等、利用する上で、かなりの苦労がありました。
Mozilla主導による言語仕様の統一化の動き
そのようなカオスなJavaSciprtの世界に統一化の動きを見せたのが、Firefoxの開発元Mozillaです。 Mozillaは仕様化されていなかったJavaScriptの統一化を目指し、 JavaScriptの統一仕様として、GoogleやAdobe等とともにECMAScriptを主導していきました。
今日提供されているブラウザでは、ECMAScriptに準拠して作られており、
JavaScriptの記述方法やAPIにもかなりの互換性があります。
※採用しているECMAScriptのVersionの違いはあります
また、クライアントマシンのマシンパワー向上、JavaScript実行エンジンの最適化、 AJAXによる、非同期通信を用いた動的なページの更新も、JavaSciprtの地位を押し上げました。
Node.jsへの流れ
このようにJavaScriptは使いやすくなり、非常に汎用的、将来性のある言語となりました。
汎用的や将来性につきましては、別に機会がありましたら記載しようと思いますが、 今回は、クライアントサイドで動くJavaScriptではなく サーバサイドあるいは、スタンドアローンアプリとしても動くNode.jsについて、ご紹介しようと思います。
Node.js
Node.jsとは何か
Node.jsを一言で言うと、JavaSciprt言語を駆使してコードを動作させるスクリプティングエンジン環境です。要は、LLと非常に似ています。というよりも、ほぼLLです。
Node.jsならではのメリットを挙げますと、
- 記述言語が、JavaScriptなので、Web Front-end EngineerやDesignerの人も修得が用意
- 既存のJavaScriptが流用可能
- 但し、条件ありで、元々の記述次第で、流用度がかなり変化します
- デフォルトのAPIがかなり豊富
http://nodejs.jp/nodejs.org_ja/api/
※ 暗号化(Crypto)、ネットワーク(Net)、圧縮伸長(Zlib)等、他のLLではオプションや拡張扱いのものもデフォルトで利用可能
※ Web APIの待ち受けも、Apache・IIS・nginx等のWebサーバなしで、簡単に作成可能です
- サーバサイドでも動かせるが、クライアントサイドで、スタンドアローンアプリやスクリプトツールとしても動かせる
- 公式純正のパッケージマネージャーがデフォルトで提供(Node Package Manager[npm])されていて、かなり高機能かつ使いやすい
- 他のLLには公式純正かつデフォルトで付いてくるパッケージマネージャーは存在しない
(デファクトスタンダードならある。Python pip、PHP Composer、Ruby Rubygems、Perl CPAN)
- 他のLLには公式純正かつデフォルトで付いてくるパッケージマネージャーは存在しない
- 豊富なライブラリやフレームワークがある
- Electron(旧ATOM Shell)、nw.js(旧Node-Webkit)、Express、Meteor、moment.js(これはNode.js専用という訳ではない)、node-fs-extra(スタンドアローンアプリ作成に非常に使える)等、他多数
ライブラリやフレームワークについては、機会があれば、またご紹介したいと思います。
Node.jsダウンロード
以下の公式サイトにアクセスして下さい。
https://nodejs.org/en/download/stable/
Windows・Macなら公式バイナリやインストールファイルを落として、実行するだけで簡単に動作可能です。
Linuxのバイナリは、最近のディストリビューションなら、大抵展開して、パスを通せば実行可能です。
ソースコードも提供されていますので、Mac以外のUnix環境、FreeBSDやNetBSD等でも、ビルドできます。
※ 公式からのダウンロード以外にも、Homebrew、yum、aptget、Nuget経由でのインストールする方法もあります
Node.jsインストール
前提
ここからは、Mac OS X環境前提で説明していきます。
インストール
上記でダウンロードしたMac用のインストールファイルをクリックして、インストール
https://nodejs.org/en/download/stable/
Mac OS X Installer (.pkg) 64-bit
node-v5.10.1.pkg
長期運用に使う場合は、LTS版がおすすめですが、大抵は、最新のStable版で良いと思います。今回も最新のStable版 v5.10.1で試します。
後は、以下の順に画面を進めていけば導入可能です。
最近のバージョンは、インストール時に以下の場所にPATHを通してくれるので、そのままターミナルで実行できます。
Node.js was installed at /usr/local/bin/node npm was installed at /usr/local/bin/npm Make sure that /usr/local/bin is in your $PATH.
ターミナルで、以下コマンドを入力すると、バージョン情報が表示されると正しく導入されています。
MacBook-Pro:~ spookies$ node -v v5.10.1 MacBook-Pro:~ spookies$ npm -v 3.8.3
次に、http簡易サーバを作ってみます。
MacBook-Pro:~ spookies$ mkdir -p src/nodejs/ MacBook-Pro:~ spookies$ cd src/nodejs MacBook-Pro:~ spookies$ vim http.js MacBook-Pro:~ spookies$ cat http.js const http = require('http’); const hostname = '127.0.0.1’; const port = 3000; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hoge Nyanko\n’); console.log('Client request!'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); }); MacBook-Pro:~ spookies$ node http.js Server running at http://127.0.0.1:3000/
最後のコマンドで、作成したソースをNode.jsで実行すると、
「Server running at http://127.0.0.1:3000/」と表示されます。
これは、127.0.0.1のホスト名と、ポート3000番でサーバを待ち受けており(待機状態で)、
クライアント側(ブラウザ)からアクセスすると、server側の処理が実行されます。
クライアント側(ブラウザ側)には、 200番ステータス(リクエスト成功)+テキストのコンテンツ属性+「Hoge Nyanko」 という文字列が返されます。
また、今回は、ターミナルから、直に実行しましたが、Service化やDaemon化、
nginx等のWebサーバと連携し、
ポートやServer側での処理を駆使すると、同時に幾つものリクエストを捌く事も出来、
Node.jsのサーバから、Node.jsのサーバも初期で提供されているAPIでリクエスト・レスポンスが可能ですので、
まさしく名前の通り、ノードとして振る舞わせる事も出来ます。
サンプルソース2(スタンドアローンスクリプト)
上記では、サーバサイドの例を記載しましたが、次はターミナルでコマンドを実行すると、 クライアント内で、特定の処理を実行するコードを例としてあげてみます。
以下は、コマンドライン引数で、バックアップ元のディレクトリ・バックアップ先のディレクトリ・ファイル名の3つを指定して、zip圧縮する例です。
サードパーティ製のモジュールとして、zip圧縮するモジュールもありますが、 ここでは、簡略化の為、MacのOSコマンドzipで代用します。
ソースコードは以下となります。
$ cat backup.js const fs = require('fs'); const path = require('path'); const process = require('process') const child_process = require('child_process'); function isDirectory(pathName) { // ファイル存在チェック var isExist = fs.existsSync(pathName); if(isExist) { // ディレクトリかどうか var isDir = fs.statSync(pathName).isDirectory(); if(isDir) { return true; } else { console.log(pathName + ' is not directory'); return false; } } else { console.log(pathName +' is not directory or file.'); return false; } } // from -> to/zipにzip圧縮する function backup(from, to, zip){ var fromDir = path.dirname(from); var fromBase= path.basename(from); console.log('cd ' + fromDir); process.chdir(fromDir); // MacでのOSコマンドzipのコマンド文を生成(多分、最近のLinuxでも使える) var exeCom = 'zip -r ' + to + '/' + zip + ' ' + fromBase; console.log('[Exec] ' + exeCom); var result = require('child_process').exec(exeCom, function(err, stdout, stderr) { if (!err) { console.log(stdout); } else { console.log(err); } }); return true; } // 引数チェック if (process.argv.length != 5) { console.log('Usage: ' + process.argv[0] + ' ' + process.argv[1] + ' from_directory_name to_directory_name zip_file_name'); console.log('For example: node ' + process.argv[1] + ' ~/dat/from =/dat/to backup.zip'); return; } // 引数の内容を受け取る var from = process.argv[2]; var to = process.argv[3]; var zipName = process.argv[4]; if(isDirectory(from) && isDirectory(to)){ backup(from, to, zipName); } else { console.log('Error!'); }
実行は、以下のコマンドで実行して下さい。
MacBook-Pro:~ spookies$ node backup.js from_directory_name to_directory_name zip_file_name
実行すると、「from_directory_name」ディレクトリをzip圧縮し、 「to_directory_name」ディレクトリに「zip_file_name」の名称でzip圧縮します。
まとめ
このようにNode.jsは、今後も将来性があり、サーバサイド・クライアントサイド問わずプログラムが作れますので、
皆様も是非活用してみてください。
Let's enjoy Node.js!