Node.js = サーバーサイドプログラミング?
最近Node.jsの勉強を始めたので、Node.jsの概要や全体像について、学んだことを記録していく。
どうもNode.jsは、自分が当初抱いていたイメージよりも、かなり広くて深い概念のような気がする。
当初、Node.jsは単にサーバーサイドプログラミングのための道具だと思っていた。JavaScriptでサーバーサイドプログラミングをするための道具。
だがどうやら、そういうものではないようだ。もっと広い概念に思えてきた。
JavaScriptそのものの機能を拡張するもの、そんな印象を受ける。
だから、サーバーサイドは別の言語で行い、クライアントサイドでのみJavaScriptを使うのだとしても、Node.jsは知っておいたほうがよさそうに思える。
ネット上の記事(主にQiita)を眺めているうちに多少は輪郭が見えてきたので、自分の知識を整理し、記録しておくための備忘録としてまとめておく。
JavaScriptに足らなかったもの
従来のJavaScriptに不足していた機能の一つに、モジュール機能がある。
プログラムのなかで、他のファイルを読み込む機能。JavaScriptではこの機能がサポートされていなかった。
他にもJavaScriptには欠点があり、それを解決するためのプロジェクトとして、CommonJSが始まった。
CommonJSについては説明するのが難しいらしいのだが、乱暴に言ってしまえば、JavaScriptの仕様のことらしい。
そしてこのCommonJSによって、ついにJavaScriptでもモジュール機能が使えるようになった。
つまりCommonJSは、JavaScriptをもっとイカした言語にしようとするプロジェクトであり、その一環として、モジュール機能を実現させたというわけだ。
だがCommonJSはあくまでも仕様に過ぎない。
その仕様に沿って実装されたのが、Node.jsである。そのため、Node.jsではモジュール機能が使える。
とはいえ現在のNode.jsは独自に拡張されており、CommonJSには準拠していないらしい。
モジュールとnpm
CommonJS、そしてNode.jsのおかげで、実際にJavaScriptでもモジュール機能が使えるようになった。
具体的には、exports
したものを、require()
で読み込めばいい。詳細は後述する。
自分が作ったモジュールはもちろん、最初からNode.jsに備え付けられているモジュールや、第三者が作成し配布しているモジュールも使える。
最初からNode.jsに備え付けられているモジュール
http
やfs
などがあり、標準モジュールと呼ばれる。特別な手続きをすることなく、require()
で読み込んで使える。
参照:Node.js API - 標準モジュール | プログラマーズ雑記帳
第三者が作成し配布しているモジュール
クライアントサイドJavaScriptにも、jQueryなどのライブラリが色々とあるが、それのNode.js版、という感じだと思う。
これを利用するためには、npmというツールを使う必要がある。
npmは最初からNode.jsに備え付けられており、これを使うことで、配布されているモジュールのインストールや管理が行えるようになる。
npmについてはあまりよく分かっていないので、別途調べる。
Browserify
Node.jsは、サーバーサイドのための言語であり、ブラウザからではなくターミナルから実行する。
しかし、せっかくモジュール機能という便利なものがJavaScriptで使えるようになったのだから、ブラウザ、つまりクライアントサイドJavaScriptでも、モジュール機能を使えるようにしたい。
そこで使うツールが、Browserifyである。
まず、Node.jsと同じように、何も意識せずにモジュール機能を使う。
だがそのままでは当然、利用できない。
だがBrowserifyを使えば、書いたコードをブラウザでも実行できる形に変換することが出来る。
つまり、Browserifyを使うことで、ブラウザでもモジュール機能を使えるようになるのだ。具体的な使い方は後述する。
C言語で記述したものを機械語にコンパイルするイメージ。Browserifyが、コンパイラの役割を果たす。
実際に使ってみる
まずはモジュール機能をNode.jsで使ってみる。次に、それをブラウザでも使えるようにするため、Browserifyを導入し利用する。
モジュール機能
まず、モジュールとして取り込みたい機能を作り、それをexports
する。
今回はサンプルとして、受け取った文字列の最後に(笑)をつける関数を作成する。
この関数をlaughingと名付け、lol.jsというファイルに保存する。
// lol.jsの中身 var laughing = function(string){ string = String(string); string += '(笑)'; return string; }; exports.laughing = laughing;
そしてそれを取り込む側のファイル(今回はmain.js)で、require()
を使って読み込む。
// main.jsの中身 var lol = require('./lol'); var result = lol.laughing('test'); console.log(result);
そしてNode.jsでmain.jsを実行すると、test(笑)
と表示され、モジュールがきちんと機能していることが分かる。
Browserify
だがこのままでは、Node.jsでは動いても、ブラウザでは動かない。
main.jsをブラウザで実行しようとすると、エラーになる。
<!DOCTYPE html> <html lang="ja"> <head> <title>browserifyのテスト</title> </head> <body> <script type="text/javascript" src="main.js"></script> </body> </html>
main.js:1 Uncaught ReferenceError: require is not defined
なので、Browserifyを使ってブラウザでも解釈できる形にコードを変換していく。
まずはnpmを使ってBrowserifyをインストールする。
余談だが、このインストールで躓いた。
色々試したが、Browserifyがインストールできないというより、そもそもグローバルインストールが出来ないようだった。
npmによるモジュールのインストールは、個別のディレクトリにインストールしていく方法と、システム全体にインストールする方法であるグローバルインストールがあり、Browserifyは後者にあたる。
調べてみると、権限がないために、グローバルインストールの際に行われるディレクトリの作成に失敗しているようだった。
そのため、sudo
でグローバルインストールを行ったら、成功した。
参照:npm installでError:EACCESがでたら - Qiita
インストールできたら、さっそく使ってみる。
require()
を使っている側のファイル(今回はmain.js)をBrowserifyで変換し、それを新しいファイル(今回はbuild.js)として出力する。
以下のコマンドで出来る。
browserify main.js -o build.js
そうすると、次のようなbuild.jsが出来る。
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var laughing = function(string){ string = String(string); string += '(笑)'; return string; }; exports.laughing = laughing; },{}],2:[function(require,module,exports){ var lol = require('./lol'); var result = lol.laughing('test'); console.log(result); },{"./lol":1}]},{},[2]);
これを、先ほど作ったhtmlで、main.jsの代わりにbuild.jsを読み込ませると、上手く機能していることが分かる。
<!DOCTYPE html> <html lang="ja"> <head> <title>browserifyのテスト</title> </head> <body> <script type="text/javascript" src="build.js"></script> </body> </html>
build.js:15 test(笑)
このように、Browserifyを利用することで、クライアントサイドJavaScriptでもモジュール機能を使えるようになる。
そして、BrowserifyはNode.jsによって提供されている。Browserifyを利用するためには、Node.jsや、そのパッケージ管理ツールであるnpmが必要になるのだ。
そしてBrowserify以外にもクライアントサイドの開発を楽にしてくれるツールが色々とあるらしい。
だからこそ、サーバーサイドはJavaScript以外で書くつもりでありNode.jsを使う予定はないのだとしても、Node.jsをインストールしておいたほうがいい。このような便利な機能を使えるようになるのだから。
このような背景があるため、Node.jsに対して、単なるサーバーサイドの言語ではなく、JavaScriptそのものを拡張するものであるような印象を受けたのだ。