Gridsome 生成靜態站點基礎

cloveryuan發表於2020-09-27

1. Gridsome是什麼

  • 一個免費、開源、基於VUE.js技術棧的靜態網站生成器
  • 官方網址:https://gridsome.org
  • GitHub: https://github.com/gridsome/gridsome

在這裡插入圖片描述

2. 什麼是靜態網站生成器

  • 靜態網站生成器是使用一系列配置、模板以及資料,生成靜態HTML檔案及相關資源的工具
  • 這個功能也叫做預渲染
  • 生成的網站不需要類似PHP這樣的伺服器
  • 只需要放到支援靜態資源的WebServer或者CDN上即可執行

3. 靜態網站的好處

  • 省錢:不需要專業的伺服器,只要能託管靜態檔案的空間即可
  • 快速:不經過後端伺服器的處理,只傳輸內容
  • 安全:沒有後端程式的支援,自然會更安全

4. 常見的靜態網站生成器

  • Jekyll(Ruby)
  • Hexo(Node)
  • Hugo(Golang)
  • Gatsby(Node/React)
  • Gridsome(Node/Vue)
  • 另外,Next.js/Nuxt.js也能生成靜態網站,但它們更多被認為是SSR(服務端渲染)框架

5. JAMStack

  • 這類靜態網站生成器還有個漂亮的名字叫做JAMStack
  • JAMStack的JAM是JavaScript、API和Markup的首字母組合
  • 本質上是一種胖前端,通過呼叫各種API來實現更多的功能
  • 其實也是一種前後端的模式,只不過離的比較開,甚至前後端來自多個不同的廠商。

6. 靜態應用的使用場景

  • 不適合有大量路由頁面的應用
    • 如果您的站點有成百上千條路由頁面,則預渲染將非常緩慢。當然,您每次更新之需要做一次,但是可能要花一些時間。大多數人不會最終獲得數千條靜態路由頁面,而只是以防萬一。
  • 不適合有大量動態內容的應用
    • 如果渲染路由中包含特定於使用者檢視其內容或其他動態源的內容,則應確保您具有可以顯示的佔位符元件,直到動態內容載入到客戶端為止,否則可能有點怪異。

7. Gridsome學習建議

  • 使用Gridsome需要有一定的Vue基礎,如果有基礎,看過文件,只會覺得它比Vue本身更簡單一些。

二、Gridsome基礎

1. 建立Gridsome專案

Gridsome依賴sharp,國內的使用者很難安裝成功sharp,所以使用淘寶映象安裝sharp。

npm config set sharp_binary_host "https://npm.taobao.org/mirrors/sharp"
npm config set sharp_libvips_binary_host "https://npm.taobao.org/mirrors/sharp-libvips"

sharp是C++語言編寫的,所以還要安裝C++環境。
sharp官網

安裝node-gyp,編譯C++擴充套件包
npm install -g node-gyp

根據node-gyp的官方文件 https://github.com/nodejs/node-gyp 的說明對不同作業系統進行安裝命令:

On Unix

  • Python v2.7, v3.5, v3.6, v3.7, or v3.8
  • make
  • A proper C/C++ compiler toolchain, like GCC

On macOS

ATTENTION: If your Mac has been upgraded to macOS Catalina (10.15), please read macOS_Catalina.md.

  • Python v2.7, v3.5, v3.6, v3.7, or v3.8
  • Xcode
    • You also need to install the XCode Command Line Tools by running xcode-select --install. Alternatively, if you already have the full Xcode installed, you can find them under the menu Xcode -> Open Developer Tool -> More Developer Tools.... This step will install clang, clang++, and make.

On Windows

Install the current version of Python from the Microsoft Store package.
Install all the required tools and configurations using Microsoft’s windows-build-tools using npm install --global windows-build-tools(搜尋cmd,然後右鍵“以管理員身份執行”,然後再安裝) from an elevated PowerShell or CMD.exe (run as Administrator).

然後根據Gridsome官網https://gridsome.org/docs/的教程安裝gridsome,

npm install --global @gridsome/cli

拉取遠端模板到本地:

gridsome create my-gridsome-site

如果安裝不成功,修改host檔案
安裝依賴的時候比較慢,又沒有進度條,可以按ctrl+C中斷掉,然後進入已經生成的my-gridsome-site目錄下,執行rm -rf node_modules刪除半成品node_modules,然後重新執行npm install,此時就能看到進度了。

安裝好依賴之後,可以在package.json裡檢視命令。

執行npm run develop啟動專案

在這裡插入圖片描述

訪問http://localhost:8080/看到以下頁面就證明啟動成功了。

在這裡插入圖片描述

2. 預渲染

建立一個Foo.vue頁面

<template>
  <div>
    <h1>Foo Page</h1>
  </div>
</template>

<script>
export default {
  name: 'FooPage'
}
</script>

<style>

</style>

然後執行npm run build進行打包,打包後生成了一個dist檔案

在這裡插入圖片描述

然後起一個靜態服務:serve dist
如果沒有serve,要全域性安裝下npm i serve -g
然後訪問http://localhost:5000就可以看到頁面是由服務端渲染好了返回的,然後客戶端的互動都是單頁面應用形式。

3. 目錄結構

在這裡插入圖片描述

src/main.js是整個專案的啟動入口,裡面載入了/layouts/Default.vue

// This is the main.js file. Import global CSS and scripts here.
// The Client API can be used here. Learn more: gridsome.org/docs/client-api

import DefaultLayout from '~/layouts/Default.vue'

export default function (Vue, { router, head, isClient }) {
  // Set default layout as a global component
  Vue.component('Layout', DefaultLayout)
}

Default.vue中有個特別之處:

<static-query>
query {
  metadata {
    siteName
  }
}
</static-query>

這個query是查詢gridsome資料給元件用的。

src/templates資料夾是放集合的節點。

src/pages是路由頁面。

src/layouts放佈局元件。

src/components放公共元件。

src/.temp放打包過程生成的檔案。

.catch是快取的一些內容

node_modules放第三方包

static放不需要打包編譯的檔案,指靜態的資源

gridsome.config.js gridsome的配置檔案

gridsome.server.js 也是girdsome的配置檔案,是配置服務端的,Gridsome內部的服務配置。

4. 專案配置

檢視Gridsome的配置

gridsome.config.js

// This is where project configuration and plugin options are located.
// Learn more: https://gridsome.org/docs/config

// Changes here require a server restart.
// To restart press CTRL + C in terminal and run `gridsome develop`

module.exports = {
  siteName: '肖戰', // 頁面上的名稱
  pathPrefix: '/my-app', // 路徑字首, 部署是否有子目錄
  templates: {}, // 定義路由模版
  configgureWebapck: {}, // type Object | Function webpack 配置
  siteDescription: '大前端', // meta 名稱
  plugins: [] // 配置外掛
}

5. Pages

pages 就是我們專案當中的路由元件,最終會生成路由頁面,在編譯的時候會成為靜態的HTML
(1) 基於檔案形式建立

直接在src/pages目錄下建立一個檔案,就是一個新的路由了

(2) 基於程式設計方式通過createPage

gridsome.server.js

api.createPages(({ createPage }) => {
    // Use the Pages API here: https://gridsome.org/docs/pages-api/
    createPage({
      path: '/my-page',
      component: './src/templates/MyPage.vue'
    })
  })

src/templates/MyPage.vue

<template>
  <div>
    <h1>
      MyPage
    </h1>
  </div>
</template>

<script>
export default {
  name: 'MyPage',
  metaInfo: {
    title: 'MyPage' // 配置header中的title
  }
}
</script>

<style>

</style>

重啟專案後訪問http://localhost:8080/my-page就可以看到MyPage頁面。

6. 動態路由

(1) pages下面建立的頁面檔名稱用方括號括起來,作為動態路由引數

src/pages/user/[id].vue
在這裡插入圖片描述

<template>
  <div>
    <h1>
      User {{ $route.params.id }} Page
    </h1>
  </div>
</template>

<script>
export default {
  name: 'UserPage'
}
</script>

<style>

</style>

重啟後訪問:http://localhost:8080/user/1

就可以看到 User 1 Page 這個內容了

(2) 程式設計方式

gridsome.server.js

api.createPages(({ createPage }) => {
  createPage({
    path: '/user/:id(\\d+)',
    component: './src/templates/User.vue'
  })
})

7. 新增集合

定義一個頁面Posts1.vue

<template>
  <Layout>
      <h1>Posts1</h1>
      <ul>
      <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
    </ul>
    </Layout>
</template>

<script>
import axios from 'axios'
export default {
  name: 'Posts1',
  data () {
    return {
      posts: []
    }
  },
  async created () {
    const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
    this.posts = data
  }
}
</script>

<style>

</style>

資料是在客戶端動態載入請求過來的,不是預渲染生成的。

想要資料預渲染,得使用Gridsome中的集合Collections

// gridsome.server.js
const axios = require('axios')

module.exports = function (api) {
  api.loadSource(async actions => {
    const collection = actions.addCollection('Post')

    const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')

    for (const item of data) {
      collection.addNode({
        id: item.id,
        title: item.title,
        content: item.body
      })
    }
  })
}

8. 在GraphQL中查詢資料

在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述

9. 在頁面中查詢GraphQL查詢資料

Posts2.vue,靜態頁面,服務端渲染的

<template>
  <Layout>
      <h1>Posts2</h1>
      <ul>
        <li v-for="edge in $page.posts.edges" :key="edge.node.id">
          <g-link to="/">{{edge.node.title}}</g-link>
        </li>
      </ul>
    </Layout>
</template>

<script>
export default {
  name: 'Posts2',
}
</script>

<style>

</style>

<page-query>
query {
  posts: allPost {
    edges {
      node {
        id
        title
      }
    }
  }
}
</page-query>


10. 使用模板渲染結點

配置動態路由模板

// gridsome.config.js
module.exports = {
  siteName: '拉鉤教育',
  siteDescription: '大前端',
  plugins: [],
  templates: {
    Post: [
      {
        path: '/posts/:id',//gridsome.serve裡面新增集合資料裡面唯一主鍵這裡是id
        component: './src/templates/Post.vue'
      }
    ]
  }
}

模板頁面src/template/Post.vue,預渲染頁面,從GraphQL獲取的資料

<template>
  <Layout>
    <h1>{{$page.post.title}}</h1>
    <p>{{$page.post.content}}</p>
  </Layout>
</template>

<page-query>
query($id: ID!) { # 動態路由引數會自動傳入進來
  post(id: $id) {
    id
    title
    content
  }
}
</page-query>
<script>
export default {
  name: 'PostPage',
  metaInfo () {
    return {
      title: this.$page.post.title
    }
  }
}
</script>

<style>

</style>

metaInfo寫成函式形式可以通過this.$page獲取到graphQL返回的資料。

三、Gridsome案例

1. 建立專案

gridsome create blog-with-gridsome

當進入install的時候按ctrl C中斷,然後進入資料夾執行npm install來安裝第三方包

cd blog-with-gridsome
npm install

2. 處理首頁模板

Fork Bootstrap的一個模板:https://github.com/StartBootstrap/startbootstrap-clean-blog

然後blog-with-gridsome平級目錄執行git clone https://github.com/cloveryuan/startbootstrap-clean-blog.git --depth=1,只克隆最後一個版本就行了。

然後回到我們的專案中,安裝需要的依賴

npm i bootstrap
npm i @fortawesome/fontawesome-free

建立src/assets/css/index.css

@import url('https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic');
@import url('https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800');

  /* 下面將startbootstrap-clean-blog裡面的css/clean-blog.css裡面的內容複製到此處 */

在src/main.js中開始位置增加:

import 'bootstrap/dist/css/bootstrap.min.css'
import '@fortawesome/fontawesome-free/css/all.min.css'

import './assets/css/index.css'

把startbootstrap-clean-blog中的img資料夾拷貝到我們的專案中的static中,作為靜態資源使用。

把startbootstrap-clean-blog中的index.html裡面的body部分的HTML程式碼拷貝到我們的專案中的src/pages/Index.vue中

3. 處理其他頁面模板

將Index.vue中的頭部、尾部程式碼剪下到layouts/Default.vue中,注意頭尾程式碼塊中間要放一個<slot/>插槽

然後將Index.vue的最外層元件由div改為Layout。Layout已經在全域性註冊過了,可以直接使用

然後寫Post.vue、About.vue、Contact.vue頁面,把startbootstrap-clean-blog中的post.html、about.html、contact.html中的程式碼拿過來即可。圖片載入不了,記得在img前面加上/,從根路徑出發

4. 使用本地md檔案管理文章內容

npm i @gridsome/source-filesystem
npm i @gridsome/transformer-remark # 轉換MD檔案

建立兩個md檔案, content/blog/article1.md、contetn/blog/artcle2.md

//gridsome.config.js
module.exports = {
  siteName: 'blog',
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'BlogPost',
        path: './content/blog/**/*.md',
      }
    }
  ]
}

在GraphQL中查詢資料:

在這裡插入圖片描述

5. Strapi介紹

網址:https://strapi.io/

strapi是一個通用的內容管理系統。

執行建立strapi命令

yarn create strapi-app my-project --quickstart

在這裡插入圖片描述
建立一個Content Type
在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述

6. 使用strapi資料介面

預設是Restful API

https://strapi.io/documentation/v3.x/content-api/api-endpoints.html#get-an-entry

在這裡插入圖片描述

給使用者配置許可權:設定下也可配置許可權

在這裡插入圖片描述

使用Postman進行介面測試:

在這裡插入圖片描述

7. 訪問受保護的API

在這裡插入圖片描述

建立一個使用者:admin, 123456

在這裡插入圖片描述

註冊、登入的API:https://strapi.io/documentation/v3.x/plugins/users-permissions.html#concept

使用Postman測試登入介面 拿到token就是Authorization

在這裡插入圖片描述

請求其他介面時,http頭部要增加授權資訊Authorization: Bearer ${token}

在這裡插入圖片描述

8. 將Strapi資料預取到Gridsome應用中

安裝

npm install @gridsome/source-strapi

使用

// gridsome.config.js
export default {
  plugins: [
    {
      use: '@gridsome/source-strapi',
      options: {
        apiURL: 'http://localhost:1337',
        queryLimit: 1000, // Defaults to 100
        contentTypes: ['post','tag'],//後面在strapi上建的集合
        //singleTypes: ['impressum'],
        // Possibility to login with a Strapi user,
        // when content types are not publicly available (optional).
        loginData: {
          identifier: '',
          password: ''
        }
      }
    }
  ]
}

重啟應用,才會拉取最新資料。

9. 設計文章標籤資料模型

刪除原來的測試資料:

在這裡插入圖片描述

建立新的Content Type,名稱為Post,有四個欄位

在這裡插入圖片描述

再建立一個新的Content Type,名稱為Tag,有兩個欄位,其中欄位posts為引用型別,為多對多的關係

在這裡插入圖片描述

在這裡插入圖片描述

新增一個Tag,標題為HTML

然後修改post裡面的標題為post 1的資料,選擇Tags為HTML

在這裡插入圖片描述

然後回到Tags表中的HTML資料的編輯屏,還可以再關聯別的Posts

在這裡插入圖片描述

10. 展示文章列表、分頁

src/pages/Index.vue

<template>
  <Layout>

    <!-- Page Header -->
    <header class="masthead" style="background-image: url('/img/home-bg.jpg')">
      <div class="overlay"></div>
      <div class="container">
        <div class="row">
          <div class="col-lg-8 col-md-10 mx-auto">
            <div class="site-heading">
              <h1>Clean Blog</h1>
              <span class="subheading">A Blog Theme by Start Bootstrap</span>
            </div>
          </div>
        </div>
      </div>
    </header>

    <!-- Main Content -->
    <div class="container">
      <div class="row">
        <div class="col-lg-8 col-md-10 mx-auto">
          <div class="post-preview" v-for="edge in $page.posts.edges" :key="edge.node.id">
            <g-link :to="'post/'+edge.node.id">
              <h2 class="post-title">
                {{edge.node.title}}
              </h2>
            </g-link>
            <p class="post-meta">
              Posted by
              <a href="#">{{edge.node.created_by.firstname + edge.node.created_by.lastname}}</a>
              on {{edge.node.created_at}}
            </p>
            <p>
              <span v-for="tag in edge.node.tags" :key="tag.id">
                <a href="">{{tag.title}}</a>
                 &nbsp;&nbsp;
              </span>
            </p>
            <hr />
          </div>
          <Pager :info="$page.posts.pageInfo" />
        </div>
      </div>
    </div>

  </Layout>
</template>

<page-query>
query ($page: Int) {
  posts: allStrapiPost (perPage: 2, page: $page) @paginate {
    pageInfo {
      totalPages
      currentPage
    }
    edges {
      node {
        id
        title
        created_at
        created_by {
          id
          firstname
          lastname
        }
        tags {
          id
          title
        }
      }
    }
  }
}
</page-query>
<script>
import { Pager } from 'gridsome'
export default {
  name: 'HomePage',
  components: {
    Pager
  },
  metaInfo: {
    title: "Hello, world!",
  },
};
</script>

11. 展示文章詳情

gridsome.config.js


module.exports = {
  siteName: 'Gridsome',
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'BlogPost',
        path: './content/blog/**/*.md'
      }
    },
    {
      use: '@gridsome/source-strapi',
      options: {
        apiURL: 'http://localhost:1337',
        queryLimit: 1000, // Defaults to 100
        contentTypes: ['post', 'tag'], // StrapiPost
        // typeName: 'Strapi,
        // singleTypes: ['impressum'],
        // Possibility to login with a Strapi user,
        // when content types are not publicly available (optional).
        // loginData: {
        //   identifier: '',
        //   password: ''
        // }
      }
    }
  ],
  templates: {
    // StrapiPost為上面Plugin中配置的typeName和contentTypes的組合
    StrapiPost: [
      {
        path: '/post/:id',
        component: './src/templates/Post.vue'
      }
    ]
  }
}

src/templates/Post.vue

<template>
  <Layout>
    <!-- Page Header -->
    <header
      class="masthead"
      :style="{backgroundImage: `url(http://localhost:1337${$page.post.cover.url})`}"
    >
      <div class="overlay"></div>
      <div class="container">
        <div class="row">
          <div class="col-lg-8 col-md-10 mx-auto">
            <div class="post-heading">
              <h1>{{$page.post.title}}</h1>
              <span class="meta"
                >Posted by
                <a href="#">{{$page.post.created_by.firstname + $page.post.created_by.lastname}}</a>
                on {{$page.post.created_at}}</span
              >
            </div>
          </div>
        </div>
      </div>
    </header>

    <!-- Post Content -->
    <article>
      <div class="container">
        <div class="row">
          <div class="col-lg-8 col-md-10 mx-auto">
            {{$page.post.content}}
          </div>
        </div>
      </div>
    </article>
  </Layout>
</template>

<page-query>
query($id: ID!) {
  post: strapiPost(id: $id) {
    id
    title
    content
    cover {
      url
    }
    tags {
      id
      title
    }
    created_at
    created_by {
      id
      firstname
      lastname
    }
  }
}
</page-query>

<script>
export default {
  name: 'PostPage'
}
</script>

<style></style>

12. 處理Markdown格式的文章內容

安裝markdown處理器:npm install markdown-it

src/templates/Post.vue

<div class="col-lg-8 col-md-10 mx-auto" v-html="mdToHtml($page.post.content)">
</div>

<script>
import MarkDownIt from 'markdown-it'
const md = new MarkDownIt()
export default {
  name: 'PostPage',
  methods: {
    mdToHtml (markdown) {
    return md.render(markdown)
  }
  }
}
</script>

13. 文章標籤處理

src/templates/Tag.vue

<template>
    <Layout>

    <!-- Page Header -->
    <header class="masthead" style="background-image: url('/img/home-bg.jpg')">
      <div class="overlay"></div>
      <div class="container">
        <div class="row">
          <div class="col-lg-8 col-md-10 mx-auto">
            <div class="site-heading">
              <h1># {{$page.tag.title}}</h1>
            </div>
          </div>
        </div>
      </div>
    </header>

    <!-- Main Content -->
    <div class="container">
      <div class="row">
        <div class="col-lg-8 col-md-10 mx-auto">
          <div class="post-preview" v-for="post in $page.tag.posts" :key="post.id">
            <g-link :to="'post/'+post.id">
              <h2 class="post-title">
                {{post.title}}
              </h2>
            </g-link>
            <p class="post-meta">
              Posted by
              on {{post.created_at}}
            </p>
            <hr />
          </div>
        </div>
      </div>
    </div>

  </Layout>
</template>

<page-query>
query($id: ID!) {
  tag: strapiTag(id: $id) {
    title
    id
    posts {
      id
      title
      created_at
    }
  }
}
</page-query>

<script>
export default {
  name: 'TagPage'
}
</script>

<style>

</style>

gridsome.config.js


module.exports = {
  siteName: 'Gridsome',
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'BlogPost',
        path: './content/blog/**/*.md'
      }
    },
    {
      use: '@gridsome/source-strapi',
      options: {
        apiURL: 'http://localhost:1337',
        queryLimit: 1000, // Defaults to 100
        contentTypes: ['post', 'tag'], // StrapiPost

      }
    }
  ],
  templates: {
    // StrapiPost為上面Plugin中配置的typeName和contentTypes的組合
    StrapiPost: [
      {
        path: '/post/:id',
        component: './src/templates/Post.vue'
      }
    ],
    StrapiTag: [
      {
        path: '/tag/:id',
        component: './src/templates/Tag.vue'
      }
    ]
  }
}

14. 網站基本設定

建立Single Type

在這裡插入圖片描述

建立一個名為general的Single Type,有三個欄位,如下:

在這裡插入圖片描述

配置general資料:

在這裡插入圖片描述

gridsome.config.js的source-strapi外掛增加singleTypes: ['general']配置,就可以獲取general資料,重啟專案就生效。

src/pages/Index.vue

<!-- Page Header -->
    <header
      class="masthead"
      :style="{
        backgroundImage: `url(http://localhost:1337${general.cover.url})`
      }"
    >
      <div class="overlay"></div>
      <div class="container">
        <div class="row">
          <div class="col-lg-8 col-md-10 mx-auto">
            <div class="site-heading">
              <h1>{{general.title}}</h1>
              <span class="subheading">{{general.subtitle}}</span>
            </div>
          </div>
        </div>
      </div>
    </header>
<page-query>
query ($page: Int) {
  # ----
 
  general: allStrapiGeneral {
    edges {
      node {
        title
        subtitle
        cover {
          url
        }
      }
    }
  }
}
</page-query>

<script>
import { Pager } from 'gridsome'
export default {
// ----
  
  computed: {
    general () {
      return this.$page.general.edges[0].node
    }
  }
};
</script>

15. 聯絡我 Contact頁面

建立一個contact的Content Type

在這裡插入圖片描述

使用Postman建立一條資料

在這裡插入圖片描述

頁面中使用傳統客戶端表單提交功能

src/pages/Contact.vue

<input v-model="form.name" type="text" class="form-control" placeholder="Name" id="name" required data-validation-required-message="Please enter your name.">

<input v-model="form.email" type="email" class="form-control" placeholder="Email Address" id="email" required data-validation-required-message="Please enter your email address.">

<input v-model="form.phone" type="tel" class="form-control" placeholder="Phone Number" id="phone" required data-validation-required-message="Please enter your phone number.">

<textarea v-model="form.message" rows="5" class="form-control" placeholder="Message" id="message" required data-validation-required-message="Please enter a message."></textarea>

<button type="submit" class="btn btn-primary" id="sendMessageButton" @click.prevent="onSubmit">Send</button>

<script>
import axios from 'axios'
export default {
  name: 'ContactPage',
  data () {
    return {
      form: {
        name: '',
        email: '',
        phone: '',
        message: ''
      }
    }
  },
  methods: {
    async onSubmit () {
      try {
        const { data } = await axios({
          method: 'POST',
          url: 'http://localhost:1337/contacts',
          data: this.form
        })
        window.alert('傳送成功')
      } catch (e) {
        alert('傳送失敗,請稍後重試')
      }
    }
  }
}
</script>

16. 部署strapi

先部署strapi、再部署Gridsome。strapi部署環境依賴於node環境的伺服器,而Gridsome只需要支援靜態網頁的伺服器就行。

(1) 配置為strapi後臺服務配置資料庫為MySQL

其他資料庫配置可以參考這裡:https://strapi.io/documentation/v3.x/concepts/configurations.html#database

config/database.js

module.exports = ({ env }) => ({
  defaultConnection: 'default',
  connections: {
    default: {
      connector: 'bookshelf',
      settings: {
        client: 'mysql',
        host: env('DATABASE_HOST', 'localhost'),// strapi部署的伺服器與MySQL所在的伺服器是同一個伺服器,主機就直接寫localhost
        port: env.int('DATABASE_PORT', 3306),
        database: env('DATABASE_NAME', 'blog'),
        username: env('DATABASE_USERNAME', 'blog'),
        password: env('DATABASE_PASSWORD', 'oPqc0Am9lfhWKNuT'),
      },
      options: {},
    },
  },
});

安裝MySQL資料的依賴

npm install mysql
(2) 將程式碼上傳到gitee上
git init
echo node_modules > .gitignore
git add .
git commit -m"第一次提交"
git remote add origin git@gitee.com:jiailing/blog-backend.git
git push -u origin master
(3) 登入到伺服器進行部署
  • ssh root@47.110.10.236進入伺服器,
  • 拉去遠端程式碼(git clone https://gitee.com/cloveryuan/blog-backend.git),
  • cd blog-backend
  • 安裝依賴包(npm i)
  • 打包(npm run build)
  • pm2 start npm – run start – name blog-backend (通過pm2啟動,blog-backend是起的別名)

先進入MySQL

mysql -uroot -p

建立使用者blog,和資料庫blog,並且給該使用者授權操作該資料庫
在這裡插入圖片描述

CREATE USER 'blog'@'%' IDENTIFIED BY 'oPqc0Am9lfhWKNuT';
CREATE DATABASE blog;
FLUSH PRIVILEGES;
GRANT ALL ON blog.* TO 'blog'@'%';
exit;

然後回到存放程式碼的目錄下,拉取gitee上的程式碼,並且安裝專案依賴

git clone https://gitee.com/jiailing/blog-backend
cd blog-backend
npm config set sharp_binary_host "https://npm.taobao.org/mirrors/sharp"
npm config set sharp_libvips_binary_host "https://npm.taobao.org/mirrors/sharp-libvips"
npm install
npm run build
npm run start

或者執行npm run develop也可以啟動專案。

如果執行build時命令列卡在了90%進度時,直接中斷掉執行start就可以了。

然後就可以通過 主機地址+1337埠號來訪問頁面了。

start 此時命令列被佔用,退出命令列服務就會停止,所以使用pm2守護程式,讓一個node應用啟動在後臺

pm2 start --name blog-backend npm -- run start

或者

pm2 start --name blog-backend npm -- run develop

記得去伺服器的例項安全組新增埠1337
在這裡插入圖片描述

依舊是通過 主機地址+1337埠號來訪問頁面。

在這裡插入圖片描述

登入後別忘了給使用者分配許可權

17. 把本地服務連通遠端應用

grid.config.js中的strapi外掛的配置中的URL介面要改為線上介面,

apiURL: process.env.GRIDSOME_API_URL

為了區分開發介面和生產介面,可以配置環境變數

.env.production

GRIDSOME_API_URL=http://jiailing.com:1337

.env.development

GRIDSOME_API_URL=http://localhost:1337

在src/main.js中注入環境變數到頁面模板中使用:

export default function (Vue, { router, head, isClient }) {
  Vue.mixin({
    data () {
      return {
        GRIDSOME_API_URL: process.env.GRIDSOME_API_URL
      }
    }
  })
  // Set default layout as a global component
  Vue.component('Layout', DefaultLayout)
}

將頁面中之前用到localhost:1337的路徑都替換掉,如背景圖片:

:style="{backgroundImage: `url(${GRIDSOME_API_URL+$page.post.cover.url})`}"

18. 部署Gridsome應用

vercel可以使得在Gridsome程式碼發生了改變,或者strapi的資料發生了改變時,都可以觸發Gridsome的自動部署。

Vercel網址:vercel.com

使用GitHub登入,GitHub的郵箱是QQ郵箱會出問題,我改成了sina郵箱就可以了。

在這裡插入圖片描述
匯入blog前端倉庫的地址,我已經將專案上傳到了GitHub上了。
在這裡插入圖片描述

飄下了成功的綵帶~

在這裡插入圖片描述

建立自動部署鉤子

在這裡插入圖片描述

複製鉤子到strapi裡

在這裡插入圖片描述

在strapi的設定裡新增webHook,請求地址為剛才複製的Vercel的裡部署鉤子地址。

在這裡插入圖片描述

修改程式碼提交或者是strapi資料變化都會觸發Vercel裡的專案重新部署:

在這裡插入圖片描述


相關文章