Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/storyblok/storyblok-astro
Astro SDK for Storyblok CMS
https://github.com/storyblok/storyblok-astro
Last synced: 6 days ago
JSON representation
Astro SDK for Storyblok CMS
- Host: GitHub
- URL: https://github.com/storyblok/storyblok-astro
- Owner: storyblok
- License: mit
- Created: 2022-08-31T12:29:30.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2025-01-31T04:41:07.000Z (15 days ago)
- Last Synced: 2025-02-01T12:20:08.702Z (13 days ago)
- Language: TypeScript
- Homepage:
- Size: 5.57 MB
- Stars: 186
- Watchers: 18
- Forks: 32
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-astro - @storyblok/astro - Astro module for the Storyblok, Headless CMS (Astro Integrations)
README
## Kickstart a new project
Are you eager to dive into coding? **[Follow these steps to kickstart a new project with Storyblok and Astro](https://www.storyblok.com/technologies?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro#astro)**, and get started in just a few minutes!
## Ultimate Tutorial
Are you looking for a hands-on, step-by-step tutorial? The **[Astro Ultimate Tutorial](https://www.storyblok.com/tp/the-storyblok-astro-ultimate-tutorial?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro)** has you covered! It provides comprehensive instructions on building a complete, multilingual website using Storyblok and Astro from start to finish.
## Installation
Install `@storyblok/astro`:
```bash
npm install @storyblok/astro
# yarn add @storyblok/astro
# See below for pnpm
```> [!NOTE]
> With pnpm, hoist Storyblok dependencies publicly with `.npmrc`. For more information, please refer to the [pnpm documentation](https://pnpm.io/npmrc).Add the following code to `astro.config.mjs` and replace the `accessToken` with the preview API token of your Storyblok space.
```js
import { defineConfig } from "astro/config";
import { storyblok } from "@storyblok/astro";export default defineConfig({
integrations: [
storyblok({
accessToken: "",
}),
],
});
```> [!WARNING]
> This SDK uses the Fetch API under the hood. If your environment doesn't support it, you need to install a polyfill like [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch). More info on [storyblok-js-client docs](https://github.com/storyblok/storyblok-js-client#fetch-use-polyfill-if-needed---version-5).### Options
When you initialize the integration, you can pass all [_@storyblok/js_ options](https://github.com/storyblok/storyblok-js#features-and-api).
```js
// Defaults
storyblok({
accessToken: "",
bridge: true,
livePreview: false,
apiOptions: {}, // storyblok-js-client options
components: {},
componentsDir: "src",
enableFallbackComponent: false,
customFallbackComponent: "",
useCustomApi: false,
});
```> [!NOTE]
> By default, the `apiPlugin` from `@storyblok/js` is loaded. If you want to use your own method to fetch data from Storyblok, you can disable this behavior by setting `useCustomApi` to `true`, resulting in an optimized final bundle.#### Region parameter
Possible values:
- `eu` (default): For spaces created in the EU
- `us`: For spaces created in the US
- `ca`: For spaces created in Canada
- `ap`: For spaces created in Australia
- `cn`: For spaces created in ChinaFull example for a space created in the US:
```js
storyblok({
accessToken: "",
apiOptions: {
region: "us",
},
});
```> [!WARNING]
> The `region` parameter **must** be specified unless the space was created in the EU.## Getting started
### 1. Creating and linking your components to the Storyblok Visual Editor
Link your Astro components to their equivalents created in Storyblok with the following steps.
First, load the components globally by specifying their name and their path in `astro.config.mjs`:
```js
components: {
page: "storyblok/Page",
feature: "storyblok/Feature",
grid: "storyblok/Grid",
teaser: "storyblok/Teaser",
},
```> [!NOTE]
> The `src` folder is automatically added to the beginning of the path, so in this example your Astro components should be located here:
>
> - `src/storyblok/Page.astro`
> - `src/storyblok/Feature.astro`
> - `src/storyblok/Grid.astro`
> - `src/storyblok/Teaser.astro`
>
> You can choose any other folder in the `src` directory for your Astro components.> [!NOTE]
> If you prefer to use a different folder than `src`, you can specify one using the `componentsDir` option:
>
> ```js
> storyblok({
> componentsDir: "app",
> });
> ```
>
> Now, your Storyblok components can be located anywhere in the `app` folder, e.g. `page: "storyblok/Page"` for `app/storyblok/Page.astro` or `page: "Page"` for `app/Page.astro`.For each component, use the `storyblokEditable()` function on its root element, passing the `blok` property that they receive:
```jsx
---
import { storyblokEditable } from "@storyblok/astro";const { blok } = Astro.props
---
{blok.headline}
```Finally, you can use the provided `` for nested components; it will automatically render them (if they are registered globally):
```jsx
---
import { storyblokEditable } from "@storyblok/astro";
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";const { blok } = Astro.props
---{blok.body?.map(blok => {return })}
```
> [!NOTE]
> The `blok` is the actual blok data coming from [Storblok's Content Delivery API](https://www.storyblok.com/docs/api/content-delivery/v2?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro).#### Using fallback components
By default, `@storyblok/astro` throws an error if a component is not implemented. Setting `enableFallbackComponent` to `true` bypasses that behavior, rendering a fallback component in the frontend instead. You can also use a custom fallback component by (for example) setting `customFallbackComponent: "storyblok/MyCustomFallback"`.
#### Using partial hydration
If you want to use partial hydration with any of the [frameworks supported by Astro](https://docs.astro.build/en/guides/integrations-guide/#article), follow these steps:
1. [Install the official Astro integration for your desired framework](https://docs.astro.build/en/guides/integrations-guide/#automatic-integration-setup)
2. Create an Astro component that serves as a wrapper and utilizes the most suitable [client directive](https://docs.astro.build/en/reference/directives-reference/#client-directives)
3. Create the actual component in Vue, Svelte, React or any other supported frameworkFor working examples, please refer to the [Live Demo on Stackblitz](https://stackblitz.com/edit/astro-sdk-demo).
### 2. Getting Storyblok Stories and using the Storyblok Bridge
#### Fetching one Story
Use the `useStoryblokApi` function to have access to an instance of `storyblok-js-client`:
```jsx
---
import { useStoryblokApi } from "@storyblok/astro";
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";const storyblokApi = useStoryblokApi();
const { data } = await storyblokApi.get("cdn/stories/home", {
version: "draft",
});const story = data.story;
---```
> [!NOTE]
> The available methods are described in the [storyblok-js-client](https://github.com/storyblok/storyblok-js-client#method-storyblokget) repository.#### Dynamic Routing
In order to dynamically generate Astro pages based on the Stories in your Storyblok Space, you can use the [Storyblok Links API](https://www.storyblok.com/docs/api/content-delivery/v2#core-resources/links/links) and the Astro [`getStaticPaths()` function](https://docs.astro.build/en/reference/api-reference/#getstaticpaths) similar to this example:
```jsx
---
import { useStoryblokApi } from "@storyblok/astro";
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";export async function getStaticPaths() {
const storyblokApi = useStoryblokApi();const { data } = await storyblokApi.getAll("cdn/links", {
version: "draft",
});
let links = data.links;
links = Object.values(links);return links.map((link) => {
return {
params: { slug: link.slug },
};
});
}const { slug } = Astro.params;
const storyblokApi = useStoryblokApi();
const { data } = await storyblokApi.get(`cdn/stories/${slug}`, {
version: "draft",
});const story = data.story;
---```
### Using the Storyblok Bridge
The Storyblok Bridge is enabled by default. If you would like to disable it or enable it conditionally (e.g. depending on the environment) you can set the `bridge` parameter to `true` or `false` in `astro.config.mjs`:
You can also provide a `StoryblokBridgeConfigV2` configuration object to the `bridge` parameter.
```ts
bridge: {
customParent?: string,
preventClicks?: boolean, // Defaults to false.
resolveRelations?: strings[],
resolveLinks?: string
}
```- `customParent` is used to provide a custom URL for the Storyblok editor iframe.
- `preventClicks` prevents the default behaviour of clicks when inside the Storyblok editor.
- `resolveRelations` may be needed to resolve the same relations that are already resolved in the API requests via the `resolve_relations` parameter.
- `resolveLinks` may be needed to resolve link fields.> [!NOTE]
> `resolveRelations` and `resolveLinks` will only become effective if the live preview feature is used (`getLiveStory()`).The provided options will be used when initializing the Storyblok Bridge. You can find more information about the Storyblok Bridge and its configuration options on the [In Depth Storyblok Bridge guide](https://www.storyblok.com/docs/guide/in-depth/storyblok-latest-js-v2?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro).
If you want to deploy a dedicated preview environment with the Bridge enabled, allowing users of the Storyblok CMS to see their changes being reflected on the frontend directly without having to rebuild the static site, you can enable Server Side Rendering for that particular use case. More information can be found in the [Astro Docs](https://docs.astro.build/en/guides/server-side-rendering/).
## Enabling Live Preview for Storyblok's Visual Editor
The Astro SDK provides a live preview feature, designed to offer real-time editing capabilities for an enhanced user experience in Storyblok's Visual Editor.
> [!NOTE]
> To utilize the Astro Storyblok Live feature, Astro must be configured to run in SSR mode.To activate the live preview feature, follow these steps:
1. Set `livePreview` to `true` in your `astro.config.mjs` file.
```js
//astro.config.mjs
export default defineConfig({
integrations: [
storyblok({
accessToken: "OsvN..",
livePreview: true,
}),
],
output: "server", // Astro must be configured to run in SSR mode
});
```2. Additionally, use `getLiveStory` on your Astro pages.
```jsx
//pages/[...slug].astro
---
import { getLiveStory, useStoryblokApi } from '@storyblok/astro';
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";const { slug } = Astro.params;
let story = null;const liveStory = await getLiveStory(Astro);
if (liveStory) {
story = liveStory;
} else {
const sbApi = useStoryblokApi();
const { data } = await sbApi.get(`cdn/stories/${slug || 'home'}`, {
version: 'draft',
resolve_relations: ['featured-articles.posts'],
});
story = data?.story;
}
// If you are using `resolve_relations` or `resolve_links`, you must also pass them to the Bridge configuration in `astro.config.mjs`.
---```
## Dom update event```js
//page.astrodocument.addEventListener('storyblok-live-preview-updated', () => {
// Here is the callback we could run code every time the body is updated via live preview
console.log('Live preview: body updated');
// Example regenerated all your css
});```
## Rendering Rich Text> [!NOTE]
> While @storyblok/astro provides basic richtext rendering capabilities, for advanced use cases, it is highly recommended to use [storyblok-rich-text-astro-renderer](https://github.com/NordSecurity/storyblok-rich-text-astro-renderer).You can easily render rich text by using either the `renderRichText` function included in `@storyblok/astro`.
Use `renderRichText`, which only supports parsing and returning native HTML tags, if you are not embedding `bloks` in your rich text. Then you can use the [`set:html` directive](https://docs.astro.build/en/reference/directives-reference/#sethtml):```jsx
---
import { renderRichText } from "@storyblok/astro";const { blok } = Astro.props
const renderedRichText = renderRichText(blok.text)
---
```You can also set a **custom Schema and component resolver** by passing the options as the second parameter of the `renderRichText` function:
```jsx
import { RichTextSchema, renderRichText } from "@storyblok/astro";
import cloneDeep from "clone-deep";const mySchema = cloneDeep(RichTextSchema); // you can make a copy of the default RichTextSchema
// ... and edit the nodes and marks, or add your own.
// Check the base RichTextSchema source here https://github.com/storyblok/storyblok-js-client/blob/v4/source/schema.jsconst { blok } = Astro.props;
const renderedRichText = renderRichText(blok.text, {
schema: mySchema,
resolver: (component, blok) => {
switch (component) {
case "my-custom-component":
return `${blok.text}`;
break;
default:
return `Component ${component} not found`;
}
},
});
```### RichTextRenderer `deprecated`
~~Use the `` component if you are embedding `bloks` in your rich text:~~
> [!IMPORTANT]
> As of `@storyblok/astro` v5, the `` component has been removed. Use the `renderRichText` function instead.## API
### useStoryblokApi()
Returns the instance of the `storyblok-js-client`.
## The Storyblok JavaScript SDK Ecosystem
![A visual representation of the Storyblok JavaScript SDK Ecosystem](https://a.storyblok.com/f/88751/2400x1350/be4a4a4180/sdk-ecosystem.png/m/1200x0)
## Acknowledgements
### Astro
We extend our deepest gratitude to the [Astro](https://astro.build/) team, especially Tony Sullivan, [Matthew Philips](https://x.com/matthewcp), and [Nate Moore](https://x.com/n_moore), for their unwavering support in enhancing this integration. Your partnership is immensely valued.
### Virtual Identity
Our heartfelt thanks go to [Virtual Identity](https://www.virtual-identity.com/), one of our closest agency partners. The live preview feature owes its existence to the ingenuity and innovation of their team. Special recognition goes to their developer [Mario Hamann](https://github.com/mariohamann) for his pivotal live preview POC and continuous support.
## Further Resources
- [Quick Start](https://www.storyblok.com/technologies?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro)
- [API Documentation](https://www.storyblok.com/docs/api?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro)
- [Developer Tutorials](https://www.storyblok.com/tutorials?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro)
- [Developer Guides](https://www.storyblok.com/docs/guide/introduction?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro)
- [FAQs](https://www.storyblok.com/faqs?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro)## Support
- Bugs or Feature Requests? [Submit an issue](/../../issues/new);
- Do you have questions about this SDK? Or would you like to join the growing community of `@storyblok/astro` users? [Join the Astro Discord Community](https://discord.com/channels/830184174198718474/1002802280267001858)
- Do you have questions about Storyblok or do you need help? [Join the Storyblok Discord Community](https://discord.gg/jKrbAMz).## Contributing
Please review our [Contributing Guidelines](https://github.com/storyblok/.github/blob/master/contributing.md) and [Code of Conduct](https://www.storyblok.com/trust-center?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro#code-of-conduct) before contributing.
This project employs [semantic-release](https://semantic-release.gitbook.io/semantic-release/) to generate new versions based on commit messages, following the Angular Commit Message Convention.
When using playgrounds during development, ensure the build is running in watch mode for an efficient workflow.