CoffeeBoxは、Node.js、CoffeeScript、MondoDbで作成されたシンプルなブログアプリです。
そこそこ本格的で「学べる」コードだと思いますので、インストールから触りだけ読んでみたいと思います。
UIもキレイです。
インストールして起動まで一気に。
$ git clone https://github.com/qiao/coffee-box $ cd coffee-box/ $ npm install $ mongod --dbpath ~/MongoDb (MongoDBを起動しておきます) $ node index.js coffee-box server listening on port 3000 in development mode
http://localhost:3000 にアクセスします。
Login画面。OpenIDを使えます。
新規投稿です。
投稿完了。
ダッシュボード。
コードを少し見てみます。
ファイル構成です。
index.js server.coffee lib ├── markdown.coffee ├── marked.js ├── require_dir.coffee └── taglist.coffee public/ ├── 404.html ├── favicon.ico └── images ├── CREDIT └── fabric_1.png scripts/ └── populate.coffee config/ ├── config.coffee ├── routes.coffee └── site.json app ├── assets │ ├── javascripts │ │ ├── application.coffee │ │ ├── bootstrap-tabs.js │ │ ├── comments.coffee │ │ ├── jquery.elastic.js │ │ ├── jquery.js │ │ ├── jquery.textarea.js │ │ ├── preview.coffee │ │ ├── session.coffee │ │ └── site.coffee │ └── stylesheets │ ├── application.styl │ ├── bootstrap.css │ ├── comments.styl │ ├── dashboard.styl │ ├── posts.styl │ ├── pygments.css │ ├── session.styl │ └── site.styl ├── controllers │ ├── comments_controller.coffee │ ├── dashboard_controller.coffee │ ├── posts_controller.coffee │ └── session_controller.coffee ├── helpers │ ├── comments_helper.coffee │ └── posts_helper.coffee ├── models │ ├── comment.coffee │ └── post.coffee └── views ├── comments │ ├── _comment.jade │ ├── _comments.jade │ ├── _form.jade │ └── _spam.jade ├── dashboard │ ├── _comments.jade │ ├── _posts.jade │ └── index.jade ├── layouts │ ├── _footer.jade │ ├── _header.jade │ └── layout.jade ├── posts │ ├── _form.jade │ ├── edit.jade │ ├── index.jade │ ├── new.jade │ └── show.jade └── session └── new.jade
MVCにわかれています。ViewテンプレートにはJadeを使っています。スタイルシートはStylus。
次に依存パッケージを見ていきます。
coffee-box@0.0.6 /Users/inouetomoyuki/Projects/node/coffee-box ├── async@0.1.18 ├── coffee-script@1.2.0 ├─┬ connect-assets@2.1.9 │ ├── connect-file-cache@0.2.4 │ ├── mime@1.2.2 │ ├─┬ snockets@1.3.4 │ │ ├── dep-graph@1.0.1 │ │ └── uglify-js@1.0.7 │ └── underscore@1.1.7 ├─┬ express@2.5.8 │ ├─┬ connect@1.8.6 │ │ └── formidable@1.0.9 │ ├── mime@1.2.4 │ ├── mkdirp@0.3.0 │ └── qs@0.4.2 ├── express-messages@0.0.2 ├── gravatar@1.0.6 ├─┬ jade@0.22.1 │ ├── commander@0.5.2 │ └── mkdirp@0.3.0 ├── moment@1.5.1 ├─┬ mongoose@2.5.13 │ ├── hooks@0.2.0 │ └─┬ mongodb@0.9.9-7 │ └── bson@0.0.4 ├── openid@0.4.1 ├─┬ pygments@0.1.2 │ └── underscore@1.3.1 ├─┬ rss@0.0.3 │ ├── logging@2.0.16 │ └── xml@0.0.7 ├─┬ stylus@0.25.0 │ ├── cssom@0.2.3 │ ├── debug@0.6.0 │ └── mkdirp@0.3.1 ├── uglify-js@1.2.6 └── validator@0.4.5
Expressが使われています。MongoDBのODMにはMongooseです。エラー表示やステータス表示にexpress-message。connect-assetsで、Rails Asset PipelineっぽくCSSやらJSやらまとめているようです。
server.coffeeを見てみます。
express = require 'express' app = module.exports = express.createServer() require('./config/config') app require('./config/routes') app app.listen 3000 console.log "coffee-box server listening on port #{app.address().port} " + "in #{app.settings.env} mode"
Expressを使っています。ConfigとRouterがあるみたい。
ルータを見ていきます。
config/routes.coffee(一部)
module.exports = (app) -> # get controllers from app settings controllersGetter = app.settings.controllersGetter PostsController = controllersGetter.getPostsController app CommentsController = controllersGetter.getCommentsController app SessionController = controllersGetter.getSessionController app DashboardController = controllersGetter.getDashboardController app # middleware for finding all posts published as individual pages findPages = PostsController.findPages # middleware for requiring login requireLogin = SessionController.requireLogin app.get '/' , findPages , PostsController.index app.get '/posts.:format?' , findPages , PostsController.index app.get POST_SHOW_PATTERN , findPages , PostsController.show app.get '/posts/new.:format?' , requireLogin , findPages , PostsController.new app.get POST_EDIT_PATTERN , requireLogin , findPages , PostsController.edit app.post '/posts.:format?' , requireLogin , PostsController.create app.put POST_SHOW_PATTERN , requireLogin , PostsController.update app.del POST_SHOW_PATTERN , requireLogin , PostsController.destroy app.post '/posts/preview' , PostsController.preview
Controllerを登録して、ルーティングを決めています。例えば app.get '/'だったら、PostControllerのindex関数にルーティングされていることがわかります。
Postコントローラを見ていきます。
post_controller.coffee(一部)
index: (req, res, next) -> # check pagination param: /posts/?page=2 pageNo = parseInt(req.query['page'], 10) or 1 POSTS_PER_PAGE = 5 Post.countPostPages POSTS_PER_PAGE, (err, totalPages) -> Post.getPostsOfPage pageNo, POSTS_PER_PAGE, (err, posts) -> return res.redirect '500' if err? res.render 'posts/index' posts: posts pageNo: pageNo totalPages: totalPages
Post.getPostsOfPage がモデルを呼び出しているところ。res.renderでViewのposts/index.jadeにデータを投げ込んでレンダリングしています。
Postモデルを見ていきます。
app/models/post.coffee
async = require 'async' mongoose = require 'mongoose' Schema = mongoose.Schema {markdown} = require('../../lib/markdown') {makeTagList} = require('../../lib/taglist') {CommentSchema} = require('./comment') PostSchema = new Schema title: type: String required: true content: type: String rawContent: type: String slug: type: String required: true unique: true comments: type: [CommentSchema] (中略) PostSchema.statics.getPostsOfPage = (pageNo, postsPerPage, callback) -> @countPostPages postsPerPage, (err, count) => return callback err, null if err? query = public: true asPage: false options = skip: (pageNo - 1) * postsPerPage limit: postsPerPage sort: [['createdAt', 'desc']] @find query, {}, options, callback
mongooseを使ってスキーマを作っています。getPostsOfPage メソッドで、MongoDbにクエリを投げています。
Postのindexビューを見ていきます。
app/views/posts/index.jade(一部)
// entry list ul.unstyled#entry-list each post in posts li!= partial('show', { locals: { post: post } }) (略)
Postコントローラの、res.renderでPostモデルから取得したデータを postsに入れています。jadeでループさせて表示させています。個々のPostデータの表示には、パーシャルを使って show.jade で表示させています。
app/views/posts/show.jade
article.entry.post != messages() header.entry-header h2.entry-title a(href=postPath(post))= post.title .entry-meta .entry-day= postDay(post) .entry-month= postMonth(post) .entry-content != post.content != partial('comments/comments', { post: post, comments: post.comments })
全体的な流れはこんな感じです。
CoffeeBoxのコードはMVCでの組み方がよくわかります。ブログではログインの方法やセッションの持たせ方、設定などの方法、Stylusでの組み方、Assetの使い方についても理解しやすいです。
まだ改善できるところもありますし、CoffeeBoxは、コールドリーディングにはちょうどいい素材かもしれません。これがすべてではありませんが、脱初心者を目指す方はぜひ。
0 件のコメント:
コメントを投稿