文章内容输出来源:拉勾教育前端高薪训练营
这类静态网站生成器还有个名字叫JAMStack:JavaScript、API和Markup的首字母组合,其本质上是一种胖前端,通过调用各种API来实现更多的功能,也可以理解为是一种前后端模式,只不过分得特别明显,甚至前后端来自多个不同的厂商
$ yarn global add @gridsome/cli
or
$ npm install --global @gridsome/cli
$ gridsome create my-gridsome-site
路由
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/
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'
})
})
}
<template>
<div>
<h1>Hello, world!</h1>
</div>
</template>
<script>
export default {
metaInfo: {
title: 'Hello, world!',
meta: [
{ name: 'author', content: 'John Doe' }
]
}
}
</script>
集合
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,在页面中查询数据
<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查找集合名称的模板
<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>
// module.exports = {
// templates: {
// Post: '/blog/:year/:month/:title',
// }
// }
module.exports = {
templates: {
Post: [
{
path: '/posts/:id',
component: './src/templates/Post.vue'
}
]
}
}
<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>
安装
$ 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 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官方地址