Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@gridsome/source-filesystem for different content route format but same template/typeName #370

Open
eneim opened this issue Apr 17, 2019 · 9 comments
Assignees
Labels
question Unsure if I am doing it right

Comments

@eneim
Copy link

eneim commented Apr 17, 2019

Summary

I wonder if there is a way to allow @gridsome/source-filesystem to accepts content from many directory.

Basic example

Saying I organize my posts in blog directory and memo directory. All are markdown and I want to use the same template for them. I would like the route for blog posts are /blog/:slug and route for memo are /memo/:slug. How can it done with current plugin config?

@eneim eneim changed the title Same 'typeName' for different content directory @gridsome/source-filesystem for different content route format but same template/typeName Apr 17, 2019
@tomtev
Copy link
Member

tomtev commented Apr 17, 2019

Hi @eneim , you can add as many filesystem sources as you want. Take a look here for an example: https://github.com/gridsome/gridsome.org/blob/master/gridsome.config.js

@tomtev
Copy link
Member

tomtev commented Apr 17, 2019

I understand your question better now.

What you could do is importing a shared component/layout in every typeName.vue.
You need to have different queries per typeName.vue anyway and then pass the data to the shared component.

@eneim
Copy link
Author

eneim commented Apr 17, 2019

@tomtev thanks for the quick response. I think my issue is close to how the route for each item is generated. Consider the following config:

    {
      // Create posts from markdown files
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'Post',
        path: 'content/posts/*.md',
        route: '/:slug'
      }
    },
    {
      // Create posts from markdown files
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'Post',
        path: 'content/books/*.md',
        route: '/books/:slug'
      }
    }

I expected that all files in /content/books dir will be generated such that its path (the route result) becomes the format of /books/:slug. Right now, they are all /:slug. So I think the route config in second block is ignored :-/.

@eneim
Copy link
Author

eneim commented Apr 17, 2019

Forgot to mention, if I use different typeName (or the templates), it is fine as expected.. Only when I want to reuse the same template, it doesn't work so well.

@tomtev
Copy link
Member

tomtev commented Apr 17, 2019

Ah, you need to have different type names.

@eneim
Copy link
Author

eneim commented Apr 17, 2019

Ohhh, sounds pretty sad, got it. If possible I hope it will be supported in the future.

A quick last question: considering that I have many types like above, can I query all of them together to show on my index page? (instead of merging allBlogPost, allBook, etc?)

@robaxelsen robaxelsen added the question Unsure if I am doing it right label Apr 18, 2019
@rsclarke
Copy link

rsclarke commented Jun 3, 2019

@eneim Did you find a solution for your last quick question? I'm faced with a similar problem. Though I'm not sure how merging would work either and support paging.

@rsclarke
Copy link

rsclarke commented Jun 4, 2019

After thinking about this a bit more, a solution I'm currently using is to have an additional ContentType that is common between those to display on an index page. I was already doing something similar for hashtags but it didn't cross my mind to use this to query both types together. 🙄 🤷‍♂️

To take the above example, the gridsome.config.js may look like:

module.exports = {
  plugins: [
    {
      // Create posts from markdown files
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'Post',
        path: 'content/posts/*.md',
        route: '/:slug',
        refs: {
          author = 'Author'
        }
      }
    },
    {
      // Create posts from markdown files
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'Book',
        path: 'content/books/*.md',
        route: '/books/:slug',
        refs: {
          author = 'Author'
        }
      }
    }
  ]
}

Where we introduce an Author type. Note you could either use the Data store API in gridsome.server.js to have a fixed author (where every markdown document has author: foo).

module.exports = function(api) {
  api.loadSource(store => {
    const authors = store.addContentType('Author')
    const foo = authors.addNode({id: 'foo'})
  })
}

Or use the refs option create: true to automatically create the Author ContentType.

Ultimately the index page can then make a query using the Author field to return both Post and Book types.

<page-query>
query Entries($page: Int) {
  entries:author(id: "foo") {
    belongsTo(page: $page, perPage: 5) @paginate {
      totalCount
      pageInfo {
        totalPages
        currentPage
      }
      edges {
        node {
          __typename
          ... on Post {
            id
            title
            content
          }
          ... on Book {
            id
            title
            content
          }
        }
      }
    }
  }
}
</page-query>

@platform-kit
Copy link

platform-kit commented Jun 13, 2021

Hi @rsclarke, @tomtev, @eneim

I found that the simplest solution to this problem is to manually assign the path in the Templates part of the gridsome config using a function

IE, for this plugin setup...

var plugins = [
 {
    use: '@gridsome/source-filesystem',
    options: {
      path: '**/*.md',
      baseDir: 'temp/docs',
      typeName: 'Doc'
    }
  }
];

and this function to generate the path...

function slugify(node) {
  var text = node.title;
  console.log(node);  
  var text = text.toString().toLowerCase()
    .replace(/\s+/g, '-')           // Replace spaces with -
    .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
    .replace(/\-\-+/g, '-')         // Replace multiple - with single -
    .replace(/^-+/, '')             // Trim - from start of text
    .replace(/-+$/, '');            // Trim - from end of text
    return  node.fileInfo.directory + '/' + text;
}

and this Gridsome config that references the function in the templates object...

var gridsomeConfig = {
  siteName: siteName,
  icon: {
    favicon: favicon,
    touchicon: favicon
  },
  plugins: plugins,
  templates: {
    Doc:
      (node) => {
        return `/docs/${slugify(node)}/`
      }    
  }
}

and given some markdown files in various subdirectories, i.e. /api and /ui...

You will get content of type Doc at /docs/ui, /docs/api, etc. With the need for only one template (GraphQL type -- meaning same query for all docs).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Unsure if I am doing it right
Projects
None yet
Development

No branches or pull requests

5 participants