当前位置: 首页 > 工具软件 > Gridsome > 使用案例 >

使用gridsome和strapi搭建静态站点

宇文灿
2023-12-01

文章内容输出来源:拉勾教育前端高薪训练营

什么是静态网站生成器

  • 静态网站生成器是使用一系列配置、模板以及数据,生成静态HTML文件及相关资源的工具
  • 这个功能也叫预渲染
  • 生成的网站不需要类似PHP这样的服务器
  • 只需要放在支持静态资源的Web Server或CDN上即可运行

静态网站的好处

  • 省钱,不需要专业的服务器,只要能托管静态文件的空间即可
  • 快速,不经过后端服务器的处理,只传输内容
  • 安全,没有后端程序执行,自然会更安全

常见的静态网站生成器

  • Jekyll(Ruby)
  • Hexo (Node)
  • Hugo (Golang)
  • Gatsby (Node/React)
  • Gridsome (Node/Vue)
    另外,Next.js和Nuxt.js也能生存静态网站,但是它们更多被认为是SSR(服务端渲染)框架

这类静态网站生成器还有个名字叫JAMStack:JavaScript、API和Markup的首字母组合,其本质上是一种胖前端,通过调用各种API来实现更多的功能,也可以理解为是一种前后端模式,只不过分得特别明显,甚至前后端来自多个不同的厂商

静态应用的使用场景

  • 不适合有大量路由页面的应用:如果您的站点有成百上千条路有页面,则预渲染将非常缓慢。当然,您每次更新只需要做一次,但是可能要花一些时间。大多数人不会最终获得数千条静态路由页面,而只是以防万一
  • 不适合有大量动态内容的应用:如果渲染路线中包含特定于用户查看其内容或其他动态源的内容,则应确保您具有可以显示的占位符组件,知道动态内容加载到客户端为止,否则可能有点怪异

GridSome

安装

$ yarn global add @gridsome/cli
or
$ npm install --global @gridsome/cli

初始化

$ gridsome create my-gridsome-site

gridsome配置

查看官方文档链接.

路由

  • gridsome会根据pages牡目录自动生成路由

src/pages/Index.vue becomes /(The frontpage)
src/pages/AboutUs.vue becomes /about-us/
src/pages/about/Vision.vue becomes /about/vision/
src/pages/blog/Index.vue becomes /blog/

  • 编程方式创建路由
    gridsome.server.js
module.exports = function (api) {
  api.createPages(({ createPage }) => {
    createPage({
      path: '/my-page',
      component: './src/templates/MyPage.vue'
    })
  })
}
  • 动态路由
    基于文件的方式

src/pages/user/[id].vue becomes /user/:id.
src/pages/user/[id]/settings.vue becomes /user/:id/settings.

基于编程方式
gridsome.server.js

module.exports = function (api) {
  api.createPages(({ createPage }) => {
    createPage({
      path: '/user/:id(\\d+)',
      component: './src/templates/User.vue'
    })
  })
}
  • Page meta info
    在vue组件中
<template>
  <div>
    <h1>Hello, world!</h1>
  </div>
</template>

<script>
export default {
  metaInfo: {
    title: 'Hello, world!',
    meta: [
      { name: 'author', content: 'John Doe' }
    ]
  }
}
</script>
  • 自定义404页面
    创建src/pages/404.vue组件

集合
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://api.example.com/posts')

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

配置GraphQL,在页面中查询数据

  • 在Pages和Templates使用
  • 在Components使用
<template>
  <Layout>
    <div>
      <h1>Posts2</h1>
      <ul>
        <li v-for="edge in $page.posts.edges" :key="edge.node.id">
          <g-link :to="edge.node.path">{{ edge.node.title }}</g-link>
        </li>
      </ul>
    </div>
  </Layout>
</template>

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

<script>
// 查询集合
query {
  allPost(sortBy: "title", order: DESC) {
    edges {
      node {
        title
      }
    }
  }
}

// 查询单个节点
query {
  post(id: "1") {
    title
  }
}

// 查询页面组件中的数据
query {
  posts: allWordPressPost {
    edges {
      node {
        id
        title
      }
    }
  }
}

// 页面组件中的多个查询
query {
  posts: allWordPressPost {
    edges {
      node {
        id
        title
      }
    }
  }
  books: allBooks {
    edges {
      node {
        id
        title
      }
    }
  }
}

查询任意组件中的数据

<template>
  <div v-html="$static.post.content" />
</template>

<static-query>
query {
  post(id: "1") {
    content
  }
}
</static-query>

功能组件支持

<static-query>
query {
  post(id: "1") {
    content
  }
}
</static-query>

<script>
export default {
  functional: true,
  render(createElement, context) {
    const { content } = context.data.$static.post
  
    return createElement('div', {
      domProps: {
        innerHTML: content
      },
    })
  }
}
</script>

设置模板
默认情况下会在src/templates/{Collection}.vue查找集合名称的模板

  • 在templates中新建模板Post.vue
<template>
  <Layout>
    <div>
      <h1>{{ $page.post.title }}</h1>
      <div>{{ $page.post.content }}</div>
    </div>
  </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
    }
  }
  // metaInfo: {
  //   title: ''
  // }
}
</script>

<style>

</style>
  • 在gridsome.config中指定模板路径
// module.exports = {
//   templates: {
//     Post: '/blog/:year/:month/:title',
//   }
// }
module.exports = {
  templates: {
    Post: [
      {
        path: '/posts/:id',
        component: './src/templates/Post.vue'
      }
    ]
  }
}
  • 修改Posts2的path
<template>
  <Layout>
    <div>
      <h1>Posts2</h1>
      <ul>
        <li v-for="edge in $page.posts.edges" :key="edge.node.id">
          <g-link :to="edge.node.path">{{ edge.node.title }}</g-link>
        </li>
      </ul>
    </div>
  </Layout>
</template>

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

使用strapi快速开发cms,为gridsome做数据支持

安装

$ npx create-strapi-starter my-project gatsby-blog
or
$ yarn create strapi-starter my-project gatsby-blog 

使用
点击《内容类型生成器》,可以根据需求生生成对应的集合类型数据或者单一类型数据,为之后的gridsome项目提供数据接口,具体的使用方法请查阅官方文档

远程服务器安装mysql
https://www.ucloud.cn/yun/47831.html

部署strapi
修改数据库配置
config/database.js

module.exports = ({ env }) => ({
  defaultConnection: 'default',
  connections: {
    default: {
      connector: 'bookshelf',
      settings: {
        client: 'mysql',
        host: env('DATABASE_HOST', 'localhost'), // 数据库主机,如果strapi和gridsome部署在同一服务器则不用修改
        port: env.int('DATABASE_PORT', 3306), // 端口号
        database: env('DATABASE_NAME', 'strapi'), // 数据库名称
        username: env('DATABASE_USERNAME', 'strapi'), // 数据库用户名
        password: env('DATABASE_PASSWORD', 'strapi'), // 数据库密码
      },
      options: {},
    },
  },
});

使用gridsome开发一个静态站点

执行上文介绍的脚本,安装gridsome并创建一个工程

$ gridsome create my-gridsome-demo

在gridsome中集成strapi

$ yarn add @gridsome/source-strapi
or
$ npm install @gridsome/source-strapi

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: 'Gridsome',
  plugins: [
    {
      use: '@gridsome/source-strapi',
      options: {
        apiURL: 'http://localhost:1337',
        queryLimit: 1000, // Defaults to 100
        contentTypes: ['post'], // 需要查询的集合内容
        singleTypes: ['journal'], // 需要查询的单个内容
        // Possibility to login with a Strapi user,
        // when content types are not publicly available (optional).
        loginData: { // 受保护的内容需要登录
          identifier: '',
          password: '',
        },
      },
    },
  ],
}

将strapi部署到服务器后,需要将apiURL配置成服务器地址,这里推荐新建.env.development和.env.production来设置服务器地址
.env.production

GRIDSOME_API_URL=服务器地址

gridsome.config.js

module.exports = {
  siteName: 'Gridsome',
  plugins: [
    {
      options: {
        apiURL: process.env.GRIDSOME_API_URL,
      },
    },
  ],
}

另外将GRIDSOME_API_URL混入Vue实例中,方便页面中使用
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)
}

编写页面
页面中的数据都是通过GraphQL查询得来,strapi默认是markdown格式的数据,需要利用markdown-it转换成html展示

$ yarn add markdown-it

Posts.vue

<template>
  <Layout>

    <div class="container">
      <div class="journal-hero">
        <h1 class="journal-header">
          {{ $page.journal.desc }}
        </h1>
      </div>
    </div>

    <g-link v-for="item in $page.posts.edges" :key="item.node.id" :to="`/journal-detail/${item.node.id}`" class="journal-post">
      <div class="container journal">
        <h2 class="journal-title">
          {{ item.node.title }}
        </h2>
        <p class="journal-excerpt">
          {{ item.node.intro }}
        </p>
      </div>
    </g-link>

    <Pager
      class="pager"
      :info="$page.posts.pageInfo"
      nav-class="navigation"
      link-class="page-link page-item"
      activeLink-class="active"
    />

  </Layout>
</template>

<page-query>
query ($page: Int) {
  posts: allStrapiPost (perPage: 10, page: $page) @paginate {
    pageInfo {
      totalPages
      currentPage
    }
    edges {
      node {
        id
        title
        intro
      }
    }
  }
  journal: strapiJournal (id: 1) {
    desc
  }
}
</page-query>

<script>
import { Pager } from 'gridsome'

export default {
  metaInfo: {
    title: 'journal'
  },
  components: {
    Pager,
  },
}
</script>

<style>

</style>

src/templates/Post.vue

<template>
  <Layout>
    <div class="journal">
      <div class="container journal-container">
        <div class="journal-header-detail">
          <h1 class="journal-title-detail">
            {{ $page.post.title }}
          </h1>
          <div class="journal-meta">
            <div class="journal-author">
              <span class="label">
                Author
              </span>
              <span class="author-name">
                {{ $page.post.admin_user.lastname }} {{ $page.post.admin_user.firstname }}
              </span>
            </div>
            <div class="journal-date">
              <span class="label">
                Date
              </span>
              <div>
                {{ $page.post.created_at }}
              </div>
            </div>
            <div class="journal-time">
              <span class="label">
                Time
              </span>
              <span >
                1 min read
              </span>
            </div>
          </div>
        </div>
        <div class="journal-content" v-html="mdToHtml($page.post.content)"></div>
      </div>
    </div>
  </Layout>
</template>

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

<script>
import MarkdownIt from 'markdown-it'
const md = new MarkdownIt()

export default {
  name: 'PostPage',
  metaInfo () {
    return {
      title: this.$page.post.title,
    }
  },
  methods: {
    mdToHtml (markdown) {
      return md.render(markdown)
    }
  }
}
</script>

<style scope>
.journal:hover {
	background: transparent;
}
</style>

将gridsome项目部署到Vercel
Vercel官方地址

  1. 进入个人中心 - overview - new Project - import Git Repository
  2. 根据提示输入git仓库的网页地址
  3. 如果修改过gridsome的scripts命令和dist输出目录等,可在Configure Project中配置
  4. 进入settings中的git,创建一个Deploy Hooks(例如deploy,master分支),然后复制创建好的地址
  5. 进入strapi-设置-Webhooks,添加一个新的hook,将刚刚复制的地址粘贴到对应的输入框,勾选上所有事件,之后只要strapi有更新,vercel就会自动部署
 类似资料: