gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.3k stars 10.31k forks source link

Gatsby 2beta - Including default SEO tags to layout.js #6423

Closed jan-dh closed 6 years ago

jan-dh commented 6 years ago

Summary

I'm building a small blog website using Gatsby 2 and I'm trying to set some default meta-tags in the header such as author, my favicon tags etc. However, seems that putting them in the layout.js file doesn't work.

If I move the meta-tags to the seperate files like my index.js (homepage) or my blog-posts.js template they do appear in the DOM. Just wondering what the right approach here would be and if this is actually working as expected? Can't find too many info in the docs the correct way to set these kind of things beside using Helmet.

Environment

npm: 6.1.0 - /usr/local/bin/npm Browsers: Chrome: 67.0.3396.99 Firefox: 61.0.1 Safari: 11.1.1 npmPackages: gatsby: next => 2.0.0-beta.20 gatsby-plugin-feed: next => 2.0.0-beta.3 gatsby-plugin-google-analytics: next => 2.0.0-beta.2 gatsby-plugin-google-fonts: 0.0.4 => 0.0.4 gatsby-plugin-offline: next => 2.0.0-beta.3 gatsby-plugin-react-helmet: next => 3.0.0-beta.3 gatsby-plugin-sharp: next => 2.0.0-beta.2 gatsby-plugin-twitter: ^1.0.20 => 1.0.20 gatsby-plugin-typography: next => 2.2.0-beta.2 gatsby-remark-copy-linked-files: next => 2.0.0-beta.2 gatsby-remark-external-links: 0.0.4 => 0.0.4 gatsby-remark-images: next => 2.0.1-beta.3 gatsby-remark-prismjs: next => 3.0.0-beta.3 gatsby-remark-responsive-iframe: next => 2.0.0-beta.2 gatsby-remark-smartypants: next => 2.0.0-beta.2 gatsby-source-filesystem: next => 2.0.1-beta.3 gatsby-transformer-remark: next => 2.1.1-beta.2 gatsby-transformer-sharp: next => 2.1.1-beta.3 npmGlobalPackages: gatsby-cli: 1.1.58

File contents

This is my layouts.js file (it sites in my components folder).

import React from 'react'
import Helmet from 'react-helmet'

import css from './index.css'

import Header from "./Header/"
import Main from "./Main/"
import Footer from "./Footer/"

export default ({ children, location}) => {
  return(
      <Helmet>
        {/* Favicon stuff from realfavicongenerator.net */}
        <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
        <link rel="manifest" href="/site.webmanifest" />
        <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#08192f" />
        <meta name="msapplication-TileColor" content="#fec001" />
        <meta name="theme-color" content="#fec001" />
      </Helmet>,
      <div className="container bg-grey-lightest">
        <Header key="app-header" location={location.pathname} />
        <Main key="app-main">
          {children}
        </Main>
        <Footer key="app-footer" />
      </div>
  )
}
merelinguist commented 6 years ago

Layouts have been removed in v2: https://next.gatsbyjs.org/docs/migrating-from-v1-to-v2/#update-layout-component

jan-dh commented 6 years ago

Not exactly. The migration docs state: Move layouts/index.js to src/components/layout.js (optional, but recommended). So my file structure looks something like this:

components/
|
|- Bio/
|  |- index.js
|
|  - Footer/
|   |- index.js
|
| - layouts.js
KyleAMathews commented 6 years ago

You need to follow step 3 as well and import the layout component into your pages.

jan-dh commented 6 years ago

This is what I'm doing as well. The code in my index.js (homepage):

import React from 'react'
import { Link } from 'gatsby'
import { graphql } from 'gatsby';
import get from 'lodash/get'
import Helmet from 'react-helmet'

import Bio from '../components/Bio/'
import Layout from '../components/layout'
import Header from '../components/Header';

class BlogIndex extends React.Component {
  render() {
    const siteTitle = this.props.data.site.siteMetadata.title
    const siteDescription = this.props.data.site.siteMetadata.description
    const siteUrl = this.props.data.site.siteMetadata.siteUrl
    const siteName = this.props.data.site.siteMetadata.siteName
    const ogImage = this.props.data.site.siteMetadata.ogImage
    const posts = this.props.data.allMarkdownRemark.edges

    return (
      <Layout location={this.props.location}>
        <Helmet
          title= {siteTitle}
          meta = {[
              { name: "description","content": siteDescription},
              { name: 'twitter:title', content: siteTitle },
              { name: 'twitter:image', content: ogImage },
              { property: "og:title", content: siteTitle},
              { property: "og:description","content": siteDescription},
              { property: "og:url", content: siteUrl},
              { property: "og:image", content: ogImage },
            ]}
        >
          <html lang="en" />
        </Helmet>
        {posts.map(({ node }) => {
          const title = get(node, 'frontmatter.title') || node.fields.slug
          return (
            <div key={node.fields.slug}>
              <Link to={node.fields.slug}  className="mx-auto max-w-sm p-4 mb-8 bg-white rounded-lg shadow block">
                <h3 className="my-1 text-xl inline-block text-black">{title}</h3>
                <span className="text-sm text-grey"> - {node.frontmatter.date}</span>
                <p className="text-grey-darker my-4 text-base" dangerouslySetInnerHTML={{ __html: node.frontmatter.intro }} />
                {node.frontmatter.categories.map(category => (
                  <span className="inline-block text-xs py-1 px-2 mt-0 mr-2 rounded-xl mb-1 ml-0 text-grey-darker bg-grey-lighter leading-none" key={category}>#{category[0].toUpperCase()}{category.slice(1)}</span>
                ))}
              </Link>
            </div>
          )
        })}
        <Bio />
      </Layout>
    )
  }
}

export default BlogIndex

export const pageQuery = graphql`
  query IndexQuery {
    site {
      siteMetadata {
        title,
        author,
        description,
        siteUrl,
        ogImage,
        siteName
      }
    }
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            date(formatString: "DD.MM.YYYY")
            title
            intro
            categories
          }
        }
      }
    }
  }
`

It's my understanding that the Helmet stuff I put in the layout.jswould be used for all pages and I can add extra meta-tags based on the actual page? Still, the favicon data from my layout.jsfile doesn't get rendered. Are you supposed to put a let's say favicon component on all your seperate pages?

jan-dh commented 6 years ago

@KyleAMathews this was closed before answered under the false assumption that I didn't do step 3...?

KyleAMathews commented 6 years ago

Sorry about that.

pieh commented 6 years ago

You syntax is wrong when you return components in layouts.js - you do something like this:

const test = () => { return "foo", "bar" }
test() // this will have just "bar"

You need to wrap your return in React.Fragment and remove comma there between Helmet and div