2014/06/03

express.jsでconnect-assetsを使う。

Railsには、asset pipelineという仕組みがあって、クライアントサイドのcoffeescriptやsassのソースを結合・圧縮してクライアントに配信することができるけど、node.js + express.jsのアプリケーションでは、同じようなことができないかな、と思って調べてみた。

connect-assets

すると、connect-assetsというライブラリを発見した。connect-assetsのREADMEに、"Transparent file compilation and dependency management for Node’s connect framework in the spirit of the Rails 3.1 asset pipeline."とあるように、Rails3.1で導入されたasset pipelineの仕組みをnode.jsのconnectフレームワーク上で実現するライブラリのようで、asset pipelineのように、分割されたjavascriptファイルやcssファイルを結合・圧縮してくれる。ソースがcoffeescriptやless、stylus、sassなどを使って書かれている場合でも使える。

mincer

connect-assetsは、内部でmincerを使っている。 mincerは、Railsのasset pipelineで使われているsprocketsのjavascriptポーティングライブラリ。 mincerの提供する構文に従って依存するライブラリを記述すると、それらをすべて結合したファイルを生成してくれる仕組みを提供する。 mincerは、内部でjavascriptの圧縮、cssの圧縮を行う。 ソースがcoffeescriptや、less、stylus、sassなどで書かれている場合は、コンパイルした上で圧縮することもできる。 connect-assetsのデフォルトだと、mincerに対して、Javascriptの圧縮器としてuguify-jsを、cssの圧縮機としてcssoを指定している。

使ってみる。

というわけで、connect-assetsを使ってみた。環境は、

  • node.js 0.10.28
  • express.js 4.2.0
  • connect-assets 3.0.1

インストール

npmでインストール。

$ npm install connect-assets --save
$ npm install less --save

cssにlessを使っているので、lessもインストールした。(less-middlewareは使わない。)

app.jsの記述

app.jsにconnect-assetsの設定を書く。 ↑のpathsには、ソースファイルのパスを指定する。 assets/jsはjavascriptのソースディレクトリ、assets/cssはCSSのソースディレクトリ(lessファイルもココに置いている)、componentsはbowerでインストールしたパッケージ群が入っている前提。 buildDirは、コンパイル・結合・圧縮後のファイルの出力ディレクトリ。

依存関係の定義

connect-assetsを使う上にあたり、mincerが理解できる形式で依存関係を定義したファイルを作成する必要がある。 mincerに対する依存関係の指定は、次のようなファイルで行う。

HTML(jade)側はどうするか?

HTML(jade)側で、connect-assetsが出力するファイルを参照するために、jadeファイルで次のコードを書く必要がある。

buildの有無

app.jsのconnect-assetsに対する設定で、buildオプションを指定することで、build(=結合・圧縮)の有無を変更できる。
デフォルトだと、

  • 開発環境では、build無し
  • 本番環境では、build有り
というオプションとなっている。この開発環境や本番環境は、NODE_ENVで切り替える。

2014/05/06

express.jsなプロジェクトでbowerを使ってパッケージを管理する。

bowerというパッケージ管理ツールがある。これは、Webサイト構築時に利用する様々なJavascriptやらcssといった外部のリソースを、パッケージとして管理するためのオープンソース。例えば、jQueryのバージョンが上がったからダウンロードしなくちゃとか、このライブラリはどこから持ってくればいいのか、とか、どこのディレクトリに配置すればいいの?とか、一度決めてしまえばそれでいいのだろうけど、bowerを使ってbowerの振る舞いに乗っかることで、外部のリソースに関する管理の手間が省けそう。

以前「node(express.js)でbootstrap3を使う、npmで簡単に。」を書いた際に、終わりの方に課題として、 ”bootstrapのJavascriptはどうすんのさ? これを楽する方法がまだわかっていませんorz。 node_modules/twitter-bootsrap-3.0.0の中にあるjsファイルをpublic/javascripts配下にコピーして使っているけど、これは今後の課題です。” と書いたけど、コレ対する解にもなる。

bowerの使い方。

bowerの基本的な使い方は簡単で、npmとかgemとか使ったことのある人なら、すぐに使えると思った。具体的な使い方は、↓のリンクが参考になります。

express.jsなプロジェクトでbowerを使う。

express.jsだとサーバーサイドで使うライブラリは、packages.jsonに書いてnpmで管理するのが基本的なパッケージ管理手法と思ってる。で、bowerはクライアントサイドで使うJavascriptやらを管理するために使う、ってことになる。

express.jsなプロジェクトにbowerを適用する。

bowerを適用するには、

$ cd express_project_root
$ bower init
を実行する。bower initは、最終的にbower.jsonを出力コマンドで、いくつかの設定を対話的に入力していく。実際のbower.jsonは、
{
  "name": "プロジェクト名",
  "version": "0.0.0",
  "homepage": "プロジェクトページヘのURL",
  "authors": [
    "名前 <メールアドレス>"
  ],
  "moduleType": [
    "node"
  ],
  "license": "MIT",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "components",
    "test",
    "tests"
  ],
}
のようになり、bowerでパッケージを管理する準備が出来た状態。

パッケージをインストールする。

例えば、jqueryを使うとする。bowerでインストールするには、

$ bower install jquery --save
とすると、プロジェクトルートにbower_componentsというディレクトリが生成され、その下にパッケージがインストールされる。また、--saveオプションを指定することで、bower.jsonに書き込まれる(この仕組みは、npmと同じですね。)。
.
├── app.js
├── bin
├── bower.json       # <= jqueryへの依存が定義される。
├── bower_components # <= この配下にパッケージがインストールされる。
├── node_modules
├── package.json
├── public
├── routes
└── views
したがって、npmやgemと同じ要領で、予め利用するパッケージがわかっているときは、bower.jsonにつらつらと書いてから、bower installすればいいし、後から利用するパッケージを増やす時は、bower install package_name --saveとすれば良さそう。

パッケージのインストール先をbower_componentsを以外にする。

bowerはデフォルトで、./bower_components配下にパッケージをインストールする。このままだと、ビューでJavascriptを読み込むのに、bower_components/jquery/dist/jquery.min.jsとかがscriptタグのsrc属性に登場することになるけど、bower云々がクライアント側のコードに出てくるのは避けたいので、インストール先のディレクトを変えてみる。具体的には、

$ less .bowerrc
{
  "directory": "components",
  "json": "bower.json"
}
というファイルを作って、"directory"を指定する(ここでは、componentsというディレクトリ名にしている)。そして、このディレクトをexpress.jsにスタティックなコンテンツを含むディレクトリであることを教えてあげれはよい。app.jsに↓を追記する。
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'components'))); // <= コレを追記する。

2014/04/24

three.jsで球を円運動させて太陽系の惑星を描いた。

three.jsの勉強中、単純なオブジェクトを円運動させる方法を知りたくて、それなら調べながら、太陽系の惑星たちの公転運動を描いてみようと思い至った。

球を描く

惑星なのでほぼ球だろう、ということでthree.jsが提供してくれているオブジェクトを使って、太陽と水星〜海王星までを球として表現してみた。3Dのオブジェクトを作るには、Geometry、Material、Meshの3つを使うのが基本だと思っていて、今回各天体を球として表現するのに、

  • THREE.MeshLambertMaterial
  • THREE.SphereGeometry
  • THREE.Mesh
の3つを使った。で、太陽をJavascriptのオブジェクトとして、↓のように書いてみた。
Sun = function() {
  this.material = new THREE.MeshLambertMaterial({ color: 0xff0000 });
  this.geometry = new THREE.SphereGeometry(109, 64, 64);
  this._mesh = new THREE.Mesh(this.geometry, this.material);
}

Sun.prototype = {
  constractor: Sun,
  get mesh() {
    return this._mesh;
  }
}
この太陽を3D空間に配置するには、
var sun = new Sun();
scene.add(sun.mesh);
とすればいい、と。

惑星は、Planetっていうオブジェクトをprototype継承させて個々の惑星を作ってやった。Planetは、

Planet = function(radiusRate, orbitalRadiusRate, color, omegaRate) {
  this.radiusBase = 4;
  this.orbitalRadiusBase = 400;
  this.radiusRate = radiusRate !== undefined ? radiusRate : 1.0
  this.orbitalRadiusRate = orbitalRadiusRate !== undefined ? orbitalRadiusRate : 1.0;
  this.color = color !== undefined ? color : 0x0000ff;
  this._omegaRate = omegaRate !== undefined ? omegaRate : 1;

  this._material = new THREE.MeshPhongMaterial({ color: this.color });
  this._geometry = new THREE.SphereGeometry(this.radiusBase * this.radiusRate, 64, 64);
  this._mesh = new THREE.Mesh(this._geometry, this._material);
  this._mesh.position.x = - this.orbitRadiusBase * this.orbitalRadiusRate;
  this._mesh.position.z = - this.orbitRadiusBase * this.orbitalRadiusRate;

  this._circleGeometry = new THREE.CircleGeometry(this.orbitalRadiusBase * this.orbitalRadiusRate, 2560);
  this._circleGeometry.vertices.shift();
  this._circleMaterial = new THREE.LineBasicMaterial({
    color: 0x111111
    // opacity: 0.1
    // linewidth: 0.01
  });
  this._circle = new THREE.Line(this._circleGeometry, this._circleMaterial);
  this._circle.rotation.x = 90 * Math.PI / 180;
};

Planet.prototype = {
  constractor: Planet,
  get material () {
    return this._material;
  },
  get geometry () {
    return this._geometry;
  },
  get mesh () {
    return this._mesh;
  },
  get circle() {
    return this._circle;
  },
  pivot: function(time) {
    var theta = 1.047 / this._omegaRate * time;
    this._mesh.position.x = Math.cos(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
    this._mesh.position.z = Math.sin(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
  }
};
のようなオブジェクトになった。コンストラクタの引数radiusRateorbitalRadiusRateは、それぞれ地球の半径を1として何倍か、地球の公転軌道半径を1として何倍か、を指定するようにした。それと、omegaRateっていうのは、地球の公転の角速度(rad/s)を1として何倍か、を指定するもので、公転運動の処理で使ってる。さらには、一応公転軌道(=円)を3D空間に表示しようと思って、circleっていう属性を定義した。円を描くのも、例のGeometry,Material,Meshの3点セットが必要だけど、three.jsは円に特化したオブジェクトを定義していて、実際に使ったのは、
  • THREE.CircleGeometry
  • THREE.LineBasicMaterial
  • THREE.Line
の3つ。これもsceneに追加してあげないと表示されないから、例えば、地球は、
Earth = function() {
  Planet.call(this, 1.0, 1.0, 0x0000ff, 1.0);
};
Earth.prototype = Object.create(Planet.prototype);
というオブジェクトを書いて、
var earth = new Earth();
scene.add(earth.mesh);
scene.add(earth.circle);
としてあげた。

円運動

円運動は、単位時間あたり何ラジアン進むか、が重要。で、今回は試しに1年を1分に見立てて色々と計算してみた。つまり、地球は1分かけて太陽の周りを1周する。その場合の地球の角速度は1.047(rad/sec)になった(あってます?)ので、これを使って瞬間瞬間の座標を計算してオブジェクトの位置を変えていけばよさそうだ、と。

で、今回のは、y=0平面上で公転させるってことにすると、xとzの値を時間と角速度と半径から求めることができるなぁ、と思い、結果出来たのが上述のPlanetオブジェクトのpivotというメソッド(↓再掲)。

pivot: function(time) {
    var theta = 1.047 / this._omegaRate * time;
    this._mesh.position.x = Math.cos(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
    this._mesh.position.z = Math.sin(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
  }

実際に動かしてみる

実際に動くページをThe Solar System 3Dで公開しました。マウスでグリグリ、コロコロできたり。とりあえず、当初の目的であった、オブジェクトを円運動させる方法はわかったので良かった。

2014/03/30

node(express.js)でcsrf対策する。

node(express.js)でcsrfに対する対策を施す方法について書いてみる。といっても、express.jsはcsrf対策のためのミドルウェアを提供しているので、その使い方の話。(ここで使っているexpress.jsのバージョンは3.4.8です。)

express.jsのcsrfミドルウェア

express.jsが提供するミドルウェアに、csrf っていうのがあってコレを使うと簡単にcsrf対策ができる。

使い方 - app.js

expressコマンドでアプリケーションを作ると、app.jsというファイルが出来て、この中にアプリケーションやサーバの設定を書くんだけど、その中で次のコードを書く。

// use session support.
app.use(express.session());

// use csrf middleware.
app.use(express.csrf());
app.use(function(req, res, next) {
  res.locals._csrf = req.csrfToken();
  next();
});
前述のこのページにあるとおり、csrfミドルウェアを使うには、session()よりも下に書けってあるので、注意が必要。

使い方 - view

csrfミドルウェアが生成してくれるトークンをformに埋める必要があるので、viewでformを書くときには、

form(action='/some_action', method='form')
  input(type='hidden', name='_csrf', value='#{_csrf}')
  :
のように、hiddenに_csrfのトークンを埋めておく。(これはテンプレートエンジンにjadeを使った場合の例)

これで、postなリクエストにcsrfトークンが含まれていなかったり、不正なトークンが含まれていると、expressが検出してエラーを上げてくれるようになる。

2014/03/23

twitter-bootstrapを使う時のベーシックなlayout.jade

twitter-bootstrapをexpressjsなアプリに適用するにあたって、jadeのレイアウト(layout.jade)にbootstrapのcssとjavascriptを埋めます。ベーシックなレイアウトをgistに上げました。