ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ReactJS 静态网页生成器方案-Gatsby学习总结

2021-01-13 10:30:21  阅读:337  来源: 互联网

标签:node 插件 const Gatsby ReactJS 生成器 gatsby 数据


ReactJS 静态网页生成器方案-Gatsby学习总结

Gatsby.js 是基于 React 构建的、速度非常快的、现代化网站生成器。这里通过一个小型的项目来学习Gatsby的使用。

1. Gatsby 介绍

Gatsby 是一个静态站点生成器.
官网:https://www.gatsbyjs.org/

2. 静态应用的优势

  1. 访问速度快
  2. 更利于 SEO 搜索引擎的内容抓取
  3. 部署简单

3. Gatsby 总览

  1. 基于 React 和 GraphQL. 结合了 webpack, babel, react-router 等前端领域中最先进工具. 开发人员开发体验好
  2. 采用数据层和UI层分离而不失 SEO 的现代前端开发模式. 对SEO非常友好
  3. 数据预读取, 在浏览器空闲的时候预先读取链接对应的页面内容. 使静态页面拥有 SPA 应用的用户体验, 用户体验好
  4. 数据来源多样化: Headless CMS, markdown, API.
  5. 功能插件化, Gatsby 中提供了丰富且功能强大的各种类型的插件, 用什么装什么.

在这里插入图片描述

4. 创建 Gatsby 项目

  1. 全局安装脚手架工具
npm install gatsby-cli -g
  1. 创建项目
创建:gatsby new project-name https://github.com/gatsbyjs/gatsby-starter-hello-world
启动:gatsby develop 或 npm start 
访问:localhost:8000

5. 基于文件的路由系统

Gatsby 框架内置基于文件的路由系统, 页面组件被放置在 src/pages 文件夹中.

在这里插入图片描述

6. 以编程的方式创建页面

基于同一个模板创建多个HTML页面,有多少数据就创建多少页面
比如商品详情页面,有多少商品就生成多少商品详情展示页面.

gatsby-node.js

function createPages({actions}) {
    const { createPage} = actions
    // 获取模板绝对路径
    const template = require.resolve("./src/templates/person.js")
    // 获取模板所需数据
    const persons = [
        {
            name:'zhangsan',
            age:20,
            slug:'zhangsan'
        },
        {
            name:'lisi',
            age:30,
            slug:'lisi'
        },
    ]
    // 根据模板及数据创建页面 有多少数据就创建多少页面
    persons.forEach(person => {
        createPage({
            //模板绝对路径
            component:template,
            //访问地址
            path:`/person/${person.slug}`,
            //传递给模板的数据
            context:person
        })
    })
    
}

7. Link 组件

在 Gatsby 框架中页面跳转通过 Link 组件实现.

import React from "react"
import { Link, graphql} from "gatsby"
import SEO from "../components/SEO" // 设置title description 等利于seo的设置
import styles from "./index.module.less"

export default function Home({data}) {
  console.log(data)
  return <div>
  <SEO title = "seo title"/>
    <Link className={styles.red} to="/list">list</Link>
    <Link to="/product">product</Link>

    <div>title:{data.site.siteMetadata.title}</div>
    <div>author:{data.site.siteMetadata.author}</div>
  </div>
}

8. GraphQL 数据层

在 Gatsby 框架中提供了一个统一的存储数据的地方,叫做数据层.
在应用构建时,Gatsby 会从外部获取数据并将数据放入数据层,组件可以直接从数据层查询数据.
数据层使用 GraphQL 构建.
调试工具:localhost:8000/___graphql(启动项目时会同时启动)
在这里插入图片描述

8.1 页面组件数据查询

在组件文件中导出查询命令, 框架执行查询并将结果传递给组件的 prop 对象. 存储在 props 对象的 data 属性中.

import React from "react"
import {graphql, Link} from "gatsby"

export default function List({data}) {  
  return <div>
  {
    data.allMarkdownRemark.nodes.map( node => (
      <div key={node.id}>
        <p>{node.frontmatter.title}</p>
        <p>{node.frontmatter.date}</p>
        <Link to={`/article/${node.fields.slug}`}> to {node.fields.slug}`</Link> 
        <div dangerouslySetInnerHTML={{__html:node.html}}></div>
      </div>
    ))
  }</div>
}

export const query = graphql`
  query {
    allMarkdownRemark {
      nodes {
        html
        frontmatter {
          date
          title
        }
        internal {
          type
        }
        fileAbsolutePath
        id
        fields {
          slug
        }
      }
    }
  }
`

8.2 非页面组件数据查询

通过钩子函数 useStaticQuery 进行手动查询.

import React from "react"
import { graphql, useStaticQuery} from "gatsby"


export default function Header({data}) {
const query = useStaticQuery(graphql`
    query {
            site {
            siteMetadata {
                title
                author
            }
            }
        }
    `)
  return <div>
    <div>list-title:{query.site.siteMetadata.title}</div>
    <div>list-author:{query.site.siteMetadata.author}</div>
  </div>
}

9. Gatsby 插件 (网址)

Gatsby 框架内置插件系统, 插件是为应用添加功能的最好的方式.

在 Gatsby 中有三种类型的插件: 分别为数据源插件 ( source ), 数据转换插件 ( transformer ), 功能插件 ( plugin )

  1. 数据源插件:负责从应用外部获取数据,将数据统一放在 Gatsby 的数据层中
  2. 数据转换插件:负责转换特定类型的数据的格式,比如将 markdown 文件中的内容转换为对象形式
  3. 功能插件:为应用提供功能,比如通过插件让应用支持 Less 或者 TypeScript.

9.1 将 JSON 数据放入数据层

要将本地 JSON 文件中的数据放入数据层需要用到两个插件.

gatsby-source-filesystem: 用于将本地文件中的数据添加至数据层.
gatsby-transformer-json:将原始JSON字符串转换为JavaScript对象.

9.2 图像优化

  1. 图像文件和数据文件不在源代码中的同一位置
  2. 图像路径基于构建站点的绝对路径, 而不是相对于数据的路径, 难以分析出图片的真实位置
  3. 图像没有经过任何优化操作
  4. 生成多个具有不同宽度的图像版本, 为图像设置 srcset 和 sizes 属性, 因此无论您的设备是什么宽度都可以加载到合适大小的图片
  5. 使用"模糊处理"技术, 其中将一个20px宽的小图像显示为占位符, 直到实际图像下载完成为止.

npm install gatsby-plugin-sharp gatsby-transformer-sharp gatsby-image


gatsby-source-filesystem: 用于将本地文件信息添加至数据层.
gatsby-plugin-sharp: 提供本地图像的处理功能(调整图像尺寸, 压缩图像体积 等等).
gatsby-transformer-sharp: 将 gatsby-plugin-sharp 插件处理后的图像信息添加到数据层.
gatsby-image: React 组件, 优化图像显示, 基于 gatsby-transformer-sharp 插件转化后的数据.

9.3 将 markdown 数据放入数据层

  1. 通过 gatsby-source-filesystem 将markdown文件数据放入数据层
  2. 通过 gatsby-transformer-remark 将数据层中的原始 markdown 数据转换为对象形式
  3. 组件数据查询

gatsby-config.js

/**
 * Configure your Gatsby site with this file.
 *
 * See: https://www.gatsbyjs.com/docs/gatsby-config/
 */

module.exports = {
  /* Your site config here */
  plugins: [
    //将本地JSON文件数据添加至graphiQL数据层
    {
      resolve:"gatsby-source-filesystem",
      options:{
        name:"json",
        path:`${__dirname}/json/`
      }
    },
    //将本地MD文件数据添加至graphiQL数据层
    {
      resolve:"gatsby-source-filesystem",
      options:{
        name:"markdown",
        path:`${__dirname}/posts/`
      }
    },
    //将本地xml文件数据添加至graphiQL数据层
    {
      resolve:"gatsby-source-filesystem",
      options:{
        name:"xml",
        path:`${__dirname}/xml/`
      }
    },
    // 将原始JSON字符串转换为JS对象
    "gatsby-transformer-json",
    //本地插件 转换xml
    "gatsby-transformer-xml",
    "gatsby-plugin-sharp",
    "gatsby-transformer-sharp",
    // 将原始MD字符串转换为JS对象
    {
      resolve:"gatsby-transformer-remark",
      //处理md文件中的图片 md文件中的图片会被转换为html
      options:{plugins:["gatsby-remark-images"]}
    },
    //获取外部strapi数据
    // {
    //   resolve:"gatsby-source-strapi",
    //   options:{
    //     apiURL:"http://localhost:1337",
    //     contentTypes:["POST"]
    //   }
    // },
    // 本地插件 plugins文件夹内 实现gatsby-source-strapi类似效果
    {
      resolve:"gatsby-source-mystrapi",
      //处理md文件中的图片 md文件中的图片会被转换为html
      options:{
        apiURL:"http://localhost:1337",
        contentTypes:["POST", "Product"]
      }
    },
    //SEO 优化管理员数据 处理head中的meta title标签
    "gatsby-plugin-react-helmet",
    //支持less
    "gatsby-plugin-less",
  ],
  siteMetadata:{
    title:'hello Gatsby',
    author:'john'
  }
}


9.4 根据markdown构建页面生成文章详情

  1. 重新构建查询数据, 添加 slug 作为请求标识, slug 值为文件名称
gatsby.md    ->  /posts/gatsby
react.md     ->  /posts/react

gatsby-node.js

//为了给每篇文章加上唯一标识(此处使用文件名作为唯一标示)
function onCreateNode ({ node, actions}) {
    const { createNodeField} = actions;
    if (node.internal.type === "MarkdownRemark") {
        const slug = path.basename(node.fileAbsolutePath, '.md')
        createNodeField({
            node,
            name:"slug",
            value:slug
        })
        
    }
}
  1. 根据 slug 标识构建页面
async function createPages({actions, graphql}) {
    const { createPage} = actions
    // 获取模板绝对路径
    const template = require.resolve("./src/templates/article.js")
    // 获取模板所需数据
    let {data} = await graphql(`
      query {
        allMarkdownRemark {
          nodes {
            fields {
              slug
            }
          }
        }
      }
    `)
    // 根据模板及数据创建页面
    data.allMarkdownRemark.nodes.forEach(node => {
        createPage({
            //模板绝对路径
            component:template,
            //访问地址
            path:`/article/${node.fields.slug}`,
            //传递给模板的数据
            context:{
                slug:node.fields.slug
            }
        })
    })
    
}
  1. 组件数据查询
export const query = graphql`
    query ($slug:String) {
        markdownRemark(fields: {slug: {eq: $slug}}) {
            html
            frontmatter {
                date
                title
            }
            id
        }
    }
`
  1. 处理 markdown 文件中图片

gatsby-remark-images: 处理 markdown 中的图片, 以便可以在生产环境中使用.

// 将原始MD字符串转换为JS对象
{
    resolve:"gatsby-transformer-remark",
    //处理md文件中的图片 md文件中的图片会被转换为html
    options:{plugins:["gatsby-remark-images"]}
},

10. 从 Strapi 中获取数据

1.创建Strapi项目

创建项目: npx create-strapi-app <项目名称>
https://github.com/strapi/strapi

  1. 使用插件导入
    https://www.gatsbyjs.org/packages/gatsby-source-strapi/?=strapi
    // 获取外部strapi数据
    {
      resolve:"gatsby-source-strapi",
      options:{
        apiURL:"http://localhost:1337", //strapi网址
        contentTypes:["POST"]
      }
    },

11. 插件开发

11.1 Gatsby Source 插件开发

数据源插件负责从 Gatsby 应用外部获取数据,创建数据查询节点供开发者使用

  1. gatsby clean 清除上一次的构建内容
  2. 在项目根目录里下创建 plugins 文件夹,在此文件夹中继续创建具体的插件文件夹,比如 gatsby-source-mystrapi 文件夹
  3. 在插件文件夹中创建 gatsby-node.js 文件
  4. 插件实际上就是 npm 包
  5. 导出 sourceNodes 方法用于获取外部数据,创建数据查询节点
  6. 在 gatsby-config.js 文件中配置插件,并传递插件所需的配置参数
  7. 重新运行应用

plugins/gatsby-source-mystrapi/gatsby-node.js

const axios = require("axios")
const pluralize = require("pluralize")
const createNodeHelper = require("gatsby-node-helpers").default

async function sourceNodes({actions}, configOptions) {
  const {apiURL, contentTypes} = configOptions
  const { createNode } = actions
  // POST - posts Product - products
  const types = contentTypes.map(type => type.toLowerCase()).map(type => pluralize(type))
  //types [ 'posts', 'products' ]
  let final = await getContents(types, apiURL)

  // console.log(final)
  for (let [key, value] of Object.entries(final)) {
    //构建数据节点对象 allPostsContent allProductsContent
    const {createNodeFactory} = createNodeHelper({
      typePrefix:key,
    })
    const createNodeObject = createNodeFactory("content")
    //根据数据节点对象创建节点
    value.forEach(item => {
      createNode(createNodeObject(item))
    })
  }

}

//从外部数据源获取数据
async function getContents (types, apiUrl) {
  const size = types.length;
  let index = 0
  // {posts:[], [products:[]]}
  const final = {}
  // 初始调用
  await loadContents()

  async function loadContents() {
    if (index === size) return
    let {data} = await axios.get(`${apiUrl}/${types[index]}`)
    final[types[index++]] = data
    await loadContents()
  }

  return final
}


module.exports = {
  sourceNodes
}

gatsby-config.js

    {// 自定义插件
      resolve:"gatsby-source-mystrapi",
      options:{
        apiURL:"http://localhost:1337",
        contentTypes:["POST", "Product"]
      }
    },

11.2 Gatsby Transformer 插件开发

  1. 在 plugins 文件夹中创建 gatsby-transformer-xml 文件件
  2. 在插件文件夹中创建 gatsby-node.js 文件
  3. 在文件中导出 onCreateNode 方法用于构建 Gatsby 查询节点
  4. 根据节点类型筛选 xml 节点 node.internal.mediaType -> application/xml
  5. 通过 loadNodeContent 方法读取节点中的数据
  6. 通过 xml2js 将xml数据转换为对象
  7. 将对象转换为 Gatsby 查询节点

plugins/gatsby-transformer-xml/gatsby-node.js

const {parseString} = require("xml2js")
const {promisify} = require("util")
const parse = promisify(parseString)
const createNodeHelper = require("gatsby-node-helpers").default

async function onCreateNode ({ node, loadNodeContent, actions}) {
    const { createNode} = actions;
    if (node.internal.mediaType === "application/xml") {
        let content = await loadNodeContent(node)
        let obj =await parse(content, {explicitArray:false, explicitRoot:false})
        //构建数据节点对象 allPostsContent allProductsContent
        const {createNodeFactory} = createNodeHelper({
            typePrefix:"XML",
          })
          const createNodeObject = createNodeFactory("parsedContent")
          //根据数据节点对象创建节点
          createNode(createNodeObject(obj))
    }
}
module.exports = {
    onCreateNode
}

12. 相关插件使用

12.1 SEO 优化

gatsby-plugin-react-helmet

react-helmet 是一个组件, 用于控制页面元数据. 这对于 SEO 非常重要.
此插件用于将页面元数据添加到 Gatsby 构建的静态HTML页面中.

npm install gatsby-plugin-react-helmet react-helmet
import React from 'react'
import { graphql, useStaticQuery} from "gatsby"
import { Helmet } from "react-helmet"
export const SEO = ({title, description, meta, lang}) => {
    const {site} = useStaticQuery(graphql`
        query {
            site {
                siteMetadata {
                    title
                    author
                }
            }
        }
    `)
    const metaDes = description || site.siteMetadata.description
    return <Helmet 
        htmlAttributes={{lang}} 
        title={title} 
        titleTemplate={`%s | ${site.siteMetadata.title}`}
        meta={[{
            name:'description',
            content:metaDes
        }].concat(meta)}
    />
}
SEO.defaultProps = {
    description:"test des",
    meta:[],
    lang:'en'
}
export default SEO

12.2 在 gatsby 应用中使用 less

下载插件:npm install --save gatsby-plugin-less
配置插件:plugins: [`gatsby-plugin-less`]
创建样式:index.module.less
引入样式:import styles from './index.module.less'

13. 配置redux

  1. 创建仓库 store/createStor
import { createStore, applyMiddleware } from "redux"
import thunk from "redux-thunk"
import reducer from "./reducer"

export default () => {
    const store = createStore(reducer, applyMiddleware(thunk))
    return store
}
  1. 创建 action reducer

  2. 配置gatsby-browser.js
    gatsby-browser.js

require("./src/styles/global.css");
const React = require("react")
const { Provider } = require("react-redux")
const createStore = require("./store/createStore").default

exports.wrapRootElement = ({ element }) => {
    return <Provider store={createStore()}>{element}</Provider>
}

  1. 配置gatsby-ssr.js
    gatsby-ssr.js
const React = require("react")
const { Provider } = require("react-redux")
const createStore = require("./store/createStore").default

exports.wrapRootElement = ({ element }) => {
    return <Provider store={createStore()}>{element}</Provider>
}

14. 完整代码

代码地址:https://gitee.com/liannian9/fed-e-task-04-04/tree/master/homework-gatsby

标签:node,插件,const,Gatsby,ReactJS,生成器,gatsby,数据
来源: https://blog.csdn.net/weixin_44213825/article/details/112554171

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有