Naturally Pacifist Marsupials
Miss any of our Open RFC calls?Watch the recordings here! »

gridsome-source-storyblok

1.0.2 • Public • Published

Gridsome Source Storyblok

The official Storyblok integration with Gridsome.

To see it in action take a look at the Storyblok Gridsome Boilerplate.

Version Downloads Stars Status

Install

yarn add gridsome-source-storyblok # or npm install gridsome-source-storyblok 

Usage

  1. In gridsome.config.js, declare the use of the plugin and define the options:
// in gridsome.config.js
{
  siteName: 'Gridsome',
  plugins: [
    {
      use: 'gridsome-source-storyblok',
      options: {
        client: {
          accessToken: '<YOUR_ACCESS_TOKEN>'
        },
        types: {
          story: {
            typeName: 'StoryblokEntry'
          }
        }
      }
    }
  ]
}
  1. In the src/templates folder create a .vue file with the same name you defined in the typeName option (default is StoryblokEntry). After that set a <page-query> tag to load the data from GraphQL. For example:
<page-query>
query StoryblokEntry ($id: ID) {
  storyblokEntry (id: $id) {
    id
    slug
    content
  }
}
</page-query>
  1. Edit the file gridsome.server.js to use a GraphQL query to generate the pages using Storyblok's full_slug attribute
module.exports = function (api) {
  api.createPages(async ({ graphql, createPage }) => {
    const { data } = await graphql(`{
      allStoryblokEntry {
        edges {
          node {
            id
            full_slug
          }
        }
      }
    }`)
 
    data.allStoryblokEntry.edges.forEach(({ node }) => {
      createPage({
        path: `/${node.full_slug}`,
        component: './src/templates/StoryblokEntry.vue',
        context: {
          id: node.id
        }
      })
    })
  })
}

The options object in details

When you declare the use of the Storyblok plugin you can pass following options:

{
  use: 'gridsome-source-storyblok',
  options: {
    client: {
      // The Storyblok JS Client options here (https://github.com/storyblok/storyblok-js-client)
      accessToken: '<YOUR_ACCESS_TOKEN>' // required!
    },
    version: 'draft', // Optional. Can be draft or published (default draft)
    // Optional: Config story and tag types names and request calls
    types: {
      story: {
        name: 'StoryblokEntry', // The name of Story template and type (default StoryblokEntry)
        params: {} // Additional query parameters
      },
      tag: {
        name: 'StoryblokTag', // The name of Tag template and type (default StoryblokTag)
        params: {} // Additional query parameters
      }
    },
    downloadImages: true, // Optional. default false,
    imageDirectory: 'storyblok_images', // Optional. Folder to put the downloaded images
    // Optional: Get additional types like datasources, links or datasource_entries
    additionalTypes: [
      {
        type: 'datasources', // required
        name: 'StoryblokDatasource' // required
      },
      {
        type: 'datasource_entries',
        name: 'StoryblokDatasourceEntry',
        params: { ...additionalQueryParams } // optional
      },
      {
        type: 'links',
        name: 'StoryblokLink'
      }
    ]
  }
}

Rendering of the Rich Text field

This plugin comes with a built in renderer to get html output from Storyblok's Rich Text field. Create and register a Richtext.vue component with the code below to use the renderer in your components like this: <richtext :text="blok.richtext"></richtext>.

<template>
  <div>
    <div v-html="richtext"></div>
  </div>
</template>
 
<script>
export default {
  props: ['text'],
  computed: {
    richtext() {
      return this.text ? this.$storyapi.richTextResolver.render(this.text) : ''
    }
  }
}
</script>

Downloading images

When downloadImages option is marked as true, this plugin will be searching in each story for a image and download it to src/<imageDirectory> folder. In your components, you can use the g-image tag. An important thing is that image property in story will be a object with some fields, not a string. Bellow, we show you an example of this:

<template>
  <div>
    <g-image :src="imageURL"></g-image>
  </div>
</template>
 
<script>
export default {
  props: ['blok'],
  computed: {
    imageURL () {
      // When options.downloadImages is false, the image property is a string
      if (typeof this.blok.image === 'string') {
        return this.blok.image
      }
 
      // When options.downloadImages is true, the image property is a object
      // Reference of this: https://github.com/gridsome/gridsome/issues/292
      const path = this.blok.image.path
      return require('!!assets-loader?width=800&quality=100&fit=inside!~/' + path)
    }
  }
}
</script> 
 
<style scoped>
img {
  max-width: 100%;
}
</style> 

Working with Tags

By default, this plugin will get all tags and create a reference to stories entries (as described in create-schema function), so it's possible to list stories from tag, for example.

You can change the name of template file and types by setting the options.types.tag.name option in gridsome.config.js (StoryblokTag is default).

Example

Create a StoryblokTag.vue file in src/templates folder with the following code:

<template>
  <Layout>
    <h1>{{ $page.storyblokTag.name }}</h1>
    <ul>
      <li v-for="edge in $page.storyblokTag.belongsTo.edges" :key="edge.node.id">
        <g-link :to="edge.node.full_slug">
          {{ edge.node.name }}
        </g-link>
      </li>
    </ul>
  </Layout>
</template>
 
<page-query>
query ($id: ID!) {
  storyblokTag(id: $id) {
    name
    belongsTo {
      edges {
        node {
          ... on StoryblokEntry {
            id
            full_slug
            name
          }
        }
      }
    }
  }
}
</page-query>

In your gridsome.server.js file, it will be necessary to create a pages for each tag as the following:

module.exports = function (api) {
  api.createPages(async ({ graphql, createPage }) => {
    // previous code (create pages to stories)
 
    const { data: tagData } = await graphql(`{
      allStoryblokTag {
        edges {
          node {
            id
            name
          }
        }
      }
    }`)
 
    tagData.allStoryblokTag.edges.forEach(({ node }) => {
      createPage({
        path: `/tag/${node.name}`,
        component: './src/templates/StoryblokTag.vue',
        context: {
          id: node.id
        }
      })
    })
  })
})

That's all! In your browser you can view a list of stories by the foo tag in http://localhost:8080/tag/foo.

Load data to different collections

To load data to multiple collections, you need to declare the configuration multiple times in gridsome.config.js. Like this:

{
  siteName: 'Gridsome',
  plugins: [
    // default collection
    {
      use: 'gridsome-source-storyblok',
      options: {
        client: {
          accessToken: '<YOUR_ACCESS_TOKEN>'
        }
      }
    },
 
    // specific collection (blogging for example)
    {
      use: 'gridsome-source-storyblok',
      options: {
        client: {
          accessToken: '<YOUR_ACCESS_TOKEN>'
        },
        types: {
          story: {
            typeName: 'StoryblokBlogEntry',
            params: {
              starts_with: 'blog/'
            }
          },
          tag: {
            typeName: 'StoryblokBlogTag'
          }
        }
      }
    }
  ]
}

And, in your gridsome.server.js, you can generate your pages for each collection, attending to the name given to each collection.

Contribution

Fork me on Github.

This project use semantic-release for generate new versions by using commit messages and we use the Angular Convention to naming the commits. Check this question about it in semantic-release FAQ.

Install

npm i gridsome-source-storyblok

DownloadsWeekly Downloads

104

Version

1.0.2

License

MIT

Unpacked Size

36.2 kB

Total Files

24

Last publish

Collaborators

  • avatar
  • avatar
  • avatar
  • avatar