gatsbyjs / gatsby

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

Is it possible to prevent some page components under src/pages from turning into pages? #17831

Closed kimbaudi closed 5 years ago

kimbaudi commented 5 years ago

Summary

Based on GatsbyJS documentation on Creating and Modifying Pages, it says:

Gatsby core automatically turns React components in src/pages into pages

But is it possible to prevent some page components under src/pages from automatically being turned into pages?

For example, suppose I have index.js and about.js under src/pages. Is there any way to prevent about.js from being turned into a page depending on whether I am in "development" or "production" environment?

I was hoping there was a way I could edit gatsby-node.js to prevent building the About page during "production" so it is only available on "development" mode.

LekoArts commented 5 years ago

But is it possible to prevent some page components under src/pages from automatically being turned into pages?

No, that's not possible.

Is there any way to prevent about.js from being turned into a page depending on whether I am in "development" or "production" environment?

The solution you're trying isn't ideal IMO anyways, you should do it differently (than fiddling with src/pages).

You can place the file somewhere else and use the createPages API to generate that.

// gatsby-node.js
exports.createPages = ({ actions }) => {
  const { createPage } = actions

  if (process.env.NODE_ENV === `production`) {
    createPage({
      path: `/about`,
      component: require.resolve(`./src/templates/about.js`),
    })
  }
}

Hope that helps! Closing the issue as answered, please reply if you need further help. Thanks for using Gatsby!

universse commented 5 years ago

Hi @kimbaudi. There are two ways to go about doing it.

First, using gatsby's onCreatePage APIs, similar to the documentation page that you linked to.

const pathsToIgnore = ['/about/', ...]
exports.onCreatePage = ({ page, actions: { deletePage }) => {
  if (process.env.NODE_ENV === 'production') return

  if (pathsToIgnore.includes(page.path)) {
    deletePage(page)
  }
}

Or you can override the default gatsby-plugin-page-creator. More info here https://www.gatsbyjs.org/packages/gatsby-plugin-page-creator/?=#ignoring-specific-files

// gatsby-config.js
  plugins: [
    // ...
    ...(process.env.NODE_ENV === 'development' && {
      resolve: 'gatsby-plugin-page-creator',
      options: {
        path: `${__dirname}/src/pages`,
        ignore: ['about.(js|ts)?(x)'],
      },
    }),
    // ...
  ]

Hope it helps.

kimbaudi commented 5 years ago

@LekoArts - I'm not sure your solution will work in my case. It seems to require that I convert all my react components under src/pages into markdown files. I've seen other websites do what you suggested, but its not an ideal solution for me. Thanks for taking the time to provide a solution, though!

@universse - Your solutions are exactly what I was looking for. Thank you! I chose to override gatsby-plugin-page-creator and prevent pages from being created instead of using onCreatePage to delete the page after its already been created.

...(process.env.NODE_ENV === `production`
    ? [
        {
        resolve: `gatsby-plugin-page-creator`,
        options: {
            path: `${__dirname}/src/pages`,
            ignore: [
            'about.js',
            ],
        },
        },
    ]
    : []),

The other solution to use onCreatePage works fine too:

const pathsToIgnore = [
  `/about/`,
]
exports.onCreatePage = ({ page, actions }) => {
  if (process.env.NODE_ENV === 'development') return
  if (pathsToIgnore.includes(page.path)) {
    const { deletePage } = actions
    deletePage(page)
  }
}

There is also a plugin called gatsby-plugin-exclude that deletes pages using onCreatePage method in gatsby-node.js as well.

universse commented 5 years ago

Oops I made some syntax errors there. Glad it helped.

LekoArts commented 5 years ago

It seems to require that I convert all my react components under src/pages into markdown files.

No, that’s not the case. This function takes a component and creates a page.

kimbaudi commented 5 years ago

@LekoArts - I don't think your suggestion to use exports.createPages to conditionally create pages based on the environment (dev/prod) makes sense in my case. If I am to follow your suggestion, I would have to move the javascript files from src/pages somewhere else and convert it to markdown. Something like the following:

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  // Create blog posts pages.
  createPages(`./src/templates/blog-post.js`, '/blog/')

  // Create notes pages.
  createPages(`./src/templates/note.js`, '/notes/')

  if (process.env.NODE_ENV === `development`) {
    // Create books pages.
    createPages(`./src/templates/note.js`, '/books/')

    // Create code pages.
    createPages(`./src/templates/note.js`, '/code/')

    // Create learn pages.
    createPages(`./src/templates/note.js`, '/learn/')
  }
}

So at least in my case, it seems I would have to move js files out of src/pages and convert it to markdown files and then use export.createPages to conditionally create pages.

I'm sure I'm not understanding what you mean because I feel that I have to move the .js files under /src/pages somewhere else and change it from a page react component to a markdown file for it to work your way.

But either way, @universse solutions are more what I was hoping/looking for.

Hope I could at least explain why I felt your solution wasn't suitable in my case (because I would have to modify files under /src/pages) even though it would work.

If you can explain your suggestion so that I don't have to make any changes to files under /src/pages, then that is what I am looking for. But that doesn't seem to be the case.

LekoArts commented 5 years ago

If I am to follow your suggestion, I would have to move the javascript files from src/pages somewhere else and convert it to markdown.

No, that's still not the case. Where did you get that impression? I didn't write that 🤔

The createPage function takes a path (the URL) and a component a JS/JSX/TSX file to generate the page. You don't have to convert JS files to Markdown.

Yes, you have to move the single file you conditionally want to use (the about.js) out of src/pages but I personally think that @universse solution is bad for the future -- you might come back to this project in 1-2 years (or even another person) and expect the src/pages/about.js file to create a page every time (as you expect).

But if you explicitly put the the file that is used conditionally in a directory like src/conditional-pages/ it will make things so much clearer.

So at least in my case, it seems I would have to move js files out of src/pages and convert it to markdown files and then use export.createPages to conditionally create pages.

You only have to move this one file. You can keep all other files in src/pages.

universse commented 5 years ago

So I guess for the src/conditional-pages approach, can conditionally include another gatsby-plugin-page-creator that points to src/conditional-pages, depending on process.env.NODE_ENV. So no overriding of default plugin or usage of other APIs is necessary.

kimbaudi commented 5 years ago

@LekoArts - I'm really sorry for not understanding your suggestion earlier. Thank you for clearing up any confusion I had about converting js files into md files 😅. I followed your suggestion and moved about.js and any other js files that I want to conditionally build from src/pages to src/hidden-pages. Then in gatsby-node.js, I updated exports.createPages to create the about.js page based on the environment (dev/prod):

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  if (process.env.NODE_ENV === `development`) {
    createPage({
      path: `/about/`,
      component: path.resolve(`./src/hidden-pages/about.js`),
    })
  }
}

Thanks for this suggestion! It works out well.

kimbaudi commented 5 years ago

@universse - I think your solution to use gatsby-plugin-page-creator plugin with options.path set to src/hidden-pages depending on the environment (dev/prod) is the most ideal solution since I don't need to make any changes to exports.createPages or exports.onCreatePage. Also, it takes into account @LekoArts suggestion to move the javascript files out of src/pages elsewhere. So thanks to both of you!

So here is my solution to only building pages under src/private-pages on "development" environment:

gatsby-config.js:

    ...(process.env.NODE_ENV === `development`
    ? [
        {
          resolve: `gatsby-plugin-page-creator`,
          options: {
            path: `${__dirname}/src/private-pages`,
          },
        },
      ]
    : []),