掘金從上線到如今,網站的前端重構了 3 次,後端也陸陸續續修改了整個網站的結構 2 次,可是隨着業務不斷推演複雜,團隊人手增長,有須要一波進一步的優化!javascript
這周,咱們會根據當下掘金的狀況和接下里的主要業務,整理代碼。css
在架構開發以前,咱們首先要梳理現有的網站狀態和需求,而後再作優化html
Node.js
因爲網站的早期開發是我來負責的,雖然我曾經寫過 PHP
、Ruby on Rails
和 Python
的後臺,但由於本身同時寫不少前端代碼所以對 JavaScript
最熟。與此同時,咱們選擇了 LeanCloud 做爲咱們的雲存儲、推送、託管平臺,於是就繼續使用了 Node.js
爲開發框架。前端
v4.4.5
Express.js
由於選擇了 LeanCloud 的緣故,其後端你託管要用 Express
加上自己對這個框架的使用還算熟練,便沿用了下來。vue
4.13.3
上面已經講了咱們選擇了 LeanCloud,具體來說咱們使用了以下功能:java
LeanStorage
:數據存儲LeanMessage
:移動應用推送Leanengine
:雲引擎
LeanAnalytics
:數據統計工具1.0.0-beta
因爲掘金網站的主頁面是一個純前端應用,其部分業務會與後端數據接口直接關聯。下圖主要展現了咱們後端的總體狀態:node
其中黑色的箭頭表示業務需求,而黃色箭頭表明數據更新需求。webpack
網站服務器是整個應用最基礎的部分,它處理網頁端的頁面、API 請求,外聯用戶信息和 LeanStorage 數據庫。git
config.js // 後端配置文件
server.js // 服務器啓動腳本
app.js // 後端業務,被 server.js 引用
cloud.js // 雲函數定義,被 app.js 引用
webpack.config.js // webpack 打包配置文件複製代碼
根據不一樣的環境(生產環境、前端開發、後端開發),config.js
定義了各個開發環境須要的配置文件信息。例如在 package.json
的 npm scripts
裏會定義:github
"dev": "cross-env NODE_ENV=devFrontend supervisor -i vue,node_modules server"複製代碼
這樣,npm run dev
就會設置當下的 NODE_ENV
是 devFrontend
,也就是前端開發環境。
接下來 server.js
就會根據當下環境讀取的配置文件開啓服務端業務,如 app.js
定義的後端業務代碼或 cloud.js
裏的雲函數。固然,在不一樣環境下 webpack
也會作不一樣的操做。
app.js
app.js
援引了配置文件後,執行 Express.js
框架,開啓業務代碼。除了基本的 middleware(頁面 template engine jade
, cookie, session 等等),其最主要的業務包含:
routes
auth
因爲網站大量使用前端 router,於是在 routes
定義中也要格外當心,掘金的開發方式是這樣的。例如 Styleguide 頁面,多是這樣的定義的:
// app.js 文件
// routes/page.js 裏定義了網頁相關的路由及後端渲染
var page = require('./routes/page');
// app 綁定了 styleguide 頁面的路由,及幾個前端路由統一
app.get('/styleguide', page.styleguide);
app.get('/styleguide/base', page.styleguide);
app.get('/styleguide/components', page.styleguide);複製代碼
cloud.js
雲函數LeanCloud 很好地支持了雲函數,能夠幫助你完成後端的數據觸發性 Hook 腳本及定時腳本。
例如每一條評論存儲在 Comment
Table 裏,那麼對於這條評論,咱們能夠捕捉到
beforeSave // 存儲以前
afterSave // 存儲以後
beforeUpdate // 更新以前
afterUpdate // 更新以後
beforeDelete // 刪除以前
afterDelete // 刪除以後複製代碼
加入,咱們想要實現一個功能,就是增長一個 comment
後,更新相應的文章的評論數加一,而刪除後則減一。
// cloud.js 文件
// cloud/comment.js 定義了關於 Comment 數據的 Hook 函數
var comment = require('./cloud/comment');
AV.Cloud.afterSave('Comment', comment.afterSave);
AV.Cloud.afterDelete('Comment', comment.afterDelete);複製代碼
// cloud/comment.js
exports.afterSave = function(request, response) {
... // update 相關文章的數據
if (ok) {
response.success();
} else {
response.error('...');
}
})複製代碼
webpack.config.js
webpack 是一個模塊打包工具,隨着它的插件、業務愈來愈強大,它也像是以前的 grunt
和 gulp
同樣分攤了一部分腳本自動化的功能。
webpack.config.base.js
:基本的打包配置文件,主要用於開發環境熱更新webpack.config.prod.js
:生產環境的配置文件,引用了 base
,定義打包需求,生成 build 好的文件這裏我就不展開關於 webpack 自己的配置優化的部分。
除了上面說的最基本的服務器開啓文件,整個項目的代碼結構以下:
config.js
server.js
app.js
/routes // 各個路由的後端業務邏輯
/views // 網頁渲染的 jade 文件
/vue // 各個頁面的 vue 業務邏輯
/redis // 緩存定義
/public // 外部訪問的靜態文件
/assets // 後端靜態文件
/data // 後端靜態數據
/scss // SCSS 樣式文件
cloud.js
/cloud // 雲函數相關定義文件
webpack.config.js // webpack 打包配置文件
webpack.config.base.js
webpack.config.prod.js複製代碼
咱們再以 Styleguide 爲例,若是咱們要添加這樣的一個網頁代碼:
app.js
的路由的哪一個模塊下,/styleguide
是一個獨立頁面,於是它應該被定義在 /routes/page.js
裏,並定義到:// page.js 文件
exports.styleguide = function(req, res) {
res.render('styleguide', {
title: '掘金前端 Style Guide'
})
}複製代碼
// app.js
app.get('/styleguide', page.styleguide);複製代碼
/views
裏面定義 /views/styleguide.jade
/vue
裏定義,並要在 webpack.config.base.js
裏定義打包邏輯page.js
裏後端渲染頁面是傳入數據/assets/scss/styleguide.scss
(更多 CSS 結構咱們會在另一篇文章中詳細描述)這樣,整個 Styleguide 頁面會影響到的後端代碼是:
app.js // 路由綁定到 /styleguide
/routes
page.js // 定義了 styleguide 後端業務
/views
styleguide.jade
/vue
/styleguide // styleguide 相關 vue 前端業務
main.js
app.vue
/assets
/scss
/pages/styleguide // [optional] styleguide 內的複雜組件樣式
__style.scss
layout.scss
...
styleguide.scss // styleguide 相關獨立樣式
webpack.config.base.js // 定義新的 styleguide 相對應的 entry複製代碼
舉例,咱們要開發一個數據的 Hook 函數到 LeanCloud,好比說每當一個新的 Comment 生成的時候,咱們要更新對應文章的評論數及最新的評論:
cloud.js // AV.Cloud.afterSave('Comment', comment.afterSave)
/cloud
comment.js // exports.afterSave = function(request, response) {}複製代碼
/cloud/____.js
文件裏cloud.js
文件註冊腳本,如:AV.Cloud.define('cloudFunctionName', functionName)
config.js
裏,不要用 if
和 else
語句區分npm scripts
綁定運行函數,如:npm run dev // 開發,測試數據
npm run dev-backend // 後端開發,測試數據
npm run dev-build // 測試數據,打包
npm run prod // 開發,生產數據
npm run prod-backend // 後端開發,生產數據
npm run prod-build // 生產數據,部署前的打包
npm run test // 測試
npm start // 開啓服務器複製代碼
getPopEntries
能夠明確到 getPopularEntries
npm install/uninstall PACKAGE --save/--save-dev
,隨時更新庫I_LOVE_YOU
用下劃線加大寫字母iLoveYou
駝峯,不管是普通變量仍是函數名ILoveYou
首字母大寫的駝峯,包括 LeanCloud 本身的數據 Table 名_iLoveYou
加前置下劃線AV.User
,不要使用 '_User'
Promise
,將複雜的業務改寫爲清晰的異步處理流:start()
.then(step1)
.then(step2)
.then(step3)
.then(step4)
.catch(errorHandler)
.finally(callback)複製代碼
always
替換了原有的 finally
AV.Promise.error
替換了 Promise.reject
AV.Promise.when([promise1, promise2, promise3])
能夠在三個 promise 都完成的狀況下作異步操做exists
, startsWith
, matches
等select
拿去部分數據query.first()
和 query.get(id)
,可是注意:
first()
後 then(function(obj) {})
中的 obj
多是 null
get()
後若是得不到數據會直接引起 error
AV.Object.createWithoutData(TABLE_NAME, ID)
來實現指針查詢,無需取一遍數據query.include('reply.user')
,一個文章查詢能夠用這類語句直接查出來一個評論的回覆的用戶數據,也就是說拿出來的一個 comment
能夠訪問到 comment.get('reply')
和 comment.get('reply').get('user')
。matchesQuery
origin/
master // 線上版本
|- hotfix-login // 熱修復,如登陸異常
release // 最新的要部署的版本
develop // 開發分支
|- feature-homepage-v2 // 正在開發的業務,如第二版的首頁
|- feature-timeline-api // 正在開發的業務,如 Timeline 的 API
developer-ming
master
release
develop
|- feature-timeline-api // 我正在開發這個 feature,不斷和 origin 同步複製代碼
develop
fork 出來一個新的 branch feature-name
feature-name -> develop
,記得打 label 到 feature
feature-name
裏修復develop
上不斷 merge 新的 review 過的業務功能develop -> release
npm run build
打包業務代碼,準備部署publish
release -> master
,標註版本號hotfix
分支develop
和 release
的同步,用 git rebase
develop
及 feature
分支不作 build
操做根據產品接下來的發展路徑,有幾個重要的功能須要優化。