ラベル express の投稿を表示しています。 すべての投稿を表示
ラベル express の投稿を表示しています。 すべての投稿を表示

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/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に上げました。

2014/03/14

node(express.js)でbootstrap3を使う、npmで簡単に。

express.jsを使ったnodeなWebアプリを作っていて、twitter-bootstrap使いたいな、と思った。かつて、bootstrap2の頃、本家からダウンロードして、cssとjavascriptをpublicに置いてできたー、とか思ったこともあったけど、npmとかないのかな?って思って探したらあった、じゃあ使ってみよう、という話です。

less-middlewareとtwitter-bootstrap-3.0.0

今回使ってみたのは、

の2つです。 less-middlewareは、express.jsがデフォルトで使用するメタCSS。twitter-bootstrap-3.0.0は、自分でpackage.jsonに書いてインストールしましたよ。
{
  "name": "appname",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.4.8",
    "jade": "*",
    "less-middleware": "*",
    "twitter-bootstrap-3.0.0": "*",
    :
  }
}

app.jsでless-middlewareの設定を書く。

twitter-bootstrap-3.0.0がインストールできたらば、app.jsに手を入れます。
いろいろとmiddlewareの登録をしている部分で、 var bootstrapPath = path.join(__dirname, 'node_modules', 'twitter-bootstrap-3.0.0');

app.use(require('less-middleware')({
  src:    path.join(__dirname, 'assets', 'less'),
  paths:  [path.join(bootstrapPath, 'less')],
  dest:   path.join(__dirname, 'public', 'stylesheets'),
  prefix: '/stylesheets'
}));
のようにless-middlewareを登録します。この記述は、
  • lessのソースは、assets/less配下に置く。
  • bootstrapPathの下のlessもlessのコンパイル対象に含める。
  • コンパイルして出来たcssファイルは、public/stylesheets配下に置く。
  • prefixは、lessのページに"Path which should be stripped from the public pathname."とあるけど、イマイチよくわかっていません。
という具合になります。
これで、bootstrapのlessはnpmに任せられるようになります。bootstrapをカスタマイズするには、assets/lessの下の自前lessファイルに書いていけば、カスタマイズできる、と。

2014-03-16追記

less-middlewareのバージョンが上がると、上述のオプションの指定の仕方が変わるそうで。 Migration 0.1.x 0.2.0 · emberfeather/less.js-middleware Wikiに詳しい説明がありますね。0.2.1-betaっていうのが今の時点で使えて、上の指定をするとエラーとなるので、次のように直したら、うまくいった。

var less = require('less-middleware');
var bootstrapPath = path.join(__dirname, 'node_modules', 'twitter-bootstrap-3.0.0');

app.use(less(path.join(__dirname, 'assets', 'less'),
             { dest: path.join(__dirname, 'public'),
               preprocess: {
                 path: function(pathname, req) {
                   return pathname.replace('/stylesheets', '');
                 }
               }
             },
             { paths:  [path.join(bootstrapPath, 'less')] }
            ));

bootstrapのJavascriptはどうすんのさ?

これを楽する方法がまだわかっていませんorz。
node_modules/twitter-bootsrap-3.0.0の中にあるjsファイルをpublic/javascripts配下にコピーして使っているけど、これは今後の課題です。

2014/01/07

express.jsで自作faviconを使用する。

express.js

express.js では、デフォルトでexpress.js自身が提供するfaviconを配信するよう、コードが自動生成される。具体的には、express.jsが提供するアプリケーションのひな形を生成するコマンドを、

 $ express 
のように実行すると、
  • app.js
というファイルが生成され、
:(略)

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('less-middleware')({ src: path.join(__dirname, 'public') }));
app.use(express.static(path.join(__dirname, 'public')));

:(略)
というコードが出力される。上記の、
express.favicon()
が、デフォルトのfaviconの使用を定義するコード。

express.favicon()

express.favicon()は、nodeアプリのためのミドルウェアで、connect というのがあって、こいつが提供する機能の1つ。詳しくは、ここにドキュメントがあった。読むと、

By default serves the connect favicon, or the favicon located by the given path.
とあるので、デフォルトだとconnectのfaviconを配信するし、パスが与えられればそいつを配信するよ、ってことだね。(同じページにソースも載っている。)

自作のfaviconを配信する。

なので、次のように自作favicon.icoへのパスをfavicon()関数に渡してあげればよさそう。

app.use(express.favicon(__dirname + '/public/images/favicon.ico', {
  maxAge: 2592000000 // キャッシュの有効期限
}));

2013/12/30

テンプレートエンジンjadeのmixinを使ってDRYを促進する。

jadeとは?

express.jsの標準テンプレートエンジンとして採用されているのが jade 。Rails上のerbとかもそうですが、うっかりすると同じようなテンプレートをいちいち繰り返して書いていることに気づいて、悲しい気持ちになるのだけど、jadeのmixinという機能を使うことで、全てではないけど悲しい事態がある程度解消できた、という話です。

mixin

リファレンスには、

Mixins allow you to create reusable blocks of jade.
と書いてあって、つまり、再利用可能なjadeブロックを作ることができる、ということ。

mixinを定義する

mixinを定義するには、


mixin name1
  block

mixin name2(args)
  block

のように、mixinキーワードを使う。定義したmixinを使うには、
+ name1
+ name2('foo')
のように、+mixin名という形で使う。 mixinの定義内には、jadeの構文が書けるし、jadeのブロックが渡せるので、
mixin article(title)
  .article
    h1= title
    block
と定義しておいて、
+article3('Title')
  p This is a description
とすると、

Title

This is a description

とレンダリングされる。

mixin適用前の悲しいテンプレート

jadeを使って作っているサイトで、mixinを知らずに書いていた残念なコードがこちら。

div.row-fluid
  div.span8.offset2
    div.row-fluid
      div.span6.well
        h3
          a(href='/labs/jscharts') JSCharts
        p.
          experiments using JSCharts.
      div.span6.well
        h3
          a(href='/labs/smoothiejs') Smoothie Charts
        p.
          experiments using Smoothie Charts.

    div.row-fluid
      div.span6.well
        h3
          a(href='/labs/chartjs') Chart.js
        p.
          experiments using Chart.js
リンク、タイトル、概要のセットで構成されたブロックが3つあるんだけど、同じ構造を3回繰り返し書いていて、DRYじゃない。

mixin適用後の美しい?テンプレート

↑のテンプレートにmininを定義してやって、DRYな形でリファクタリングしたコードがこちら。

// mixinの定義
mixin article(href, title, desc)
  div.span6.well
    h3
      a(href=href)= title
    p= desc

// mixin使用
div.row-fluid
  div.span8.offset2
    div.row-fluid
      +article('/labs/jscharts', 'JSCharts', 'experiments using JSCharts.')
      +article('/labs/smoothiejs', 'Smoothie Charts', 'experiments using Smoothie Charts.')

    div.row-fluid
      +article('/labs/chartjs', 'Chart.js', 'experiments using Chart.js.')

まったく同じコンテンツをレンダリングするjadeのコードが、よりシンプルかつエレガントになった。mixinをうまく使うことで、jadeテンプレートがDRYになることがわかる。実際にリファクタリングしたページは、こちらで公開しています。

2013/08/15

node(express.js)なアプリをcapistranoでdeployする。

Railsアプリをサーバーにデプロイする際に、Capistranoを使ってきたけど、これをNode.js+express.jsなアプリでも使えればなぁ、と思っていて、@d_akatsukaさんの、
Node.js アプリをデプロイして Upstart で起動させる Capistrano レシピを書いた
を大いに参考にさせて頂いて、やっと自分の環境でも動かすことができたので、まとめてみる。

Capistrano

Capistranoは、rubygemsとしてインストールする。

  $ gem install capistrano
  $ cap --version
  Capistrano v2.15.4
ちなみに、僕の環境のrubyはrbenv+ruby_buildでインストールしたruby2.0.0p0。

Capfileとdeploy.rb

Capistranoでデプロするには、一般的に、Capfileとdeploy.rbという2つのRubyスクリプトが必要になる。 今回は、express.jsアプリケーションの標準的なディレクトリ構成にこの2つのファイルを追加した。

project_root
├── Capfile
├── app.js
├── config
│   └── deploy.rb
├── node_modules
├── package.json
├── public
├── routes
└── views

それぞれ、次のような内容を書く。
#
# Capfile
#
load 'deploy'
# Uncomment if you are using Rails' asset pipeline
    # load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks
#
# deploy.rb
#
set :application,        'application_name'
set :host,               'your.host.com' # or ip address.
set :user,               'username'
set :password,           'password'
set :deploy_to,          "/var/www/apps/#{application}"
set :shared_children,    %w(log node_modules)

set :node_file,          'app.js'
set :node_version,       "v0.10.12"
set :application_binary, "/usr/local/nvm/#{node_version}/bin/node"
set :npm_binary,         "/usr/local/nvm/#{node_version}/bin/npm"

set :scm,          :git
set :repository,   'git://git.host/your/repository.git'
set :branch,       'master'
set :deploy_via,   :remote_cache

role :app,           host
set  :use_sudo,      false
set  :default_run_options, :pty => true

namespace :deploy do

  task :default do
    update
    start
  end

  task :cold do
    update
    start
  end

  task :setup, :expect => { :no_release => true } do
    dirs = [deploy_to, release_path, shared_path]
    dirs += shared_children.map { |d| File.join(shared_path, d) }
    run "mkdir -p #{dirs.join(' ')}"
    run "chmod g+w #{dirs.join(' ')}" if fetch(:group_writable, true)
  end

  task :finalize_update, :expect => { :no_release => true } do
    run "chmod -R g+x #{latest_release}" if fetch(:group_writable, true)
    run <<-CMD
      rm -rf #{latest_release}/log #{latest_release}/node_modules &&
      ln -s #{shared_path}/log #{latest_release}/log &&
      ln -s #{shared_path}/node_modules #{latest_release}/node_modules
    CMD
  end

  task :start, :roles => :app do
    run "#{sudo} restart #{application} || #{sudo} start #{application}"
  end

  task :stop, :roles => :app do
    run "#{sudo} stop #{application}"
  end

  task :restart, :roles => :app do
    start
  end

  task :npm, :roles => :app do
    run "cd #{latest_release} && #{npm_binary} install"
  end

  desc "writes the upstart script for running the daemon."
  task :write_upstart_script, :roles => :app do
    upstart_script = <<-UPSTART
description "#{application} upstart script"

start on (local-filesystem and net-device-up)
stop  on shutdown

respawn
respawn limit 5 60

script
  chdir #{current_path}
  exec sudo -u #{user} NODE_ENV="production" #{npm_binary} start >> log/production.log 2>&1
end script
    UPSTART

    put upstart_script, "/tmp/#{application}.conf"
    run "#{sudo} mv /tmp/#{application}.conf /etc/init"
  end

end

after 'deploy:setup',           'deploy:write_upstart_script'
after 'deploy:finalize_update', 'deploy:npm'
ほぼ、前述の@d_akatsukaさんの記事のdeploy.rbとかわらないけど、サーバーサイドでnvmをシステムワイドに適用していることで、 nvm経由のnodeやnpmの起動で、パスの指定がこのようになった。

デプロイする

初めてサーバーにデプロイする場合は、

 $ cap deploy:setup
を実行する。コレが成功すると、:deploy_toで指定したディレクトリがサーバーサイドで生成され、 さらに/etc/init配下にupstartのスクリプトが生成される。
通常は、
 $ cap deploy
を実行すると、リポジトリから最新モジュールを取得し、転送、配置、upstartでnodeの再起動をやってくれる。
上述のdeploy.rbで、
 $ cap deploy:start
 $ cap deploy:stop
 $ cap deploy:restart
 $ cap deploy:rollback
を試したけど、うまく動いた。

2013/04/13

[node][express][mongoose] モデルのファイル分割

node,expressなWebアプリケーション開発の話です。
mongooseを使ったモデルをうまくファイル分割して配置したい、と思ってやってみました。
(うまいかどうか、正直自信はありません。)

expressで作ったアプリケーションディレクトリは、
  • app.js
  • package.json
  • node_modules
  • public
  • routes
  • views
のように、2つのファイルと、4つのディレクトリで構成されます。
この構成に対して、
db.js
mongodbへのコネクション処理を実装
models
mongodbのcollectionに対応したスキーマ定義ファイルを配置するディレクトリ
を追加しました。

実装は次のようにしました。

db.js

var mongoose = require('mongoose');
mongoose.connect('mongodb://hostname:port/dbname');

models/somemodel.js
var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

var SomeModel = new Schema({
  attr1: SomeType,
  attr2: SomeType,
  :
});

// 以下、モデルのロジックの実装。
これで、モデルごとにファイルを分割し、models配下に格納していくことができます。
最後に、app.jsでdb.jsををrequireします。
// :
require('./db');
// :
また、モデル単位のファイルは、必要な場所でそれぞれrequireします。

2012/08/18

[node] node.js+matador+stylusの環境構築

nodeを使ったwebアプリの開発を実験中ですが、当初expressを使って作り始めましたが、 MVCアーキテクチャに則って作るべきと思い、妥当なフレームワークを探してました。
そこで見付けたのが、matadorというフレームワークです。
MVCアーキテクチャで実装でき、mongodbと相性が良さそうです。

matadorのインストールは、npmを使って簡単に出来ます。

 $ nvm use v0.8.4
 $ npm install matador -g      # matador コマンドのインストール
 $ matador init your_app_name  # アプリの生成
 $ cd your_app_name
 $ npm install matador         # matador moduleのインストール
 $ node all/server.js          # 起動

この段階で、node+matadorのアプリ開発環境ができた状態です。
ここにstylusを投入したくて、stylusインストール後、server.jsを修正して、以下のようにしました。

stylusインストール
 $ cd your_app_name
 $ npm install stylus
server.js

   :
app.configure(function () {

  app.set('view engine', 'html');
  app.register('.html', matador.engine);

  // Use the cache helper's no-cache middleware.
  app.use(app.getHelper('Cache').auditHeadersMiddleware);
  app.use(app.getHelper('Cache').noCacheMiddleware);

  app.use(matador.cookieParser());
  app.use(matador.session({secret: 'boosh'}));

  // TODO: Add JSON body parser middleware
  app.use(app.requestDecorator());
  app.use(app.preRouter());

  app.use(express.bodyParser());
  // stylusを使うために、↓を追加。
  app.use(require('stylus').middleware(__dirname + '/app/public'));
});
   :
この状態で、.cssがなければnode起動時に.stylを.cssに変換してくれるんですが、 一度作られると、.stylを編集しても.cssに変換されませんでした。
なので、node_devを使えば、良さそうです。

express
http://expressjs.com/
matador
http://obvious.github.com/matador/
stylus
http://learnboost.github.com/stylus/
2012年に使いたいJavaScriptのMVCフレームワーク14選
http://memo.yomukaku.net/entries/8nZdDFu
node.jsの開発時に役立つモジュール
http://blog.asial.co.jp/794

2012/08/11

[emacs] jade-mode, stylus-mode

node(node.js)+expressを使ったWebアプリケーションを書く環境を整えています。
僕はEmacsを使っているんで、expressのテンプレートエンジンであるJadeとCSSメタ言語Stylusを Emacsで書くために、jade-modeをインストールしました。
ので、その設定を書いときます。


jade-modeは、 https://github.com/brianc/jade-mode/ からもってきます。
jade-modeがstylusモードを内包していました。


.emacsには、以下を追加します。

  (add-to-list 'load-path "/path/to/jade-mode")
  (require 'stylus-mode)
  (require 'jade-mode)    
  (add-to-list 'auto-mode-alist '("\\.styl$" . stylus-mode))
  (add-to-list 'auto-mode-alist '("\\.jade$" . jade-mode))
簡単すね。