Hackathon Starter:Node.JS Web開發(fā)腳手架
譯文本文翻譯自Hackathon Starter的Github頁面。
在線demo: http://hackathonstarter.herokuapp.com
本文翻譯時Hackathon Starter的version:2.3.2
Hackathon Starter是專門為Node.JS Web開發(fā)而準(zhǔn)備的一個樣板。
如果你以前參加過黑客馬拉松(hackathon),那么你一定會意識到項目準(zhǔn)備階段會花費大量時間:比如決定制作什么、選擇編程語言、選擇web 框架,以及選擇css框架。一段時間過后,你好不容易在Github上建立起初始化的項目,然后其他成員才終于能夠開始工作。或者考慮一個更簡單的情景, 使用Facebook賬戶登錄。如果你不熟悉OAuth 2.0的話,這將耗費你大量的時間。
當(dāng)我開始本項目時,我首要考慮的是簡單和易用。我也試著讓它盡量的兼容以及可復(fù)用,使它能夠在大多數(shù)hackathon web app上使用。在最壞的情況,比如你只對使用Google賬戶登錄感興趣,你也可以將它當(dāng)做一個學(xué)習(xí)指南。
你很可能不需要使用所有的賬號登錄認(rèn)證功能,不用擔(dān)心,這些在Hackathon Starter 2.1版本之后是可選擇的。
現(xiàn)代風(fēng)格

扁平化Bootstrap主題

默認(rèn)主題

Hackathon Starter生成器界面

特性
- 本地登錄認(rèn)證(使用Email與密碼)
 - OAuth 1.0a認(rèn)證( Twitter)
 - OAuth 2.0認(rèn)證(Facebook、Google、Github、Linkedin等)
 - 快速提示
 - MVC項目結(jié)構(gòu)
 - Node.JS 集群支持
 - Rails 3.1風(fēng)格的 Asset pipeline,由connect-assets提供
 - LESS樣式表(自動編譯無需Gulp/Grunt)
 - Bootstrap 3 + Flat UI + iOS 7
 - 聯(lián)系表單(支持Mailgun、Sendgrid、Mandrill)
 - 賬戶管理
Gravatar頭像
用戶詳細(xì)資料
改密碼
找回密碼
重置密碼
綁定社交賬號
注銷賬號 - CSRF保護(hù)
 - API案例(Facebook等)
 
環(huán)境依賴
- MongoDB
 - Node.JS
 - 命令行工具
Mac OS X:Xcode
Windows:Visual Studio
Ubuntu:sudo apt-get install build-essential
Fedora:sudo yum groupinstall "Development Tools"
OpenSUSE:sudo zypper install --type pattern devel_basis 
注意:如果你是Node.JS新手,建議閱讀教程Getting Started With Node.js, Express, MongoDB。
入門指南
最簡單的開始方法就是克隆Github倉庫:
# Get the latest snapshot git clone --depth=1 https://github.com/sahat/hackathon-starter.git myproject cd myproject # Install NPM dependencies npm install node app.js
注意:強(qiáng)烈建議安裝Nodemon,它能監(jiān)控你的Node.JS App的任何改動并自動重啟,從長遠(yuǎn)來看著將節(jié)省你大量時間。
生成器(Generator)
Hackathon Starter生成器目前還在實驗階段,它與目前的代碼緊密相連,一旦移動或改變項目代碼,生成器將有可能不可用,因此建議在下載HS后第一時間使用。
生成器能夠選擇賬號認(rèn)證、改變發(fā)送郵件的服務(wù)商。
獲得API密鑰(略過)
本部分講如何從Facebook、Google等服務(wù)提供商處獲取API密鑰。
項目結(jié)構(gòu)
| Name | Description | 
|---|---|
| config/passport.js | 本地與OAuth的賬號認(rèn)證策略,包括登錄 | 
| config/secrets.js | API密鑰、密碼、數(shù)據(jù)庫地址等 | 
| controllers/api.js | /api 路由控制器,包括所有api示例 | 
| controllers/contact.js | 聯(lián)系表單的控制器 | 
| controllers/home.js | 主頁(index)的控制器 | 
| controllers/user.js | 用戶賬號管理的控制器 | 
| models/User.js | Mongoose中用戶的schema與model | 
| public/ | 靜態(tài)資源 (fonts, css, js, img) | 
| public/js/application.js | 指定客戶端JS依賴 | 
| public/js/main.js | 你所編寫的客戶端JS | 
| public/css/styles.less | 你的App的主樣式表 | 
| public/css/themes/default.less | 一些Bootstrap默認(rèn)樣式 | 
| views/account/ | 賬號管理模板 | 
| views/api/ | API示例模板 | 
| views/partials/flash.jade | 錯誤、信息與成功的提示 | 
| views/partials/navigation.jade | 導(dǎo)航欄部分的模板 | 
| views/partials/footer.jade | Footer部分的模板 | 
| views/layout.jade | 基礎(chǔ)模板 | 
| views/home.jade | 主頁模板 | 
| app.js | 主要的App文件 | 
| setup.js | 移除賬號認(rèn)證等的工具 | 
注意:這里沒有規(guī)定你應(yīng)該如何處理你的視圖,你可以將你的視圖模板放在你喜歡的地方,只要記住更新extends ../layout并且與控制器中的res.render()路徑一致。
使用包列表
| Package | Description | 
|---|---|
| async | 提供同步控制流的工具庫 | 
| bcrypt-Node.JS | 哈希并鹽化用戶密碼的庫 | 
| cheerio | 提供服務(wù)器端處理web頁面能力的庫 | 
| clockwork | Clockwork SMS API庫 | 
| connect-assets | 處理和編譯LESS樣式和JS文件的工具 | 
| connect-mongo | MongoDB連接Express的庫 | 
| csso | connect-assets庫的依賴 | 
| express | Node.js web框架 | 
| body-parser | Express 4.0 中間件 | 
| cookie-parser | Express 4.0 中間件 | 
| express-session | Express 4.0 中間件 | 
| morgan | Express 4.0 中間件 | 
| compression | Express 4.0 中間件 | 
| errorhandler | Express 4.0 中間件 | 
| method-override | Express 4.0 中間件 | 
| express-flash | 提供Express的快速提示 | 
| express-validator | Express的簡單表單驗證 | 
| fbgraph | Facebook Graph API 庫 | 
| github-api | GitHub API 庫 | 
| jade | Express的模板引擎 | 
| lastfm | Last.fm API 庫 | 
| instagram-node | Instagram API 庫 | 
| less | LESS編譯器. 在connect-assets中使用. | 
| lusca | CSRF 中間件 | 
| mongoose | MongoDB ODM. | 
| node-foursquare | Foursquare API 庫 | 
| node-linkedin | LinkedIn API 庫 | 
| nodemailer | Node.js發(fā)送郵件的庫 | 
| passport | node.js簡單優(yōu)雅的賬號認(rèn)證庫 | 
| passport-facebook | Sign-in with Facebook 插件 | 
| passport-github | Sign-in with GitHub 插件 | 
| passport-google-oauth | Sign-in with Google 插件 | 
| passport-twitter | Sign-in with Twitter 插件 | 
| passport-instagram | Sign-in with Instagram 插件 | 
| passport-local | 本地登錄的插件 | 
| passport-linkedin-oauth2 | Sign-in with LinkedIn 插件 | 
| passport-oauth | 設(shè)定你自己的OAuth1.0a與OAuth2.0策略 | 
| request | 簡化的HTTP請求庫 | 
| stripe | 官方 Stripe API 庫 | 
| tumblr.js | Tumblr API 庫 | 
| twilio | Twilio API 庫 | 
| twit | Twitter API 庫 | 
| lodash | 方便的JS工具庫 | 
| uglify-js | connect-assets的依賴 | 
| validator | 在 controllers/api.js中與express-validator聯(lián)合使用 | 
| mocha | 測試框架 | 
| chai | BDD/TDD 聲明庫 | 
| supertest | HTTP 聲明庫 | 
| multiline | 生成器使用的Multi-line 字符串 | 
| blessed | 生成器使用的互動式命令行界面 | 
| yui | Yahoo API 示例中使用 | 
有用的工具與資源
- JSDB.io – 包含絕大多數(shù)JS庫的數(shù)據(jù)庫
 - JS Recipes – 前端與后端的JS教程
 - Jade Syntax Documentation by Example – 比jade官方的文檔還要好
 - HTML to Jade converter – 當(dāng)你需要將從網(wǎng)上找來的HTML片段快速的應(yīng)用到項目中時特別有用
 - JavascriptOO – 一個常用JS庫的示例、CDN以及教學(xué)視頻的目錄
 - Favicon Generator – 生成各平臺的favicon
 
推薦的設(shè)計資源
- Code Guide – 開發(fā)靈活、耐用、可持續(xù)的HTML與CSS的標(biāo)準(zhǔn)
 - Bootsnipp – 配合Bootstrap使用的一些代碼片段
 - UIBox – HTML, CSS, JS, UI 組件
 - Bootstrap Zero – 免費的Bootstrap主題
 - Google Bootstrap – Google風(fēng)格的Bootstrap主題
 - Font Awesome Icons – 已經(jīng)被包含在Hackathon Starter項目中,可以將這作為參考頁面
 - Colors – 更好的web頁面配色
 - Creative Button Styles – 各種各樣非常棒的按鈕
 - Creative Link Effects – 漂亮的鏈接CSS效果
 - Medium Scroll Effect – 像Medium一樣的頂部背景圖片漸隱效果
 - GeoPattern – SVG background pattern generator.
 - Trianglify – SVG low-poly background pattern generator.
 
推薦的Node.JS庫
- Nodemon – 代碼改動時自動重啟Node.js服務(wù)
 - geoip-lite – 根據(jù)IP地址庫的地理位置定位
 - Filesize.js – 格式化文件大小,如 
filesize(265318); // "265.32 kB". - Numeral.js – 格式化并操作數(shù)字的庫
 - Node Inspector – 基于Chrome開發(fā)者工具的Node.js調(diào)試器
 - node-taglib – 讀取常用音頻格式的meta-data的庫
 - sharp – 調(diào)整圖片大小的庫,支持JPEG, PNG, WebP 和 TIFF
 
推薦的客戶端JS庫
- Framework7 – 包含構(gòu)建iOS7風(fēng)格App完整特性的HTML框架
 - InstantClick – 在鼠標(biāo)指上時預(yù)下載,加快頁面加載速度
 - NProgress.js – 簡練的進(jìn)度顯示條
 - Hover – 非常棒的鼠標(biāo)hover css3動畫效果
 - Magnific Popup – 響應(yīng)式的jQuery彈出框插件
 - jQuery Raty – 星星打分插件
 - Headroom.js – 隱藏你的header直到你需要它
 - X-editable – 直觀的修改表單元素
 - Offline.js – 探測用戶是否在線
 - Alertify.js – 可愛的彈出警告與瀏覽器對話框
 - selectize.js – 可調(diào)整樣式的select元素與input標(biāo)簽
 - drop.js – 強(qiáng)大的JS與CSS庫用于創(chuàng)建下拉菜單與其他浮動顯示層
 - scrollReveal.js – 提供滾動時的動畫效果
 
高級Tips
- 當(dāng)安裝NPM包時,添加–save標(biāo)簽,它將自動添加到package.json文件中。如:npm install –save moment
 - 當(dāng)你需要多個同步工作,并當(dāng)它們都完成后才渲染頁面時,使用async.parallel() 。比如你需要爬取三個頁面的數(shù)據(jù),爬取完成后將結(jié)果填充到模板中。
 - 想要從隊列中尋找特定的對象?試試Lodash里的_.find 函數(shù)。比如,這段代碼提供了檢索Twitter token的能力:
 
- var token = _.find(req.user.tokens, { kind: 'twitter' });
 
FAQ
為什么我在提交表單時顯示403錯誤?
你需要在表單中添加下面的隱藏元素,這是一項CSRF保護(hù)措施。
- input(type='hidden', name='_csrf', value=_csrf)
 
注意:CSRF現(xiàn)在支持白名單了,這意味著你可以提交一些URL鏈接,他們可以被CSRF忽略。
注意2:如需忽略的URL是動態(tài)的,可以用正則表達(dá)式匹配。
cluster_app.js是什么?
一個Node實例在單個線程中運行。為了充分利用多內(nèi)核系統(tǒng)的性能,用戶會希望啟動一個Node的進(jìn)程簇來處理負(fù)載。cluster模塊讓你能夠簡單創(chuàng)建共享服務(wù)器端口的子進(jìn)程。
cluster_app.js是app.js的多進(jìn)程版本,它能為每個被探測到的CPU創(chuàng)建一個進(jìn)程。為了最大化的滿足HTTP請求,這是一個很好的功能。但是,cluster模塊仍處於實驗階段,因此請小心使用,確保你正確理解了它的意圖和行為。要使用它,只需要運行node cluster_app.js,它與app.js是完全分離的,無任何依賴關(guān)系。需要提醒的是,如果你用cluster_app.js替代app.js,你需要在package.json里做出聲明。
什么是Rails 3.1風(fēng)格的asset pipeline?
下面是你如何在HTML里定義靜態(tài)文件,使用Jade或其他的模板引擎:
- link(href='/css/styles.css', rel='stylesheet')
 - script(src='/js/lib/jquery-2.1.0.min.js')
 - script(src='/js/lib/bootstrap.min.js')
 - script(src='/js/main.js')
 
看起來足夠簡單?在開發(fā)環(huán)境下也行是這樣。但如果當(dāng)你將app部署到生產(chǎn)環(huán)境時,它們能夠被自動的壓縮到單個的文件呢?
- link(href='/css/styles.css', rel='stylesheet')
 - script(src='/js/application.js')
 
當(dāng)你引入的JS庫越多,自動連接并壓縮JS文件帶來的好處就越大。connect-assets庫能夠讓你簡單的完成這一操作,只需兩行代碼:
- != css('styles') // expects public/css/styles.less
 - != js('application') // expects public/js/application.js
 
你只需要記住在public/js/application.js中定義你的JS文件。語法從Rails中借鑒而來:
- //= require lib/jquery-2.1.0.min
 - //= require lib/bootstrap.min
 - //= require main
 
使用這個方法,當(dāng)在開發(fā)模式時,它會加載各個獨立的JS文件,而當(dāng)部署到生產(chǎn)環(huán)境,它會自動形成單個JS文件。你可以看Sprockets-style concatenation 來了解更多。
我出現(xiàn)了MongoDB Connection Error,該如何修復(fù)它?
這是一個在app.js中自定義的錯誤信息,用來表示連接到MongoDB時出現(xiàn)了問題。
- mongoose.connection.on('error', function() {
 - console.error('✗ MongoDB Connection Error. Please make sure MongoDB is running.');
 - });
 
它提示你應(yīng)該在啟動app.js之前先啟動MongoDB,你可以在這里下載MongoDB,也可以從包管理器來安裝,如果你是Windows用戶,可以按照在Windows上安裝MongoDB的說明來做。
Tip:如果你一直連接著網(wǎng)絡(luò),也可以試著使用 MongoLab 或者 MongoHQ 等在線數(shù)據(jù)庫服務(wù),你只需要更新config/secrets.js中的db信息。
當(dāng)我部署我的app時提示錯誤,為什么?
有可能是你沒有在secrets.js中正確的設(shè)置數(shù)據(jù)庫路徑。當(dāng)你在本地運行你的app時,數(shù)據(jù)庫路徑是localhost,但當(dāng)你部署app時,你需要在網(wǎng)上找到一個運行的MongoDB,并將連接地址正確的填寫在secrets.js中。你也可以申請MongoLab 或者 MongoHQ 等免費服務(wù)。
為什么采用Jade代替Handlebars模板引擎?
當(dāng)我開始這個項目的時候我并不熟悉Handlebars,后來我開發(fā)了一些Ember.js apps并且熟悉了Handlebars的語法。Handlebars的確更簡單一些,因為它就像HTML一樣,但我并不后悔選擇了Jade。理由有三, 第一因為Jade是Express的默認(rèn)模板引擎,所以以前開發(fā)過Express應(yīng)用的人已經(jīng)對它很熟悉了;第二,我發(fā)現(xiàn)在Handlebars里 extends和block是必不可少的,它實際上并沒有達(dá)到即開即用的程度,你仍然需要編寫一些擴(kuò)展函數(shù);第三,客觀的說,Jade看上去比 Handlebars更簡潔干凈,這點與其他非HAML風(fēng)格的引擎相比也是一樣。
為什么你在app.js里定義了所有的路由(route)?
一言以蔽之,為了簡潔。也許有其他更好的方法,比如在這篇博文中 將app上下文按照概述傳給每一個控制器,但我發(fā)現(xiàn)這種方法對初學(xué)者來說說容易搞混的。我花了大量時間來理解exports和 module.exports的概念,保證有一個單獨的全局性app文件作為參考。這是我的背景想法。app.js對我來說是“app的心臟”,它應(yīng)該成 為其他所有模型、控制器、路由等的參考。
我不需要一個絕對底部(sticky footer),我能刪除它嗎?
當(dāng)然可以。不過不像一個常規(guī)footer,你還需要做一些額外的工作。首先,從styles.less里刪除#wrap和#footer,以及html, body { height: 100%; }。然后,從layout.jade中刪除#wrap和#footer所在的行(順便說下,如果Jade沒有檢測到class或id,它會默認(rèn)其是一個div元素)。不要忘了調(diào)整#wrap下面的縮進(jìn),本項目使用兩個空格表示塊級縮進(jìn)。
我能夠使用Sass代替LESS嗎?
Yes you can!雖然你需要手動的轉(zhuǎn)換現(xiàn)有的樣式表到Sass,考慮到Sass和LESS的相似程度,這不會太難。然后你只需要重命名styles.less為styles.scss,connect-assets會自動的采用Sass預(yù)處理器。
你甚至可以同時的使用Sass和LESS,在layout.jade里分別指定了LESS和Sass樣式表文件:
- != css('styles') # public/css/styles.less
 - != css('my_sass_styles') # public/css/my_sass_styles.scss
 
注意:項目的package.json不包含Sass,所以你需要自己安裝它,使用以下命令:
- npm install --save node-sass
 
迷你指南
這一部分將提供單一特定功能的細(xì)節(jié)解釋。也許你很好奇這個項目是如何工作的,也許你已經(jīng)迷失在代碼當(dāng)中,我希望它能給你一些指引。
定制HTML與CSS設(shè)計入門
HTML5 UP提供許多漂亮的模板,并且可以免費下載。
當(dāng)你下載了一個zip文件,里面有index.html、images、css和js文件夾。那么,如何把它拿到Hackathon Starter里面來呢?Hackathon Starter使用Bootstrap CSS框架,但那些模板沒有使用。將它們放到一起會出現(xiàn)很多意想不到的情況。
注意:使用定制模板的方法,你應(yīng)當(dāng)理解你不能重用我創(chuàng)建的所有視圖:layout、主頁、登錄、注冊、賬號管理、聯(lián)系頁面。這些視圖使用 Bootstrap柵格風(fēng)格創(chuàng)建。你需要用新模板里的語法手動更新這些柵格。不過你也可以用另一種方法,在大多數(shù)界面使用Bootstrap,而在 landing page使用另一種風(fēng)格的模板。
讓我們從頭開始,在這個例子里我將使用Escape Velocity 模板。

注意:為了簡潔起見我將只考慮index.html,忽略left-sidebar.html、 no-sidebar.html和 right-sidebar.html。
將所有的js文件從html5up-escape-velocity/js移動到public/js,并將所有css文件從html5up- escape-velocity/css移動到public/css,最后將所有圖片文件從html5up-escape-velocity /images移動到public/images,復(fù)制index.html里的代碼,并將它們粘貼到HTML To Jade 進(jìn)行轉(zhuǎn)換。
創(chuàng)建一個新文件escape-velocity.jade,將轉(zhuǎn)換到的Jade代碼粘貼進(jìn)去。將!!! 5修改為doctype html,這是Jade最近的一個改動之一,但是http://html2jade.aaron-powell.com 還沒有跟進(jìn)這個改動。
在controllers/home.js里創(chuàng)建一個新的控制器escapeVelocity:
- exports.escapeVelocity = function(req, res) {
 - res.render('escape-velocity', {
 - title: 'Landing Page'
 - });
 - };
 
然后在app.js里創(chuàng)建一個路由,我將它放在index控制器的后面::
- app.get('/escape-velocity', homeController.escapeVelocity);
 
重啟服務(wù)器(如果你沒有使用nodemon),然后你就可以在http://localhost:3000/escape-velocity 來查看新模板了。
我的講解將在這里打住,如果你想在更多的頁面使用這個模板,下面是你需要關(guān)注的Jade文件:
- layout.jade – 基本模板
 - index.jade – 主頁
 - partials/navigation.jade – Bootstrap導(dǎo)航欄
 - partials/footer.jade – 絕對底部(sticky footer)
 
你需要手動的將新模板分解為更小的部分。弄清楚模板的哪些部分你想在所有的頁面中保留——那將是你的新layout.jade,其他頁面將通過 block content來共享代碼。如果有不清楚的地方,你可以使用已有的模板作為參考。
這是一個枯燥無味的過程,如果你下載的模板有一套新的柵格系統(tǒng),那么需要更加謹(jǐn)慎了。這是我為什么使用Bootstrap的原因。很多人已經(jīng)熟悉Bootstrap了,即使沒用過學(xué)起來也很簡單。你還可以從Themeforest購買一些漂亮的Bootstrap模板。然后你可以很方便的將它放到Hackathon Starter里。如果你需要完全的定制HTML與CSS,上面這些內(nèi)容將幫助你。
快速提示是如何工作的?
快速提示(Flash messages)允許你在一個請求的結(jié)尾,以及當(dāng)且僅當(dāng)下一個請求之前顯示一段信息。比如,當(dāng)?shù)卿浭r,你可以輸出一些警告信息,但一旦刷新頁面或者 再次進(jìn)入登錄頁面后,這個警告信息不應(yīng)該再次出現(xiàn),它只會被顯示一次。本項目使用express-flash模塊來顯示快速提示,這個模塊在我創(chuàng)建 Hackathon Starter項目時就被包含在connect-flash里面。有了express-flash你無需發(fā)送快速提示到每一個視圖,它一開始就是可用的, 感謝express-flash。
使用快速提示需要兩個步驟。使用下面的代碼在你的控制器里創(chuàng)建一個快速提示:
- req.flash('errors', { msg: 'Error messages goes here' }
 
然后在你的視圖里顯示它們:
- if messages.errors
 - .alert.alert-danger.fade.in
 - for error in messages.errors
 - div= error.msg
 
在第一步里,'errors'是你定義的快速提示的名稱,它應(yīng)該和你的視圖里的messages里的屬性名稱相匹配。將警告信息放在if message.errors以讓它們出錯時才顯示。錯誤信息采用{ msg: 'Error messages goes here' }的形式而不是像'Error messages goes here'一樣的字符串是為了一致性。express-validator模塊會驗證用戶的輸入,當(dāng)發(fā)生錯誤時返回一個數(shù)組對象,每個對象都含有一個msg屬性。下面是express-validator所返回信息的一個示例:
- [
 - { param: "name", msg: "Name is required", value: "<received input>" },
 - { param: "email", msg: "A valid email is required", value: "<received input>" }
 - ]
 
如果使用字符串,你會發(fā)現(xiàn)信息框里面是空的。上面的錯誤信息也可以應(yīng)用在info或者success的場合。
partials/flash.jade是控制快速提示格式化顯示的子模板。它使用一個叫做DRY的方法,將散落在各個視圖的快速提示歸到一處。
和導(dǎo)航欄與footer子模板一樣,flash子模板被包含在layout.jade里。
- body
 - #wrap
 - include partials/navigation
 - .container
 - include partials/flash
 - block content
 - include partials/footer
 
如何創(chuàng)建一個新頁面?
更正確的說法應(yīng)該是“如何創(chuàng)建一個新路由”。主文件app.js包含所有的路由,每一個路由都伴隨著一個callback函數(shù),你會在某些路由里發(fā) 現(xiàn)3個以上的參數(shù),在這種情況里,第一個參數(shù)仍然是URL字符串,中間的參數(shù)是中間件,你可以將它們想象成門禁,如果它阻止你前進(jìn),你將不能得到 callback函數(shù)。一個例子是需要認(rèn)證的路由:
- app.get('/account', passportConf.isAuthenticated, userController.getAccount);
 
它的順序總是從左到右。當(dāng)用戶訪問/account頁面,isAuthenticated中間件將檢查用戶是否認(rèn)證:
- exports.isAuthenticated = function(req, res, next) {
 - if (req.isAuthenticated()) {
 - return next();
 - }
 - res.redirect('/login');
 - };
 
如果認(rèn)證檢查通過,你通過呼叫return next()的方式讓用戶通過門禁。它會依次通過剩下的中間件直到最后一個參數(shù),即callback函數(shù),它通常在接受到GET請求時渲染頁面,或在收到 POST請求時跳轉(zhuǎn)頁面。在這個例子里,你將被跳轉(zhuǎn)到用戶賬號管理頁面,如果認(rèn)證沒有通過,你將被跳轉(zhuǎn)到登錄頁面。
- exports.getAccount = function(req, res) {
 - res.render('account/profile', {
 - title: 'Account Management'
 - });
 - };
 
Express.js里有app.get、app.post、app.put、app.delete四種HTTP動作。但在大多數(shù)情況你只需要前兩種,除非你想創(chuàng)建一個RESTful API。如果你只想顯示一個頁面,使用GET,如果你想提交表單,使用POST。
下面是一個添加路由到你的app里的典型工作流。我們的目的是創(chuàng)建一個頁面顯示數(shù)據(jù)庫里的書籍列表。
第一步:定義一個路由。
- app.get('/books', bookController.getBooks);
 
在express 4.0以上你可以這樣定義你的路由:
- app.route('/books')
 - .get(bookController.getBooks)
 - .post(bookController.createBooks)
 - .put(bookController.updateBooks)
 - .delete(bookController.deleteBooks)
 
而下面是一個需要認(rèn)證中間件的路由:
- app.route('/api/twitter')
 - .all(passportConf.isAuthenticated)
 - .all(passportConf.isAuthorized)
 - .get(apiController.getTwitter);
 - .post(apiController.postTwitter)
 
上面三種方式都是可接受的,你可以使用它們中的任何一種。我認(rèn)為app.route里HTTP動詞的這種鏈?zhǔn)綄懛ǚ浅8蓛魞?yōu)雅,不過缺點是當(dāng)每個路由占一行的時候,你不能一眼看到所有的動作。
第二步:創(chuàng)建一個叫book.js的新控制器文件。
- /**
 - * GET /books
 - * List all books.
 - */
 - exports.getBooks = function(req, res) {
 - Book.find(function(err, docs) {
 - res.render('books', { books: docs });
 - });
 - };
 
第三步:將控制器加入到app.js里。
- var bookController = require('./controllers/book');
 
第四步:創(chuàng)建book.jade模板。
- extends layout
 - block content
 - .page-header
 - h3 All Books
 - ul
 - for book in books
 - li= book.name
 
到這里就完成了。
當(dāng)然,你可以將1到3步合在一起放到app.js里:
- app.get('/books', function(req, res) {
 - Book.find(function(err, docs) {
 - res.render('books', { books: docs });
 - });
 - });
 
是的,這樣更簡單些,但當(dāng)你在app.js中加入1000行代碼時,瀏覽起來會變得比較麻煩。這個項目的初衷本來就是為了分解關(guān)注點,這樣你可以與你的隊員一起工作而不是忙碌于解決沖突。
上面的內(nèi)容就是一切了,Express.js非常易于使用。大部分時間其實用在處理其他API,讓它們來干真正的工作,比如查詢數(shù)據(jù)庫的Mongoose,使用websocket收發(fā)信息的socket.io,發(fā)送郵件的 Nodemailer,表單驗證的express-validator 庫,以及處理web頁面的Cheerio 等。
如何在Hackathon Starter里使用Socket.io?
Dan Stroot曾提交了一個非常棒的pull以在Hackathon Starter里添加一個實時的儀表盤。但我認(rèn)為它違反了非特定化的原則,因此并未接受。但你仍然可以在Hackathon Starter里使用Socket.io。下面是一般的操作步驟。
- npm install socket.io --save
 
將var app = express();替換為下面的代碼:
- var app = express();
 - var http = require('http');
 - var server = http.createServer(app);
 - var io = require('socket.io').listen(server);
 
將下面的代碼添加到app.js的末尾:
- io.configure(function() {
 - io.set('transports', ['websocket']);
 - });
 - io.sockets.on('connection', function(socket) {
 - socket.emit('greet', { hello: 'Hey, Mr.Client!' });
 - socket.on('respond', function(data) {
 - console.log(data);
 - });
 - socket.on('disconnect', function() {
 - console.log('Socket disconnected');
 - });
 - });
 
最后,將
- app.listen(app.get('port'), function() {
 
改為
- server.listen(app.get('port'), function() {
 
后端的工作到這里就完成了。
你有兩種方式將前端部分的js加到app中,一種是直接加到layout.jade中,將下面的代碼加到head塊中。
- script(src='/socket.io/socket.io.js')
 - script.
 - var socket = io.connect(window.location.href);
 - socket.on('greet', function (data) {
 - console.log(data);
 - socket.emit('respond', { message: 'Hello to you too, Mr.Server!' });
 - });
 
注意代碼中socket.io的路徑,你并不需要實際的在項目中包含socket.io.js,它將在運行時自動生成。
另一種方法是將js部分加入到獨立的的main.js文件中,并將它們包含在jQuery的ready函數(shù)下。
- $(document).ready(function() {
 - // Place JavaScript code here...
 - var socket = io.connect(window.location.href);
 - socket.on('greet', function (data) {
 - console.log(data);
 - socket.emit('respond', { message: 'Hello to you too, Mr.Server!' });
 - });
 - });
 
到這里所有工作就完成了。
這里有一個實時儀表盤的在線演示。你可以查看這里它是如何添加到工程里的。
Mongoose Cheatsheet
查詢所有用戶:
- User.find(function(err, users) {
 - console.log(users);
 - });
 
通過email查詢用戶:
- var userEmail = 'example@gmail.com';
 - User.findOne({ email: userEmail }, function(err, user) {
 - console.log(user);
 - });
 
查詢5個最近的用戶賬號:
- User
 - .find()
 - .sort({ _id: -1 })
 - .limit(5)
 - .exec(function(err, users) {
 - console.log(users);
 - });
 
從所有文檔中查詢指定列的總數(shù):
假設(shè)每個用戶有一個叫做votes的列,你希望統(tǒng)計所有用戶的votes總數(shù)。一個笨辦法是循環(huán)查找所有的文檔并手動的將結(jié)果加起來。另一個方法是使用MongoDB Aggregation Framework 來代替:
- User.aggregate({ $group: { _id: null, total: { $sum: '$votes' } } }, function(err, votesCount) {
 - console.log(votesCount.total);
 - });
 
應(yīng)用部署(略過)
本部分介紹了應(yīng)用MongoLab、Heroku、OpenShift等在線服務(wù)來部署應(yīng)用,由于網(wǎng)絡(luò)環(huán)境的不同,在國內(nèi)可能難以用到,所以不予翻譯。
(正文完)
譯者注:翻譯完成后覺得Hackathon Starter的確是個好東西,不過就像這篇文章所說的,每個開發(fā)者都需要有自己的Project Starter,這個Hackathon Starter也不適合直接拿來用,吃透它,將它本地化才是最好的做法。















 
 
 






 
 
 
 