這是一個包含不少靜態內容頁面的站點, 從技術上來講就如同一系列HTML文件, 展現給訪問者. 與動態網站不一樣的是, 他不須要後端開發或者數據庫支撐. 發佈靜態站點之因此容易, 是由於文件只須要上傳到服務器或者存儲器. 沒有額外的渲染頁面的請求, 也沒有數據庫被黑的風險, 因此它既安全也快速.javascript
爲了快速建站, 其實不少開源的靜態頁面生成框架可用, 好比前陣子我搞的Jekyll, Hugo, 好似國人偏心的Hexo等等, 他們的工做原理類似, 內容都是經過靜態文件(好比Markdown)或者帶有內容的API, 經過獲取這些內容, 注入到開發者作好的模板, 最後生成一大堆HTML文件.php
Progressive Web Apps (PWA)其實是網頁應用, 幾乎基於Javascript, 而且可靠, 快速, 有吸引力的. 這幾年比較火的Angular, Vue, React都是相似的前端框架.前端
靜態站點碰見了PWA就產生了Gatsby
將這兩點組合起來的最佳選擇看起來就是Gatsby了, 可是一樣須要一個內容接口, 這就是我將要展現的, 經過Strapi建立一個內容API提供給Gatsby, 而後打包發佈出一個靜態站點.java
這個並非型男熟知的傑士派, 雖然我也用過這個發泥, 好像不是很好用. Gatsby是基於React的快速靜態網站框架, 有了它, 你就能夠感受飄飄然的開發React網站了.node
Strapi是一個基於高級的Nodejs API內容管理框架. 聽起來有點繞口, 通俗來講就是讓你能簡單, 安全, 高效的開發出強大API的開源的內容管理框架. 它是免費的, 人們都愛免費的, 能夠隨意在你的服務器上使用, 也很是具備可個性化, 可擴展性的玩意.react
我真想不到國內幾乎沒有人用Gatsby和Strapi, 百度上查不到任何資料...
見證奇蹟的時刻即將到來, 咱們快建立個Strapi API, 添加點內容吧!linux
Requirements: please make sure Node 8 (or higher) and MongoDB are installed and running on your machine.
此時, 暗喜前陣子已經琢磨出來了並裝好了Node 8
, 不過裝MongoDB就沒有了. 所以這裏就要插入一段關於MongoDB的內容了. 若是已經有了請自動跳過此內容.webpack
果斷找到文檔Install MongoDB Community Edition on Red Hat Enterprise or CentOS Linux, 這個redhat和centOS應該是通用的吧- -! 看到Configure the package management system (yum)., 發現原來還有這種操做, 建立repo文件, 來安裝對應版本的軟件. 閒話少說, 直接上代碼:git
# cd /etc/yum.repos.d/ # touch mongodb-org-3.6.repo # vi mongodb-org-3.6.repo
將如下內容copy進去保存github
[mongodb-org-3.6] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.6/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc
再進行安裝
# sudo yum install -y mongodb-org
若是有特殊需求, 請參閱上文提到的官方文檔, 我這裏裝的是MongoDB Community Edition
按以上步驟很快就裝好了. 接下來啓動mongod(若是沒有啓動的話), 以下命令:
# service mongod start
完成後, 咱們接着建立Strapi項目的主題, 推薦安裝strapi@alpha
版本:
# npm i strapi@alpha -g
完成後, 去到你要建立本文項目的目錄, 好比我這裏的路徑是/home/web/
, 我在這裏建立一個gatsby-strapi-tutorial
目錄:
# mkdir gatsby-strapi-tutorial
在這裏面搭一個API腳手架
# cd gatsby-strapi-tutorial # strapi new api
進入項目目錄, 並運行Node.js服務器
# cd api # strapi start
這裏忽然時不時卡住了, 若是你很順利, 那麼能夠跳過此內容, 頻繁報錯以下
[root@whidy api]# strapi start DEBUG (24910 on whidy): Server wasn't able to start properly. ERROR (24910 on whidy): (hook:mongoose) takes too long to load
大概是網絡緣由, 我聯通網絡出問題, 換了電信幾番嘗試就行了.
操做過程當中頻繁出現剛纔的問題, 我以爲不是網絡問題那麼簡單, 我打算從數據庫方面着手完善一下試試, 固然後來證實, 一切問題都與MongoDB無關, 因此下面縮進內容能夠選擇性閱讀大多數狀況下我是不肯意理睬WARNING信息的, 只要不是ERROR就好, 可是此次我有點不爽, 後來折騰了半天發現有的很難處理, 好吧我錯了, 我想我仍是不死磕了吧😱.
soft rlimits too low
WARNING: soft rlimits too low. rlimits set to 1024 processes, 64000 files. Number of processes should be at least 32000 : 0.5 times number of files.
參閱:
versions of RHEL older than RHEL6
WARNING: You are running in OpenVZ which can cause issues on versions of RHEL older than RHEL6.
服務器硬件限制? 能夠安全忽略.
參閱: WARNING: You are running in OpenVZ which can cause issues on versions of RHEL older than RHEL6.
Access Control
覺得要搞帳戶什麼的, 而後運行mongo
命令, 建立了一個admin帳戶:
# mango > use admin > db.createUser( { user: "username", pwd: "userpassword", roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] } ) # mongo --port 27017 -u "username" -p "userpassword" --authenticationDatabase "admin"
其實我本身當時也不知道是搞啥, 其實徹底不要緊的操做. 不少人甚至官方文檔Start MongoDB without access control.也提到:
mongod --port 27017 --dbpath /data/db1
但是我一直報錯, 要麼說不存在, 搞半天才明白, 要手動建立, 建立好了, 又說服務被佔用, service mongod stop
停了服務, 連上去了, show dbs
發現跟以前的又不同, 沒有找到我以前看到的strapi
庫, 才恍然大悟, 原來其實我建立了一個跟以前無關的庫...
事實上, 啓動mongod服務的時候, 它鏈接了一個默認配置庫, 這個庫的路徑時早就建立好的, 經過查看/etc/mongod.conf
這個文件就知道了. 所以刪了那個沒用的db目錄. 接着操做.
後來次日早上, 再次執行strapi start
很順利. 我也沒辦法再研究昨天到底是爲何老是連不上了. 反正就是渣渣網絡常常會帶來各類坑!😡, 這段沒什麼做用的內容就過去了.
回到剛纔strapi start
, 成功以後, 咱們若是是本地操做的, 帶有界面的操做系統的話就能夠直接訪問http://localhost:1337/admin了, 若是也是遠程操做, 就改爲IP就行了.
接下來的操做是建立用戶, 原文已經圖文並茂, 傻子都能看懂的步驟了, 因爲篇幅過大, 我就簡單翻譯一下, 不詳細複述了嘿嘿~
按照原文操做:
article
的內容類型有三個字段: title
(字符串), content
(文本), author
(關係, 多文章對應一個用戶).添加幾項內容到數據庫
Add New Article
完成後, 就能夠訪問http://localhost:1337/article了.
到目前, 你的API搞定了, 咱們要搞靜態網站啦
首先, 全局安裝Gatsby CLI:
# npm install --global gatsby-cli
回到以前提到的gatsby-strapi-tutorial
目錄, 建立一個新博客:
# gatsby new blog
事情老是不是那麼順利.
報錯, 須要git
. 然而個人這臺嶄新的服務器還沒裝, 那就裝一個吧.
若是你的git已經部署OK, 而且上面這個操做沒有問題, 如下內容可忽略:
參考Download for Linux and Unix執行:
# yum install git
再次執行後依舊報錯(當前git版本1.7.1
)
error Command failed: git clone git://github.com/gatsbyjs/gatsby-starter-default.git blog --single-branch
推測是版本問題. 只好手動安裝了. 因而又找到這個安裝 Git
# yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel # wget https://www.kernel.org/pub/software/scm/git/git-2.16.1.tar.gz # tar -zxf git-2.16.1.tar.gz # cd git-2.16.1 # make prefix=/usr/local all # sudo make prefix=/usr/local install
漫長的make prefix=/usr/local all
以後, 提示:
SUBDIR perl
/usr/bin/perl Makefile.PL PREFIX=\'/usr/local\' INSTALL_BASE=\'\' --localedir=\'/usr/local/share/locale\' Can\'t locate ExtUtils/MakeMaker.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at Makefile.PL line 3. BEGIN failed--compilation aborted at Makefile.PL line 3. make[1]: *** [perl.mak] Error 2 make: *** [perl/perl.mak] Error 2
蛋疼, 等了半天, 又要解決這個問題, 好在看起來比較容易處理, 參考git fails to build in Fedora 14, 而後繼續執行最後兩條make
命令, 雖然最後出來不少看起來很奇怪的內容, 不過彷佛是成功了. 執行:
# git --version git version 2.16.1
接下來咱們再一次執行gatsby new blog
, 我擦還提示剛纔的...single-branch
的error, 這就坑爹了- -. 通過簡短的排查. 原來彷佛他仍是跑的舊版git, 須要刪掉以前yum自動安裝的git 1.7.1
, 我單純的覺得直接自動升級了. 因而:
# yum remove git
按照提示刪除成功後, 再次檢測git仍是ok的, 此次我第三次執行gatsby new blog
, 終於成功了!
我這小白也不知道linux軟件管理是咋整的. 反正能繼續執行卡了我半天的gatsby就行了吧...每次建立速度很慢, 執行
gatsby new blog
完成的時候提示added 1398 packages in 137.652s
, 大概就是2分鐘多, 多是安裝依賴包費時吧
建立成功後, 接着操做, 進入博客目錄
# cd blog
啓動服務器
# gatsby develop
理論上你就能夠經過http://localhost:8000訪問到默認的效果博客站點了.
然而又一次出現小插曲, 若是你是和我同樣遠程訪問, 也許如下內容對你有用
每次執行
gatsby develop
的時間甚至更長, 完成時提示以下:info bootstrap finished - 334.876 s DONE Compiled successfully in 90373ms 21:15:06 You can now view gatsby-starter-default in the browser. http://localhost:8000/ View GraphiQL, an in-browser IDE, to explore your site's data and schema http://localhost:8000/___graphql Note that the development build is not optimized. To create a production build, use gatsby build
大概用了6分鐘左右, 糟糕的是並不能經過遠程IP來訪問! 查看了目錄下的配置文件和官方文檔, 也沒查到. 絕望之時, 忽然在大量資料中看到webpack也有這樣的問題, 想起來以前webpack的server默認配置也是沒法經過ip訪問, 阜陽市人民政府可是webpack的
devServer
配置host: "0.0.0.0"
便可, 試了下:# gatsby develop --host 0.0.0.0
又通過4分鐘左右漫長等待, 此次成功了! 不過我嘗試搜索Gatsby究竟用的什麼服務器啓動, 爲什麼不能像webpack那樣加一段配置呢, 卻沒有找到. 後來湊巧找到了一篇webpack下的issue, Server can't be accessed via IP, 有人提到過這條命令.
所以, 從小插曲中來看, 遠程訪問控制的開發者, 須要加個參數, 具體命令:
# gatsby develop --host 0.0.0.0
這樣, 至此開發模式服務器搞定.
Gatsby understands this pretty well. So its creators decided to build a specific and independent layer: the data layer. This entire system is strongly powered by GraphQL.
前面有一些插件介紹很少說了, 執行安裝:
# npm install --save gatsby-source-strapi
完成後, 須要作些配置, 修改gatsby-config.js
文件, 替換成如下內容:
module.exports = { siteMetadata: { title: `Gatsby Default Starter`, }, plugins: [ `gatsby-plugin-react-helmet`, { resolve: `gatsby-source-strapi`, options: { apiURL: `http://localhost:1337`, contentTypes: [ // List of the Content Types you want to be able to request from Gatsby. `article`, `user` ] }, }, ], }
保存後, 重啓Gatsby服務器
爲了在首頁顯示文章列表, 咱們須要修改首頁代碼以下:
路徑: src/pages/index.js
import React from 'react' import Link from 'gatsby-link' const IndexPage = ({ data }) => ( <div> <h1>Hi people</h1> <p>Welcome to your new Gatsby site.</p> <p>Now go build something great.</p> <ul> {data.allStrapiArticle.edges.map(document => ( <li key={document.node.id}> <h2> <Link to={`/${document.node.id}`}>{document.node.title}</Link> </h2> <p>{document.node.content}</p> </li> ))} </ul> <Link to="/page-2/">Go to page 2</Link> </div> ) export default IndexPage export const pageQuery = graphql` query IndexQuery { allStrapiArticle { edges { node { id title content } } } } `
這裏就應用到了GraphQL啦, 好激動呢. 咱們導出pageQuery
, 一個GraphQL查詢會請求文章列表, 咱們只須要將須要查詢的字段添加進去就行了~
而後咱們傳遞{ data }
這個結構對象做爲IndexPage
參數, 遍歷它的allStrapiArticles
對象, 來展現數據.
GraphQL查詢能夠快速生成, 你能夠嘗試在http://localhost:8000/___graphql修改, 並測試.
首頁有了列表以後, 咱們還要訪問文章頁面呢, 接下來寫一個模板:
路徑: src/templates/article.js
import React from 'react' import Link from 'gatsby-link' const ArticleTemplate = ({ data }) => ( <div> <h1>{data.strapiArticle.title}</h1> <p>by <Link to={`/authors/${data.strapiArticle.author.id}`}>{data.strapiArticle.author.username}</Link></p> <p>{data.strapiArticle.content}</p> </div> ) export default ArticleTemplate export const query = graphql` query ArticleTemplate($id: String!) { strapiArticle(id: {eq: $id}) { title content author { id username } } } `
你須要手動建立這個目錄和文件, 固然Gatsby並不知道模板什麼時候展現. 每篇文章都須要一個特別的URL, 感謝Gatsby提供的createPage
函數.
首先, 咱們寫個makeRequest
函數來處理GraphQL請求. 而後經過createPage
函數使咱們在獲取的文章列表後爲它們建立一個頁面, 路徑爲文章id的URL, 回到blog
目錄, 呼倫貝爾市人民政府修改gatsby-node.js
文件
const path = require(`path`); const makeRequest = (graphql, request) => new Promise((resolve, reject) => { // Query for nodes to use in creating pages. resolve( graphql(request).then(result => { if (result.errors) { reject(result.errors) } return result; }) ) }); // Implement the Gatsby API 「createPages」. This is called once the // data layer is bootstrapped to let plugins create pages from data. exports.createPages = ({ boundActionCreators, graphql }) => { const { createPage } = boundActionCreators; const getArticles = makeRequest(graphql, ` { allStrapiArticle { edges { node { id } } } } `).then(result => { // Create pages for each article. result.data.allStrapiArticle.edges.forEach(({ node }) => { createPage({ path: `/${node.id}`, component: path.resolve(`src/templates/article.js`), context: { id: node.id, }, }) }) }); // Query for articles nodes to use in creating pages. return getArticles; };
再次重啓Gatsby服務器.
如今你就能經過點擊首頁的文章進入到文章內容頁面了.
雖然這個彷佛並不重要, 不過仍是加上學習一下吧😁
添加做者頁和建立文章頁很類似, 咱們仍是先建立個模板:
路徑: src/templates/user.js
import React from 'react' import Link from 'gatsby-link' const UserTemplate = ({ data }) => ( <div> <h1>{data.strapiUser.username}</h1> <ul> {data.strapiUser.articles.map(article => ( <li key={article.id}> <h2> <Link to={`/${article.id}`}>{article.title}</Link> </h2> <p>{article.content}</p> </li> ))} </ul> </div> ) export default UserTemplate export const query = graphql` query UserTemplate($id: String!) { strapiUser(id: { eq: $id }) { id username articles { id title content } } } `
而後再次修改gatsby-node.js
來建立做者URLs:
const path = require(`path`); const makeRequest = (graphql, request) => new Promise((resolve, reject) => { // Query for article nodes to use in creating pages. resolve( graphql(request).then(result => { if (result.errors) { reject(result.errors) } return result; }) ) }); // Implement the Gatsby API 「createPages」. This is called once the // data layer is bootstrapped to let plugins create pages from data. exports.createPages = ({ boundActionCreators, graphql }) => { const { createPage } = boundActionCreators; const getArticles = makeRequest(graphql, ` { allStrapiArticle { edges { node { id } } } } `).then(result => { // Create pages for each article. result.data.allStrapiArticle.edges.forEach(({ node }) => { createPage({ path: `/${node.id}`, component: path.resolve(`src/templates/article.js`), context: { id: node.id, }, }) }) }); const getAuthors = makeRequest(graphql, ` { allStrapiUser { edges { node { id } } } } `).then(result => { // Create pages for each user. result.data.allStrapiUser.edges.forEach(({ node }) => { createPage({ path: `/authors/${node.id}`, component: path.resolve(`src/templates/user.js`), context: { id: node.id, }, }) }) }); // Queries for articles and authors nodes to use in creating pages. return Promise.all([ getArticles, getAuthors, ]) };
重啓服務器, 刷新頁面, Wow! 大功告成! 時不時很酷!!!