一、Gridsome 介绍
- Gridsome 是一个免费、开源、基于 Vue 技术栈的网站生成器
- 官方网站
- Github 什么是静态网站生成器
- 静态网站生成器是使用一系列配置、模版以及数据、生成静态HTMl文件及相关工具
- 同时这个功能也叫预渲染
- 生成的网站不需要类似 PHP 这样的服务器
- 只需要放到静态资源的 Web Server 或者 CDN 上运行 静态网站的好处
- 省钱 不需要专业的服务器,只要能托管静态文件的空间即可
- 快速 不经过后端服务器的出来,只传输内容
- 安全 没有后端程序的执行,自然会更安全 常见的静态网站生成器
- Jekyll (Ruby)
- Hexo (Node)
- Hugo (Golang)
- Gatsby (Node/React)
- Gridsome (Node/Vue)
- 另外,Next.js, Nuxt.js 也能生成静态网站,但是他们更多认为是SSR(服务端渲染)框架 JAMStack
- 这类静态网站生成器还有个漂亮的名字叫JAMStack
- JAMStack的JAM是JavaScript、API和Markup的首字母组合 本质上是一种胖前端,通过调用各种API来实现更多的功能
- 其实也是一种前后端的模式,只不过离得比较开,甚至前后端来自多个不同的厂商 静态应用的使用场景
- 不适合有大量路由页面的应用
- 如果您的站点有成百上千条路由页面,则预渲染将非常缓慢。当然,您每次更新只需要做一次,但是可能要花一些时间。大多数人不会最终获得数千条静态路由页面,而只是以防万一
- 不适合有大量动态内容的应用
- 如果渲染路线中包含特定于用户查看其内容或其他动态源的内容,则应确保您具有可以显示的占位符组件,直到动态内容加载到客户端为止。否则可能有点怪异
二、Gridsome基础
创建Gridsome 项目
- node-gyp
npm install -g node-gyp
- 安装 Gridsome 脚手架
yarn global add @gridsome/cli
npm install --global @gridsome/cli
gridsome create gridsome-blog // 初始化项目
cd gridsome-blog
gridsome develop
安装依赖的时候很慢,无进度条,解决方法:
- 中断当前安装
- 进入已经生成的项目目录下,删除当前的 node_modules
- 执行 npm install ,此时就可以看到进度了
- 安装好依赖之后,执行npm run develop启动项目
启动后效果如下:
预渲染
打包生成dist目录
yarn build
安装web静态服务器
npm i -g serve
将build文件夹部署到该服务器
serve dist
效果如下:
打开控制台,看到返回的是预渲染好的html文件
目录结构
- gridsome.config.js gridsome 的配置文件
- gridsome.server.js 也是 girdsome 的配置文件,是配置服务端的,Gridsome 内部的服务配置。
- Default.vue 中有个特别之处, query 就是专门查询gridsome数据给组件使用
- components 放一些公共组件
- static 静态资源
- dist打包文件
<static-query>
query {
metadata {
siteName
}
}
</static-query>
项目配置
module.exports = {
siteName: 'Grisome', // 页面上的名称
pathPrefix: '/strapi', // 路径前缀, 部署是否有子目录
templates: {}, // 定义路由模版
configgureWebapck: {}, // type Object | Function webpack 配置
siteDescription: '学习', // meta 名称
plugins: [] // 配置插件
}
Pages
pages 就是我们项目当中的路由组件,最终会生成路由页面,在编译的时候会成为静态的HTML
两种创建方式
- 基于文件创建 直接在pages文件下新建文件 例如demo.vue
- 基于API创建
// gridsome.server.js 配置
api.createPages(({ createPage }) => {
// Use the Pages API here: https://gridsome.org/docs/pages-api/
createPage({
path: '/demo',
component: './src/templates/demo.vue'
})
})
动态路由 pages 下面创建的页面文件名称用方括号括起来,作为动态路由参数:src/pages/user/[id].vue
<template>
<h1>
User {{ $route.params.id }} Page
</h1>
</template>
<script>
export default {
name: 'UserPage'
}
</script>
API 创建
api.createPages(({ createPage }) => {
createPage({
path: '/user/:id(\\d+)',
component: './src/templates/User.vue'
})
})
添加集合
创建一个demo 组件
<template>
<Layout>
<h1>demo</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: 'demo',
data () {
return {
posts: []
}
},
async created () {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
this.posts = data
}
}
</script>
通过这种方式渲染不是静态化渲染的,它是在客户端动态加载的,我们需要用预渲染方式将数据渲染到页面中预渲染数据
// gridsome.server.js
const axios = require('axios')
module.exports = function (api) {
api.loadSource(async ({ addCollection }) => {
const collection = 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
})
}
})
}
在GraphQl中查询数据
访问 http://localhost:8080/___explore
query {
post (id : 2) {
id
title
content
}
}
在页面中查询GraphQl
- 组件中使用
<static-query></static-query>
- 页面路由中使用
<page-query></page-query>
<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: 'Posts',
}
</script>
<page-query>
query {
posts: allPost {
edges {
node {
id
title
}
}
}
}
</page-query>
使用模版渲染节点页面
Templates for collections:配置路由模版
// gridsome.config.js
module.exports = {
siteName: '拉钩教育',
siteDescription: '大前端',
plugins: [],
templates: {
Post: [
{
path: '/posts/:id',
component: './src/templates/Post.vue'
}
]
}
}
创建一个Post.vue 预渲染页面,从GraphQL获取的数据
<template>
<Layout>
<h1>{{$page.post.title}}</h1>
<p>{{$page.post.content}}</p>
</Layout>
</template>
<page-query>
// ID! 不能为空,动态路由参数会自动传入进来
query($id: ID!) {
post(id: $id) {
id
title
content
}
}
</page-query>
<script>
export default {
name: 'PostPage',
metaInfo () {
return {
title: this.$page.post.title
}
}
}
</script>