Gatsby: Getting an external link warning when using Link with createPages

Created on 23 Jan 2019  Â·  26Comments  Â·  Source: gatsbyjs/gatsby

Description

I'm using <Link> for pages generated from WordPress posts by createPages, and the links works just fine, but I am getting the following warning in the console...

External link hello-world was detected in a Link component. Use the Link component only for internal links. See: https://gatsby.app/internal-links

Steps to reproduce

  1. Pull in Wordpress API data using the gatsby-source-wordpress plugin.
  2. Follow the documentation to generate pages for each post.
  3. Use Gatsby's Link component to link to any of those posts.
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Link, graphql } from 'gatsby'
import { Layout } from '../components/Layout'

class IndexPage extends Component {
  render () {
    const { data } = this.props

    return (
      <Layout>
        <ul>
          {
            data.allWordpressPost.edges.map(({ node }) => console.log('node', node) || (
              <li key={node.id}>
                <Link to={node.slug}>{node.title}</Link>
              </li>
            ))
          }
        </ul>
      </Layout>
    )
  }
}

export default IndexPage

IndexPage.propTypes = {
  data: PropTypes.shape({
    allWordpressPost: PropTypes.shape({
      edges: PropTypes.array
    })
  })
}

export const pageQuery = graphql`
  query {
    allWordpressPost(sort: { fields: [date] }) {
      edges {
        node {
          id
          title
          slug
        }
      }
    }
  }
`

This is the output of that console.log:

{
    excerpt: "<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>↵"
    id: "2347739f-f4fa-5d13-8eac-4a0059e4ff82"
    slug: "hello-world"
    title: "Hello world!"
}

Expected result

There should be no console warning as they are not external links.

Actual result

Received console warning as shown above.

Environment

System:
OS: macOS Sierra 10.12.6
CPU: x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 9.11.1 - ~/.nvm/versions/node/v9.11.1/bin/node
Yarn: 1.12.3 - /usr/local/bin/yarn
npm: 5.6.0 - ~/.nvm/versions/node/v9.11.1/bin/npm
Browsers:
Chrome: 71.0.3578.98
Firefox: 64.0.2
Safari: 12.0.2
npmPackages:
gatsby: ^2.0.76 => 2.0.93
gatsby-awesome-pagination: ^0.3.3 => 0.3.3
gatsby-image: ^2.0.20 => 2.0.27
gatsby-plugin-manifest: ^2.0.9 => 2.0.13
gatsby-plugin-offline: ^2.0.16 => 2.0.21
gatsby-plugin-react-helmet: ^3.0.2 => 3.0.5
gatsby-plugin-remove-trailing-slashes: ^2.0.6 => 2.0.6
gatsby-plugin-sass: ^2.0.7 => 2.0.7
gatsby-plugin-sharp: ^2.0.14 => 2.0.18
gatsby-source-filesystem: ^2.0.8 => 2.0.17
gatsby-source-wordpress: ^3.0.25 => 3.0.27
gatsby-transformer-sharp: ^2.1.8 => 2.1.10
npmGlobalPackages:
gatsby-cli: 2.4.3

Most helpful comment

Solved.

<Link to={`/${node.slug}`}>{node.title}</Link>

I did not include the / in the link.

All 26 comments

Solved.

<Link to={`/${node.slug}`}>{node.title}</Link>

I did not include the / in the link.

I get these warnings even with a slash in the path.

+1

Edit:
Tell a lie... <Link to={`/${node.slug}`}> worked for me.

Also getting a console full of these errors even when prefixed with a forward slash - the paths are otherwise just hyphen-separated-strings, the corresponding pages exist, and clicking the link navigates to them.

<Link to={`/${slug}`}>

Adding / to the beginning of links removed the related warnings for me.

I found that handling it in the gatsby-node.js file was easier:

const relativePath = createFilePath({
  node,
  getNode,
  basePath: "src/content/blog/",
})
createNodeField({
  node,
  name: "slug",
  value: `/blog${relativePath}`,
})

I still get warnings when I link internally. The links works fine. Anyone knows why? I have a / in the beginning.

Why has this issue been closed? I'm getting this error too, and so are others above.

Yes, this is pretty annoying. It seems to happen if you don't put the full string in the Link component itself and substitute via templating or any kind of substitution. I'm grabbing the link from an array of objects in the same file as I need to map over it to be able to use React Spring's "useTrail" animation.

It's pretty annoying that my console is flooded with these warnings and I have to look really closely and sift through the console to be able to find a console log. I have tried all of the methods above and none of them work unless I put the full path in the "to" attribute instead of substitution.

+1

I have same issue, I have / in front of the link but still getting this error.

Anyone have any clue?

Same issue here, despite prefixing with /

Has anyone found a solution to this warning?

I tinkered with this a bit today. Gatsby version 2.20.12.

(Mentioned by cushmatt on February 12th…)

The trick is that the full string must be built, in totality, before being passed to <Link>.


Meaning, this works… 👍

const url = '/' + 'page-slug-here';

return (
  <Link to={url}>
    Text
  </Link>
);

But this still shows a warning… 👎

const url = 'page-slug-here';

return (
  <Link to={`/${url}`}>
    Text
  </Link>
);

I tinkered with this a bit today. Gatsby version 2.20.12.

(Mentioned by cushmatt on February 12th…)

The trick is that the full string must be built, in totality, before being passed to <Link>.

Meaning, this works…

const url = '/page-slug-here';

return (
  <Link to={url}>
    Text
  </Link>
);

But this still shows a warning…

const url = 'page-slug-here';

return (
  <Link to={`/${url}`}>
    Text
  </Link>
);

Kudos for finding a solution. I'm running into this with {url} values in a mapping function, so I can't define them as a constant ahead of time. Still looking for a solution :(

cc: @alexfornuto

You can still string build it in a function.

It just can't be done via backtick template literal interpolation.

For instance, this should work…

// Loop through.
const newList = oldList.map(({
  id = '',
  myVariable = ''
}, index) => {
  // Build dynamic URL.
  let url = [
    '',
    'path',
    'to',
    myVariable
  ];

  // String cleanup.
  url = url.join('/).replace(/\/+/g, '/');

  /*
    NOTE:

    By the time we reach here, `url` should
    be equal to something like this…

    "/path/to/my-variable"

    Then, it's just a matter of passing what
    looks like a static string to `<Link>`.
  */

  // Add to array.
  return (
    <Link to={url} key={id || index}>
      Text
    </Link>
  );
});

I see what you're saying. I think the critical difference is that my maps and filters happen inside of my page's return, like this:

                    <tbody>
                      {categorizedPages
                        .filter(page => {
                          return (
                            page.node.frontmatter.title
                              .toLowerCase()
                              .indexOf(searchTitle.toLowerCase()) >= 0
                          )
                        })
                        .filter((page) => {
                          return page.node.frontmatter.categories.filter(
                            (category) => category.indexOf(searchCategory) > -1
                          ).length;
                        })
                        .map((page, i) => {
                          return (
                            <tr key={i}>
                              <td>
                                <a
                                  href={`/${page.node.fields.slug}`}
                                >
                                  {page.node.frontmatter.title}
                                </a>
                              </td>
...

I'm sure there's some way I could abstract all that logic out of where it is and above where I could define constants, but I honestly _don't want_ to do that just to work around this bug in the Link component.

My issue got resolved by having a / (forward slash) at the end of the route as well as in the beginning...
image

@Alek-Sei I just gave that a try:

                                <Link
                                  to={`/${page.node.fields.slug}/`}
                                >
                                  {page.node.frontmatter.title}
                                </Link>

with no success. The difference here of the use of a value other than a literal string makes our two examples dissimilar enough to make different outcomes unsurprising.

@Alek-Sei I just gave that a try:

                                <Link
                                  to={`/${page.node.fields.slug}/`}
                                >
                                  {page.node.frontmatter.title}
                                </Link>

with no success. The difference here of the use of a value other than a literal string makes our two examples dissimilar enough to make different outcomes unsurprising.

Yeah, that's quite an issue. I can replicate your error with ease unfortunately as it turns out :) Didn't try it before, but gonna keep looking into it, maybe something relatively simple and efficient comes up.

Thanks @Alek-Sei

@LekoArts Maybe this issue should be re-opened or a new one created?

I'm still getting this error, I'm just trying to create a pagination for my blog using this tutorial https://www.gatsbyjs.org/docs/adding-pagination/

link 2 was detected in a Link component. Use the Link component only for internal links.

The pagination link is: http://localhost:8000/2

I am getting the same error but also my dynamic pages only work when prepended with 2 forward slashes, they get detected as external links with the slashes

@alexfornuto

Any luck on this issue? I am mapping my pathing into a component as well and the multitude of warnings is driving me nuts.

       <div className="case container--base">
              <div className="case--header char-100">
                <h2 className="case--title">{caseData.frontmatter.title}</h2>
              </div>
              <h5 className="char-100 case--subheader">
                {caseData.frontmatter.subheader}
              </h5>
              <div className="case--tags">
                {caseData.frontmatter.tags.map((t, i) => (
                  <div key={i} className="case--tag kilo">
                    {t},
                  </div>
                ))}
              </div>
              <AniLink
                fade
                to={caseData.frontmatter.path}
                className="icon--arrow"
              >
                Case{""} <IoIosArrowRoundForward />
              </AniLink>
              {caseData.frontmatter.featured_img !== null ? (
                <div className="case--img">
                  <Img
                    fluid={
                      caseData.frontmatter.featured_img.childImageSharp.fluid
                    }
                    objectFit="contain"
                  />
                </div>
              ) : undefined}
            </div>

In the meantime is there a way to suppress this warning in the console. I know it's not best practice to suppress warning but until it's resolved.

/shrug

Did you know that they make you a "maintainer" even if you only make small improvements to the documentation? In other words, I'm in the same boat as you. I'm hoping @LekoArts will look at this issue and provide the insight you seek.

Is it possible that client side rendered pages are not considered as "internal"?

All my URLs like /research/3f26ba2b-f189-41f8-83bb-f19f4cfe52b8/User gives me the waring

External link research/3f26ba2b-f189-41f8-83bb-f19f4cfe52b8/User was detected in a Link component.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  Â·  3Comments

kalinchernev picture kalinchernev  Â·  3Comments

timbrandin picture timbrandin  Â·  3Comments

brandonmp picture brandonmp  Â·  3Comments

totsteps picture totsteps  Â·  3Comments