儘管沒有特別的動力去構建一個全新的CMS,可是我仍是願意去撰文一篇來書寫如何去作這樣的事——編輯-發佈-開發分離模式是如何工做的。微服務是咱們對於複雜應用的一種趨勢,編輯-發佈-開發分離模式則是另一種趨勢。在上篇文章《Repractise架構篇一: CMS的重構與演進》中,咱們說到編輯-發佈-開發分離模式。javascript
如先前提到的,Carrot使用了下面的方案來搭建他們的靜態內容的CMS。css
在這個方案裏內容是用Contentful來發布他們的內容。而在我司ThoughtWorks的官網裏則採用了Github來管理這些內容。因而若是讓咱們寫一個基於Github的CMS,那麼架構變成了這樣:html
或許你也用過Hexo / Jekyll / Octopress這樣的靜態博客,他們的原理都是相似的。咱們有一個代碼庫用於生成靜態頁面,而後這些靜態頁面會被PUSH到Github Pages上。前端
從咱們設計系統的角度來講,咱們會在Github上有三個代碼庫:java
Content。用於存放編輯器生成的JSON文件,這樣咱們就能夠GET這些資源,並用Backbone / Angular / React 這些前端框架來搭建SPA。jquery
Code。開發者在這裏存放他們的代碼,如主題、靜態文件生成器、資源文件等等。git
Builder。在這裏它是運行於Travis CI上的一些腳本文件,用於Clone代碼,並執行Code中的腳本。程序員
以及一些額外的服務,當且僅當你有一些額外的功能需求的時候。github
Extend Service。當咱們須要搜索服務時,咱們就須要這樣的一些服務。如我正考慮使用Python的whoosh來完成這個功能,這時候我計劃用Flask框架,可是隻是計劃中——由於沒有合適的中間件。npm
Editor。相比於前面的那些知識這一步適合更重要,也就是爲何生成的格式是JSON而不是Markdown的原理。對於非程序員來講,要熟練掌握Markdown不是一件容易的事。因而,一個考慮中的方案就是使用 Electron + Node.js來生成API,最後經過GitHub API V3來實現上傳。
So,這一個過程是如何進行的。
整個過程的Pipeline以下所示:
編輯使用他們的編輯器來編輯的內容並點擊發布,而後這個內容就能夠經過GitHub API上傳到Content這個Repo裏。
這時候須要有一個WebHooks監測到了Content代碼庫的變化,便運行Builder這個代碼庫的Travis CI。
這個Builder腳本首先,會設置一些基本的git配置。而後clone Content和Code的代碼,接着運行構建命令,生成新的內容。
而後Builder Commit內容,並PUSH內容。
這裏還依賴於WebHook這個東西——還沒想到一個合適的解決方案。下面,咱們對裏面的內容進行一些拆解,Content裏面因爲是JSON就很少解釋了。
Github與Travis之間,能夠作一個自動部署的工具。相信已經有不少人在Github上玩過這樣的東西——先在Github上生成Token,而後用travis加密:
travis encrypt-file ssh_key --add
加密後的Key就會保存到.travis.yml
文件裏,而後就能夠在Travis CI上push你的代碼到Github上了。
接着,你須要建立個deploy腳本,而且在after_success
執行它:
after_success: - test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy.sh
在這個腳本里,你所須要作的就是clone content和code中的代碼,並執行code中的生成腳本,生成新的內容後,提交代碼。
#!/bin/bash set -o errexit -o nounset rev=$(git rev-parse --short HEAD) cd stage/ git init git config user.name "Robot" git config user.email "robot@phodal.com" git remote add upstream "https://$GH_TOKEN@github.com/phodal-archive/echeveria-deploy.git" git fetch upstream git reset upstream/gh-pages git clone https://github.com/phodal-archive/echeveria-deploy code git clone https://github.com/phodal-archive/echeveria-content content pwd cp -a content/contents code/content cd code npm install npm install grunt-cli -g grunt mv dest/* ../ cd ../ rm -rf code rm -rf content touch . if [ ! -f CNAME ]; then echo "deploy.baimizhou.net" > CNAME fi git add -A . git commit -m "rebuild pages at ${rev}" git push -q upstream HEAD:gh-pages
這就是這個builder作的事情——其中最主要的一個任務是grunt
,它所作的就是:
grunt.registerTask('default', ['clean', 'assemble', 'copy']);
Assemble是一個使用Node.js,Grunt.js,Gulp,Yeoman 等來實現的靜態網頁生成系統。這樣的生成器有不少,Zurb Foundation, Zurb Ink, Less.js / lesscss.org, Topcoat, Web Experience Toolkit等組織都使用這個工具來生成。這個工具彷佛上個Release在一年多之前,如今正在開始0.6。雖然,這並不重要,可是仍是順便一說。
咱們所要作的就是在咱們的Gruntfile.js
中寫相應的生成代碼。
assemble: { options: { flatten: true, partials: ['templates/includes/*.hbs'], layoutdir: 'templates/layouts', data: 'content/blogs.json', layout: 'default.hbs' }, site: { files: {'dest/': ['templates/*.hbs']} }, blogs: { options: { flatten: true, layoutdir: 'templates/layouts', data: 'content/*.json', partials: ['templates/includes/*.hbs'], pages: pages }, files: [ { dest: './dest/blog/', src: '!*' } ] } }
配置中的site用於生成頁面相關的內容,blogs則能夠根據json文件的文件名生成對就的html文件存儲到blog目錄中。
生成後的目錄結果以下圖所示:
. ├── about.html ├── blog │ ├── blog-posts.html │ └── blogs.html ├── blog.html ├── css │ ├── images │ │ └── banner.jpg │ └── style.css ├── index.html └── js ├── jquery.min.js └── script.js 7 directories, 30 files
這裏的靜態文件內容就是最後咱們要發佈的內容。
還須要作的一件事情就是:
grunt.registerTask('dev', ['default', 'connect:server', 'watch:site']);
用於開發階段這樣的代碼就夠了,這個和你使用WebPack + React 彷佛相差不了多少。
在這種情形中,編輯可否完成工做就不依賴於網站——脫稿又少了 個藉口。這時候網站出錯的機率過小了——你不須要一個緩存服務器、HTTP服務器,因爲沒有動態生成的內容,你也不須要守護進程。這些內容都是靜態文件,你能夠將他們放在任何能夠提供靜態文件託管的地方——CloudFront、S3等等。或者你再相信本身的服務器,Nginx但是全球第二好(第一還沒出現)的靜態文件服務器。
開發人員只在須要的時候去修改網站的一些內容。
So,你可能會擔憂若是這時候修改的東西有問題了怎麼辦。
使用這種模式就意味着你須要有測試來覆蓋這些構建工具、生成工具。
相比於本身的代碼,別人的CMS更可靠?
須要注意的是若是你上一次構建成功,你生成的文件都是正常的,那麼你只須要回滾開發相關的代碼便可。舊的代碼仍然能夠工做得很好。
其次,因爲生成的是靜態文件,查錯的成本就比較低。
最後,從新放上以前的靜態文件。