Using gridsome and strapi to build static sites

Posted by junk@alf2.com on Wed, 27 Oct 2021 05:33:36 +0200

Output source of article content: pull hook education front-end high salary training camp

What is a static site builder

  • Static website generator is a tool for generating static HTML files and related resources using a series of configurations, templates and data
  • This feature is also called pre rendering
  • The generated website does not need a server like PHP
  • You only need to run it on a Web Server or CDN that supports static resources

Benefits of static websites

  • Save money, do not need a professional server, as long as you can host the space of static files
  • Fast, no processing by the back-end server, only transmitting content
  • Security, no back-end program execution, naturally more secure

Common static website builder

  • Jekyll(Ruby)
  • Hexo (Node)
  • Hugo (Golang)
  • Gatsby (Node/React)
  • Gridsome (Node/Vue)
    In addition, Next.js and Nuxt.js can also survive static websites, but they are more regarded as SSR (server-side rendering) frameworks

This kind of static website generator is also called JAMStack: an acronym combination of JavaScript, API and Markup. In essence, it is a fat front end. It realizes more functions by calling various APIs. It can also be understood as a front-end and back-end mode, but the difference is particularly obvious. Even the front-end and back-end come from multiple different manufacturers

Usage scenarios for static applications

  • Not suitable for applications with a large number of routing pages: if your site has hundreds of routing pages, the pre rendering will be very slow. Of course, you only need to do it once per update, but it may take some time. Most people don't end up with thousands of static routing pages, just in case
  • Not suitable for applications with a large amount of dynamic content: if the rendering route contains content specific to users viewing their content or other dynamic sources, make sure you have a placeholder component that can be displayed until the dynamic content is loaded to the client, otherwise it may be a little weird

GridSome

install

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

initialization

$ gridsome create my-gridsome-site

gridsome configuration

View links to official documents.

route

  • gridsome will automatically generate routes according to the pages directory

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/

  • Create routes programmatically
    gridsome.server.js
module.exports = function (api) {
  api.createPages(({ createPage }) => {
    createPage({
      path: '/my-page',
      component: './src/templates/MyPage.vue'
    })
  })
}
  • Dynamic routing
    File based approach

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

Based on programming mode
gridsome.server.js

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

<script>
export default {
  metaInfo: {
    title: 'Hello, world!',
    meta: [
      { name: 'author', content: 'John Doe' }
    ]
  }
}
</script>
  • Custom 404 page
    Create src/pages/404.vue component

aggregate
gridsome.server.js

const axios = require('axios')

module.exports = function (api) {
  // Add data that needs to be pre rendered into the page
  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
      })
    }
  })
}

Configure GraphQL to query data in the page

  • Use in Pages and Templates
  • Use in 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 set
query {
  allPost(sortBy: "title", order: DESC) {
    edges {
      node {
        title
      }
    }
  }
}

// Query a single node
query {
  post(id: "1") {
    title
  }
}

// Query data in page components
query {
  posts: allWordPressPost {
    edges {
      node {
        id
        title
      }
    }
  }
}

// Multiple queries in page components
query {
  posts: allWordPressPost {
    edges {
      node {
        id
        title
      }
    }
  }
  books: allBooks {
    edges {
      node {
        id
        title
      }
    }
  }
}

Query data in any component

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

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

Functional component support

<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>

Set template
By default, the template for the collection name is found in src/templates/{Collection}.vue

  • Create a new template Post.vue in templates
<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>
  • Specify the template path in gridsome.config
// module.exports = {
//   templates: {
//     Post: '/blog/:year/:month/:title',
//   }
// }
module.exports = {
  templates: {
    Post: [
      {
        path: '/posts/:id',
        component: './src/templates/Post.vue'
      }
    ]
  }
}
  • Modify the path of Posts2
<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>

Use strapi to quickly develop cms and provide data support for gridsome

install

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

use
Click the content type generator to generate the corresponding set type data or single type data according to the requirements, and provide a data interface for subsequent gridsome projects. For specific usage methods, please refer to Access to official documents

Remote server installation mysql
https://www.ucloud.cn/yun/47831.html

Deploy strapi
Modify database configuration
config/database.js

module.exports = ({ env }) => ({
  defaultConnection: 'default',
  connections: {
    default: {
      connector: 'bookshelf',
      settings: {
        client: 'mysql',
        host: env('DATABASE_HOST', 'localhost'), // The database host does not need to be modified if strapi and gridsome are deployed on the same server
        port: env.int('DATABASE_PORT', 3306), // Port number
        database: env('DATABASE_NAME', 'strapi'), // Database name
        username: env('DATABASE_USERNAME', 'strapi'), // Database user name
        password: env('DATABASE_PASSWORD', 'strapi'), // Database password
      },
      options: {},
    },
  },
});

Developing a static site using gridsome

Execute the script described above, install gridsome and create a project

$ gridsome create my-gridsome-demo

Integrating strapi in gridsome

$ 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'], // Collection content to query
        singleTypes: ['journal'], // Single content to query
        // Possibility to login with a Strapi user,
        // when content types are not publicly available (optional).
        loginData: { // Protected content requires login
          identifier: '',
          password: '',
        },
      },
    },
  ],
}

After deploying strapi to the server, you need to configure the apiURL as the server address. It is recommended to create. env.development and. env.production to set the server address
.env.production

GRIDSOME_API_URL=server address

gridsome.config.js

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

In addition, gridsome_ API_ The URL is mixed into the Vue instance to facilitate use in the page
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)
}

Compose page
The data in the page is obtained through GraphQL query. strapi defaults to the data in markdown format, which needs to be converted into html display using markdown it

$ 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>

Deploy gridsome project to Vercel
Vercel official address

  1. Enter personal Center - overview - new Project - import Git Repository
  2. Enter the web address of the git repository as prompted
  3. If you have modified the scripts command and dist output directory of gridsome, you can configure them in Configure Project
  4. Enter git in settings, create a Deploy Hooks (for example, deploy, master branch), and then copy the created address
  5. Enter strapi settings Webhooks, add a new hook, paste the address just copied into the corresponding input box, check all events, and then vercel will deploy automatically as long as strapi is updated

Topics: Javascript