@storyblok/nuxt 8.0.0 → 8.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -411
- package/dist/module.d.mts +18 -1
- package/dist/module.d.ts +18 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +2 -2
- package/dist/runtime/composables/useAsyncStoryblok.d.ts +68 -0
- package/dist/runtime/composables/useAsyncStoryblok.js +11 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,448 +1,79 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
<h1 align="center">@storyblok/nuxt</h1>
|
|
6
|
+
<p>
|
|
7
|
+
The Nuxt 3 module to interact with <a href="http://www.storyblok.com?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt" target="_blank">Storyblok API</a> and enable the <a href="https://www.storyblok.com/docs/guide/essentials/visual-editor?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt" target="_blank">Real-time Visual Editing Experience</a>.
|
|
8
|
+
</p>
|
|
9
|
+
<br />
|
|
7
10
|
</div>
|
|
8
11
|
|
|
9
12
|
<p align="center">
|
|
10
13
|
<a href="https://npmjs.com/package/@storyblok/nuxt">
|
|
11
|
-
<img src="https://img.shields.io/npm/v/@storyblok/nuxt/latest.svg?style=flat-square" alt="Storyblok
|
|
14
|
+
<img src="https://img.shields.io/npm/v/@storyblok/nuxt/latest.svg?style=flat-square&color=8d60ff" alt="Storyblok Nuxt Module" />
|
|
12
15
|
</a>
|
|
13
16
|
<a href="https://npmjs.com/package/@storyblok/nuxt" rel="nofollow">
|
|
14
|
-
<img src="https://img.shields.io/npm/dt/@storyblok/nuxt.svg?style=
|
|
17
|
+
<img src="https://img.shields.io/npm/dt/@storyblok/nuxt.svg?style=appveyor&color=8d60ff" alt="npm">
|
|
15
18
|
</a>
|
|
16
|
-
</p>
|
|
17
|
-
|
|
18
|
-
<p align="center">
|
|
19
19
|
<a href="https://storyblok.com/join-discord">
|
|
20
20
|
<img src="https://img.shields.io/discord/700316478792138842?label=Join%20Our%20Discord%20Community&style=appveyor&logo=discord&color=8d60ff">
|
|
21
21
|
</a>
|
|
22
22
|
<a href="https://twitter.com/intent/follow?screen_name=storyblok">
|
|
23
23
|
<img src="https://img.shields.io/badge/Follow-%40storyblok-8d60ff?style=appveyor&logo=twitter" alt="Follow @Storyblok" />
|
|
24
|
-
</a><br
|
|
25
|
-
<a href="https://app.storyblok.com/#!/signup?utm_source=github.com&utm_medium=readme&utm_campaign
|
|
24
|
+
</a><br/>
|
|
25
|
+
<a href="https://app.storyblok.com/#!/signup?utm_source=github.com&utm_medium=readme&utm_campaign=@storyblok/nuxt">
|
|
26
26
|
<img src="https://img.shields.io/badge/Try%20Storyblok-Free-8d60ff?style=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAHqADAAQAAAABAAAAHgAAAADpiRU/AAACRElEQVRIDWNgGGmAEd3D3Js3LPrP8D8WXZwSPiMjw6qvPoHhyGYwIXNAbGpbCjbzP0MYuj0YFqMroBV/wCxmIeSju64eDNzMBJUxvP/9i2Hnq5cM1devMnz984eQsQwETeRhYWHgIcJiXqC6VHlFBjUeXgav40cIWkz1oLYXFmGwFBImaDFBHyObcOzdW4aSq5eRhRiE2dgYlpuYoYSKJi8vw3GgWnyAJIs/AuPu4scPGObd/fqVQZ+PHy7+6udPOBsXgySLDfn5GRYYmaKYJcXBgWLpsx8/GPa8foWiBhuHJIsl2DkYQqWksZkDFgP5PObcKYYff//iVAOTIDlx/QPqRMb/YSYBaWlOToZIaVkGZmAZSQiQ5OPtwHwacuo4iplMQEu6tXUZMhSUGDiYmBjylFQYvv/7x9B04xqKOnQOyT5GN+Df//8M59ASXKyMHLoyDD5JPtbj42OYrm+EYgg70JfuYuIoYmLs7AwMjIzA+uY/zjAnyWJpDk6GOFnCvrn86SOwmsNtKciVFAc1ileBHFDC67lzG10Yg0+SjzF0ownsf/OaofvOLYaDQJoQIGix94ljv1gIZI8Pv38zPvj2lQWYf3HGKbpDCFp85v07NnRN1OBTPY6JdRSGxcCw2k6sZuLVMZ5AV4s1TozPnGGFKbz+/PE7IJsHmC//MDMyhXBw8e6FyRFLv3Z0/IKuFqvFyIqAzd1PwBzJw8jAGPfVx38JshwlbIygxmYY43/GQmpais0ODDHuzevLMARHBcgIAQAbOJHZW0/EyQAAAABJRU5ErkJggg==" alt="Follow @Storyblok" />
|
|
27
27
|
</a>
|
|
28
28
|
</p>
|
|
29
29
|
|
|
30
|
-
##
|
|
31
|
-
Are you eager to dive into coding? **[Follow these steps to kickstart a new project with Storyblok and Nuxt](https://www.storyblok.com/technologies?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt#nuxt)**, and get started in just a few minutes!
|
|
32
|
-
|
|
33
|
-
## Ultimate Tutorial
|
|
34
|
-
Are you looking for a hands-on, step-by-step tutorial? The **[Nuxt Ultimate Tutorial](https://www.storyblok.com/tp/storyblok-nuxt-ultimate-tutorial?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt)** has you covered! It provides comprehensive instructions on building a complete, multilingual website using Storyblok and Nuxt from start to finish.
|
|
35
|
-
|
|
36
|
-
## Installation
|
|
37
|
-
|
|
38
|
-
Install `@storyblok/nuxt`:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npx nuxi@latest module add storyblok
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Add following code to modules section of `nuxt.config.js` and replace the accessToken with API token from Storyblok space.
|
|
45
|
-
|
|
46
|
-
```js
|
|
47
|
-
import { defineNuxtConfig } from 'nuxt';
|
|
48
|
-
|
|
49
|
-
export default defineNuxtConfig({
|
|
50
|
-
modules: [
|
|
51
|
-
['@storyblok/nuxt', { accessToken: '<your-access-token>' }]
|
|
52
|
-
// ...
|
|
53
|
-
]
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
You can also use the `storyblok` config if you prefer:
|
|
58
|
-
|
|
59
|
-
```js
|
|
60
|
-
import { defineNuxtConfig } from 'nuxt';
|
|
61
|
-
|
|
62
|
-
export default defineNuxtConfig({
|
|
63
|
-
modules: ['@storyblok/nuxt'],
|
|
64
|
-
storyblok: {
|
|
65
|
-
accessToken: '<your-access-token>'
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
> **Warning**
|
|
71
|
-
> 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).
|
|
72
|
-
|
|
73
|
-
### Options
|
|
74
|
-
|
|
75
|
-
When you initialize the module, you can pass all [_@storyblok/vue_ options](https://github.com/storyblok/storyblok-vue#storyblok-api) plus a `bridge` option explained in our [JS SDK Storyblok bridge section](https://github.com/storyblok/storyblok-js#storyblok-bridge) and a `enableSudoMode` option to define your own plugin (see below).
|
|
76
|
-
|
|
77
|
-
> **Note**
|
|
78
|
-
> If you want to use Storyblok inside `nuxt-devtools` you can use the option `devtools`, if enabled, make sure to have installed the @nuxt/devtools module and enable it on your nuxt config.
|
|
79
|
-
|
|
80
|
-
```js
|
|
81
|
-
// Defaults
|
|
82
|
-
["@storyblok/nuxt", {
|
|
83
|
-
{
|
|
84
|
-
accessToken: "<your-access-token>",
|
|
85
|
-
bridge: true,
|
|
86
|
-
devtools: true,
|
|
87
|
-
apiOptions: {}, // storyblok-js-client options
|
|
88
|
-
}
|
|
89
|
-
}]
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Define your own plugin
|
|
93
|
-
|
|
94
|
-
While the recommended approach covers most cases, there are specific instances where you may need to use the `enableSudoMode` option and disable our plugin, allowing you to incorporate your own.
|
|
95
|
-
|
|
96
|
-
```js
|
|
97
|
-
// nuxt.config.ts
|
|
98
|
-
modules: [
|
|
99
|
-
[
|
|
100
|
-
'@storyblok/nuxt',
|
|
101
|
-
{
|
|
102
|
-
accessToken: '<your-access-token>',
|
|
103
|
-
enableSudoMode: true
|
|
104
|
-
}
|
|
105
|
-
]
|
|
106
|
-
];
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
To include additional functionalities in the SDK's `apiOptions`, such as custom cache methods, you can implement the following solution inside the plugins folder (autoimported):
|
|
110
|
-
|
|
111
|
-
```js
|
|
112
|
-
// plugins/storyblok.js
|
|
113
|
-
import { apiPlugin, StoryblokVue } from '@storyblok/vue';
|
|
114
|
-
|
|
115
|
-
export default defineNuxtPlugin(({ vueApp }) => {
|
|
116
|
-
vueApp.use(StoryblokVue, {
|
|
117
|
-
accessToken: '<your-access-token>',
|
|
118
|
-
apiOptions: {
|
|
119
|
-
cache: {
|
|
120
|
-
type: 'custom',
|
|
121
|
-
custom: {
|
|
122
|
-
flush() {
|
|
123
|
-
console.log('all right');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
use: [apiPlugin]
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Region parameter
|
|
134
|
-
|
|
135
|
-
Possible values:
|
|
136
|
-
|
|
137
|
-
- `eu` (default): For spaces created in the EU
|
|
138
|
-
- `us`: For spaces created in the US
|
|
139
|
-
- `ap`: For spaces created in Australia
|
|
140
|
-
- `ca`: For spaces created in Canada
|
|
141
|
-
- `cn`: For spaces created in China
|
|
142
|
-
|
|
143
|
-
Full example for a space created in the US:
|
|
144
|
-
|
|
145
|
-
```js
|
|
146
|
-
["@storyblok/nuxt", {
|
|
147
|
-
{
|
|
148
|
-
accessToken: "<your-access-token>",
|
|
149
|
-
apiOptions: {
|
|
150
|
-
region: "us"
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}]
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
> **Important**
|
|
157
|
-
> For spaces created in the United States or China, the `region` parameter **must** be specified.
|
|
158
|
-
|
|
159
|
-
## Getting started
|
|
160
|
-
|
|
161
|
-
### 1. Creating and linking your components to the Storyblok Visual Editor
|
|
162
|
-
|
|
163
|
-
To link your Vue components to the equivalent one in your Storyblok space:
|
|
164
|
-
|
|
165
|
-
- First, you need to load them globally adding them to the `~/storyblok` directory. It's important to name them with Pascal case in your code `ExampleComponent.vue` and with a hyphen inside your Storyblok space `example-component`, so they will be imported automatically.
|
|
166
|
-
|
|
167
|
-
If you want to define your own directory for the Storyblok related components, you can use the option `componentsDir` in the `nuxt.config.js`:
|
|
168
|
-
|
|
169
|
-
```js
|
|
170
|
-
// nuxt.config.ts
|
|
171
|
-
modules: [
|
|
172
|
-
[
|
|
173
|
-
"@storyblok/nuxt",
|
|
174
|
-
{
|
|
175
|
-
accessToken: "<your-access-token>",
|
|
176
|
-
componentsDir: '~/components',
|
|
177
|
-
}
|
|
178
|
-
]
|
|
179
|
-
],
|
|
180
|
-
components: {
|
|
181
|
-
dirs: [
|
|
182
|
-
{
|
|
183
|
-
path: '~/components/storyblok',
|
|
184
|
-
global: true,
|
|
185
|
-
}
|
|
186
|
-
]
|
|
187
|
-
},
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Otherwise, you can set another directory and load them manually (for example, by [using a Nuxt plugin](https://stackoverflow.com/questions/43040692/global-components-in-vue-nuxt)).
|
|
191
|
-
|
|
192
|
-
> **Warning**
|
|
193
|
-
> Take into account that if you name a component inside the `storyblok` folder the same as another in the `components` folder, it won't work properly. Tip: Keep the components in your Nuxt project with different names.
|
|
194
|
-
|
|
195
|
-
- For each component, use the `v-editable` directive on its root element, passing the `blok` property that they receive:
|
|
196
|
-
|
|
197
|
-
```html
|
|
198
|
-
<div v-editable="blok"></div>
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
- Finally, use `<StoryblokComponent>` which is available globally in the Nuxt app:
|
|
202
|
-
|
|
203
|
-
```html
|
|
204
|
-
<StoryblokComponent :blok="blok" />
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
> 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-nuxt).
|
|
208
|
-
|
|
209
|
-
### 2. Getting Storyblok Stories and listen to Visual Editor events
|
|
30
|
+
## Features
|
|
210
31
|
|
|
211
|
-
|
|
32
|
+
- Fetch content from the Content Delivery API
|
|
33
|
+
- Connect frontend components with the Visual Editor via StoryblokBridge
|
|
34
|
+
- Render rich text content with the Storyblok Rich Text Renderer based on `@storyblok/richtext`
|
|
35
|
+
- Nuxt 3 module with automatic setup and configuration
|
|
36
|
+
- Auto-imported composables: `useAsyncStoryblok`, `useStoryblok`, `useStoryblokApi`, `useStoryblokBridge`
|
|
37
|
+
- Auto-imported components: `StoryblokComponent`, `StoryblokRichText`
|
|
38
|
+
- Auto-imported utilities: `renderRichText`, `useStoryblokRichText`
|
|
39
|
+
- Built-in TypeScript support with auto-generated types
|
|
40
|
+
- SSR/SSG compatibility with proper hydration
|
|
41
|
+
- DevTools integration for Storyblok management
|
|
212
42
|
|
|
213
|
-
|
|
43
|
+
## Documentation
|
|
214
44
|
|
|
215
|
-
|
|
45
|
+
For complete documentation, please visit [package reference](https://www.storyblok.com/docs/packages/storyblok-nuxt)
|
|
216
46
|
|
|
217
|
-
|
|
218
|
-
> If you want to know more about versioning `{ version: "draft" /* or "publish" */ }` then go to the section [Working with preview and/or production environments](#3-working-with-preview-andor-production-environments)
|
|
219
|
-
|
|
220
|
-
```html
|
|
221
|
-
<script setup>
|
|
222
|
-
const story = await useAsyncStoryblok(
|
|
223
|
-
"vue",
|
|
224
|
-
{ version: "draft", resolve_relations: "Article.author" }, // API Options
|
|
225
|
-
{ resolveRelations: ["Article.author"], resolveLinks: "url" } // Bridge Options
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
if (story.value.status) {
|
|
229
|
-
throw createError({
|
|
230
|
-
statusCode: story.value.status,
|
|
231
|
-
statusMessage: story.value.response
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
</script>
|
|
235
|
-
|
|
236
|
-
<template>
|
|
237
|
-
<StoryblokComponent v-if="story" :blok="story.content" />
|
|
238
|
-
</template>
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
Which is the short-hand equivalent to using `useStoryblokApi` inside `useState` and `useStoryblokBridge` functions separately:
|
|
242
|
-
|
|
243
|
-
```html
|
|
244
|
-
<script setup>
|
|
245
|
-
const story = useState();
|
|
246
|
-
const storyblokApi = useStoryblokApi();
|
|
247
|
-
|
|
248
|
-
const { data } = await storyblokApi.get(
|
|
249
|
-
`cdn/stories/vue`,
|
|
250
|
-
{
|
|
251
|
-
version: "draft"
|
|
252
|
-
}
|
|
253
|
-
);
|
|
254
|
-
story.value = data.story;
|
|
255
|
-
|
|
256
|
-
onMounted(() => {
|
|
257
|
-
useStoryblokBridge(
|
|
258
|
-
story.value.id,
|
|
259
|
-
(evStory) => (story.value = evStory),
|
|
260
|
-
{ resolveRelations: ["Article.author"], resolveLinks: "url" } // Bridge Options
|
|
261
|
-
);
|
|
262
|
-
});
|
|
263
|
-
</script>
|
|
264
|
-
|
|
265
|
-
<template>
|
|
266
|
-
<StoryblokComponent v-if="story" :blok="story.content" />
|
|
267
|
-
</template>
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
> The `useState` is an SSR-friendly `ref` replacement. Its value will be preserved after server-side rendering (during client-side hydration).
|
|
271
|
-
|
|
272
|
-
## Rendering Rich Text
|
|
273
|
-
|
|
274
|
-
You can render rich text fields by using the `StoryblokRichText` component:
|
|
275
|
-
|
|
276
|
-
```html
|
|
277
|
-
<template>
|
|
278
|
-
<StoryblokRichText :doc="blok.articleContent" />
|
|
279
|
-
</template>
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
Or you can have more control by using the `useStoryblokRichText` composable:
|
|
283
|
-
|
|
284
|
-
```html
|
|
285
|
-
<script setup>
|
|
286
|
-
const { render } = useStoryblokRichText({
|
|
287
|
-
// options like resolvers
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
const root = () => render(blok.articleContent);
|
|
291
|
-
</script>
|
|
292
|
-
|
|
293
|
-
<template>
|
|
294
|
-
<root />
|
|
295
|
-
</template>
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
For more incredible options you can pass to the `useStoryblokRichText`, please consult the [Full options](https://github.com/storyblok/richtext?tab=readme-ov-file#options) documentation.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
#### Overriding the default resolvers
|
|
302
|
-
|
|
303
|
-
You can override the default resolvers by passing a `resolver` prop to the `StoryblokRichText` component, for example, to use vue-router links or add a custom codeblok component: :
|
|
304
|
-
|
|
305
|
-
```html
|
|
306
|
-
<script setup>
|
|
307
|
-
import { NuxtLink } from '#components';
|
|
308
|
-
import type { StoryblokRichTextNode } from '@storyblok/vue';
|
|
309
|
-
import CodeBlok from "./components/CodeBlok.vue";
|
|
310
|
-
|
|
311
|
-
const resolvers = {
|
|
312
|
-
// NuxtLink example:
|
|
313
|
-
[MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
|
|
314
|
-
h(NuxtLink, {
|
|
315
|
-
to: node.attrs?.href,
|
|
316
|
-
target: node.attrs?.target,
|
|
317
|
-
}, node.text),
|
|
318
|
-
// Custom code block component example:
|
|
319
|
-
[BlockTypes.CODE_BLOCK]: (node: Node) => {
|
|
320
|
-
return h(CodeBlock, {
|
|
321
|
-
class: node?.attrs?.class,
|
|
322
|
-
}, node.children)
|
|
323
|
-
},
|
|
324
|
-
}
|
|
325
|
-
</script>
|
|
326
|
-
|
|
327
|
-
<template>
|
|
328
|
-
<StoryblokRichText :doc="blok.articleContent" :resolvers="resolvers" />
|
|
329
|
-
</template>
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
If you want to use the `useStoryblokRichText` composable, you can pass the `resolvers` via the options object:
|
|
333
|
-
|
|
334
|
-
```html
|
|
335
|
-
<script setup>
|
|
336
|
-
import CodeBlok from "./components/CodeBlok.vue";
|
|
337
|
-
|
|
338
|
-
const { render } = useStoryblokRichText({
|
|
339
|
-
resolvers: {
|
|
340
|
-
// NuxtLink example:
|
|
341
|
-
[MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
|
|
342
|
-
h(NuxtLink, {
|
|
343
|
-
to: node.attrs?.href,
|
|
344
|
-
target: node.attrs?.target,
|
|
345
|
-
}, node.text),
|
|
346
|
-
// Custom code block component example:
|
|
347
|
-
[BlockTypes.CODE_BLOCK]: (node: Node) =>
|
|
348
|
-
h(CodeBlock, {
|
|
349
|
-
class: node?.attrs?.class,
|
|
350
|
-
}, node.children)
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
const root = () => render(blok.articleContent);
|
|
355
|
-
</script>
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## 3. Working with preview and/or production environments
|
|
359
|
-
|
|
360
|
-
Remember that the bridge only works using `version: 'draft'` and the _Preview Access Token_.
|
|
361
|
-
|
|
362
|
-
For the production site, NOT used as a preview for content editors, `version: 'published'` and _Public Access Token_ should be used.
|
|
363
|
-
|
|
364
|
-
> **Note**
|
|
365
|
-
> If you're using production as a preview for marketeers and your public site, you will need a plugin to handle different .env variables, or versions using the _Preview Access Token_, checking if you are inside Storyblok or not. For example, something like `if (window.location.search.includes(_storyblok_tk[token]=<YOUR_TOKEN>)`.
|
|
366
|
-
|
|
367
|
-
Check the official docs on how to [access different content versions](https://www.storyblok.com/docs/guide/essentials/accessing-data#content-versions).
|
|
368
|
-
|
|
369
|
-
The recommended way to handle different content versions with Nuxt is by using environment variables in combination with [Nuxt runtime config](https://nuxt.com/docs/guide/going-further/runtime-config) to expose configuration and secrets within your application
|
|
370
|
-
|
|
371
|
-
In your `nuxt.config.ts`:
|
|
372
|
-
|
|
373
|
-
```ts
|
|
374
|
-
export default defineNuxtConfig({
|
|
375
|
-
runtimeConfig: {
|
|
376
|
-
public: {
|
|
377
|
-
storyblokVersion: process.env.STORYBLOK_VERSION || 'published'
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
Then you can access the runtime config in your components:
|
|
384
|
-
|
|
385
|
-
```ts
|
|
386
|
-
const config = useRuntimeConfig();
|
|
387
|
-
|
|
388
|
-
const story = await useAsyncStoryblok(
|
|
389
|
-
'blog',
|
|
390
|
-
{
|
|
391
|
-
version: config.public.storyblokVersion,
|
|
392
|
-
resolve_relations: 'overview.featured_story'
|
|
393
|
-
},
|
|
394
|
-
{ resolveRelations: 'overview.featured_story' }
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
// or
|
|
398
|
-
|
|
399
|
-
const { data: articles } = await storyblokApi.get('cdn/stories', {
|
|
400
|
-
version: config.public.storyblokVersion,
|
|
401
|
-
starts_with: 'blog',
|
|
402
|
-
is_startpage: false
|
|
403
|
-
});
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
## API
|
|
407
|
-
|
|
408
|
-
### useAsyncStoryblok(slug, apiOptions, bridgeOptions)
|
|
47
|
+
## Contributing
|
|
409
48
|
|
|
410
|
-
|
|
49
|
+
If you'd like to contribute, please refer to the [contributing guidelines](CONTRIBUTING.md).
|
|
411
50
|
|
|
412
|
-
|
|
51
|
+
## Community
|
|
413
52
|
|
|
414
|
-
|
|
53
|
+
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
|
|
415
54
|
|
|
416
|
-
|
|
55
|
+
- [Discuss Storyblok on Github Discussions](https://github.com/storyblok/monoblok/discussions)
|
|
417
56
|
|
|
418
|
-
|
|
57
|
+
For community support, chatting with other users, please visit:
|
|
419
58
|
|
|
420
|
-
|
|
59
|
+
- [Discuss Storyblok on Discord](https://storyblok.com/join-discord)
|
|
421
60
|
|
|
422
|
-
|
|
61
|
+
## Support
|
|
423
62
|
|
|
424
|
-
|
|
63
|
+
For bugs or feature requests, please [submit an issue](https://github.com/storyblok/monoblok/issues/new/choose).
|
|
425
64
|
|
|
426
|
-
|
|
65
|
+
> [!IMPORTANT]
|
|
66
|
+
> Please search existing issues before submitting a new one. Issues without a minimal reproducible example will be closed. [Why reproductions are Required](https://antfu.me/posts/why-reproductions-are-required).
|
|
427
67
|
|
|
428
|
-
|
|
68
|
+
### I can't share my company project code
|
|
429
69
|
|
|
430
|
-
|
|
70
|
+
We understand that you might not be able to share your company's project code. Please provide a minimal reproducible example that demonstrates the issue by using tools like [Stackblitz](https://stackblitz.com) or a link to a Github Repo lease make sure you include a README file with the instructions to build and run the project, important not to include any access token, password or personal information of any kind.
|
|
431
71
|
|
|
432
|
-
|
|
72
|
+
### Feedback
|
|
433
73
|
|
|
434
|
-
|
|
435
|
-
- [API Documentation](https://www.storyblok.com/docs/api?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt)
|
|
436
|
-
- [Developer Tutorials](https://www.storyblok.com/tutorials?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt)
|
|
437
|
-
- [Developer Guides](https://www.storyblok.com/docs/guide/introduction?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt)
|
|
438
|
-
- [FAQs](https://www.storyblok.com/faqs?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt)
|
|
74
|
+
If you have a question, please ask in the [Discuss Storyblok on Discord](https://storyblok.com/join-discord) channel.
|
|
439
75
|
|
|
440
|
-
## Support
|
|
441
76
|
|
|
442
|
-
|
|
443
|
-
- Do you have questions about Storyblok or you need help? [Join our Discord Community](https://storyblok.com/join-discord).
|
|
444
|
-
|
|
445
|
-
## Contributing
|
|
77
|
+
## License
|
|
446
78
|
|
|
447
|
-
|
|
448
|
-
This project use [semantic-release](https://semantic-release.gitbook.io/semantic-release/) for generate new versions by using commit messages and we use the Angular Convention to naming the commits. Check [this question](https://semantic-release.gitbook.io/semantic-release/support/faq#how-can-i-change-the-type-of-commits-that-trigger-a-release) about it in semantic-release FAQ.
|
|
79
|
+
[License](/LICENSE)
|
package/dist/module.d.mts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { AsyncDataOptions, AsyncData, NuxtError } from 'nuxt/app';
|
|
3
|
+
import { ISbResult, ISbStoriesParams, StoryblokBridgeConfigV2 } from '@storyblok/vue';
|
|
4
|
+
import { ComputedRef } from 'vue';
|
|
2
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Options for the useAsyncStoryblok composable.
|
|
8
|
+
* Extends Nuxt's AsyncDataOptions with Storyblok-specific configuration.
|
|
9
|
+
*/
|
|
10
|
+
interface UseAsyncStoryblokOptions extends AsyncDataOptions<ISbResult> {
|
|
11
|
+
/** Storyblok API parameters for fetching stories */
|
|
12
|
+
api: ISbStoriesParams;
|
|
13
|
+
/** Storyblok Bridge configuration for live preview */
|
|
14
|
+
bridge: StoryblokBridgeConfigV2;
|
|
15
|
+
}
|
|
16
|
+
interface UseAsyncStoryblokResult extends AsyncData<ISbResult, NuxtError<unknown>> {
|
|
17
|
+
story: ComputedRef<ISbResult['data']['story']>;
|
|
18
|
+
}
|
|
3
19
|
interface ModuleOptions {
|
|
4
20
|
accessToken: string;
|
|
5
21
|
enableSudoMode: boolean;
|
|
@@ -9,7 +25,8 @@ interface ModuleOptions {
|
|
|
9
25
|
apiOptions: any;
|
|
10
26
|
componentsDir: string;
|
|
11
27
|
}
|
|
28
|
+
|
|
12
29
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
13
30
|
|
|
14
31
|
export { _default as default };
|
|
15
|
-
export type { ModuleOptions };
|
|
32
|
+
export type { ModuleOptions, UseAsyncStoryblokOptions, UseAsyncStoryblokResult };
|
package/dist/module.d.ts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { AsyncDataOptions, AsyncData, NuxtError } from 'nuxt/app';
|
|
3
|
+
import { ISbResult, ISbStoriesParams, StoryblokBridgeConfigV2 } from '@storyblok/vue';
|
|
4
|
+
import { ComputedRef } from 'vue';
|
|
2
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Options for the useAsyncStoryblok composable.
|
|
8
|
+
* Extends Nuxt's AsyncDataOptions with Storyblok-specific configuration.
|
|
9
|
+
*/
|
|
10
|
+
interface UseAsyncStoryblokOptions extends AsyncDataOptions<ISbResult> {
|
|
11
|
+
/** Storyblok API parameters for fetching stories */
|
|
12
|
+
api: ISbStoriesParams;
|
|
13
|
+
/** Storyblok Bridge configuration for live preview */
|
|
14
|
+
bridge: StoryblokBridgeConfigV2;
|
|
15
|
+
}
|
|
16
|
+
interface UseAsyncStoryblokResult extends AsyncData<ISbResult, NuxtError<unknown>> {
|
|
17
|
+
story: ComputedRef<ISbResult['data']['story']>;
|
|
18
|
+
}
|
|
3
19
|
interface ModuleOptions {
|
|
4
20
|
accessToken: string;
|
|
5
21
|
enableSudoMode: boolean;
|
|
@@ -9,7 +25,8 @@ interface ModuleOptions {
|
|
|
9
25
|
apiOptions: any;
|
|
10
26
|
componentsDir: string;
|
|
11
27
|
}
|
|
28
|
+
|
|
12
29
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
13
30
|
|
|
14
31
|
export { _default as default };
|
|
15
|
-
export type { ModuleOptions };
|
|
32
|
+
export type { ModuleOptions, UseAsyncStoryblokOptions, UseAsyncStoryblokResult };
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, addComponentsDir, addPlugin, addImports
|
|
1
|
+
import { defineNuxtModule, createResolver, addComponentsDir, addImportsDir, addPlugin, addImports } from '@nuxt/kit';
|
|
2
2
|
|
|
3
3
|
const module = defineNuxtModule({
|
|
4
4
|
meta: {
|
|
@@ -29,6 +29,7 @@ const module = defineNuxtModule({
|
|
|
29
29
|
nuxt.options.build.transpile.push(resolver.resolve("./runtime"));
|
|
30
30
|
nuxt.options.build.transpile.push("@storyblok/nuxt");
|
|
31
31
|
nuxt.options.build.transpile.push("@storyblok/vue");
|
|
32
|
+
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
32
33
|
nuxt.options.runtimeConfig.public.storyblok = options;
|
|
33
34
|
const enablePluginCondition = options.usePlugin === true && options.enableSudoMode === false;
|
|
34
35
|
if (enablePluginCondition) {
|
|
@@ -57,7 +58,6 @@ const module = defineNuxtModule({
|
|
|
57
58
|
addImports({ name, as: name, from: "@storyblok/vue" });
|
|
58
59
|
}
|
|
59
60
|
nuxt.options.typescript.hoist.push("@storyblok/vue");
|
|
60
|
-
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
61
61
|
if (options.devtools) {
|
|
62
62
|
nuxt.hook("devtools:customTabs", (iframeTabs) => {
|
|
63
63
|
iframeTabs.push({
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type ISbResult, type ISbStoriesParams, type StoryblokBridgeConfigV2 } from '@storyblok/vue';
|
|
2
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
3
|
+
import type { AsyncDataOptions, NuxtError } from '#app';
|
|
4
|
+
import type { DedupeOption } from 'nuxt/app/defaults';
|
|
5
|
+
/**
|
|
6
|
+
* Options for the useAsyncStoryblok composable.
|
|
7
|
+
* Extends Nuxt's AsyncDataOptions with Storyblok-specific configuration.
|
|
8
|
+
*/
|
|
9
|
+
export interface UseAsyncStoryblokOptions extends AsyncDataOptions<ISbResult> {
|
|
10
|
+
/** Storyblok API parameters for fetching stories */
|
|
11
|
+
api: ISbStoriesParams;
|
|
12
|
+
/** Storyblok Bridge configuration for live preview */
|
|
13
|
+
bridge: StoryblokBridgeConfigV2;
|
|
14
|
+
}
|
|
15
|
+
interface AsyncDataExecuteOptions {
|
|
16
|
+
dedupe?: DedupeOption;
|
|
17
|
+
cause?: 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch';
|
|
18
|
+
}
|
|
19
|
+
export interface UseAsyncStoryblokResult {
|
|
20
|
+
story: ComputedRef<ISbResult['data']['story']>;
|
|
21
|
+
data: Ref<ISbResult>;
|
|
22
|
+
pending: Ref<boolean>;
|
|
23
|
+
error: Ref<NuxtError<unknown> | null>;
|
|
24
|
+
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>;
|
|
25
|
+
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>;
|
|
26
|
+
clear: () => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Composable for fetching Storyblok stories with async data handling and live preview support.
|
|
30
|
+
*
|
|
31
|
+
* This composable combines Nuxt's useAsyncData with Storyblok's bridge functionality to provide:
|
|
32
|
+
* - Async data fetching with loading and error states
|
|
33
|
+
* - Automatic caching based on URL and API parameters
|
|
34
|
+
* - Live preview updates when editing in Storyblok
|
|
35
|
+
* - SSR/SSG compatibility
|
|
36
|
+
*
|
|
37
|
+
* @param url - The story URL path (e.g., 'home', 'blog/my-post')
|
|
38
|
+
* @param options - Configuration options for AsyncData, API calls and bridge setup
|
|
39
|
+
* @returns An object containing the async data result with additional story computed property
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```vue
|
|
43
|
+
* <script setup>
|
|
44
|
+
* const { data, pending, error, story } = await useAsyncStoryblok('home', {
|
|
45
|
+
* api: {
|
|
46
|
+
* version: 'published', // or 'draft' for preview
|
|
47
|
+
* cv: Date.now()
|
|
48
|
+
* },
|
|
49
|
+
* bridge: {
|
|
50
|
+
* resolveRelations: ['featured-posts.posts', 'featured-posts.authors'],
|
|
51
|
+
* resolveLinks: 'url'
|
|
52
|
+
* }
|
|
53
|
+
* })
|
|
54
|
+
* </script>
|
|
55
|
+
*
|
|
56
|
+
* <template>
|
|
57
|
+
* <div v-if="pending">Loading...</div>
|
|
58
|
+
* <div v-else-if="error">Error: {{ error.message }}</div>
|
|
59
|
+
* <div v-else>
|
|
60
|
+
* <h1>{{ story?.content?.title }}</h1>
|
|
61
|
+
* <div v-html="story?.content?.body"></div>
|
|
62
|
+
* </div>
|
|
63
|
+
* </template>
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
*/
|
|
67
|
+
export declare function useAsyncStoryblok(url: string, options: UseAsyncStoryblokOptions): Promise<UseAsyncStoryblokResult>;
|
|
68
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useStoryblokApi, useStoryblokBridge } from "@storyblok/vue";
|
|
2
|
-
import { computed,
|
|
2
|
+
import { computed, watch } from "vue";
|
|
3
|
+
import { useAsyncData } from "#app";
|
|
3
4
|
const stableStringify = (obj) => {
|
|
4
5
|
const sortedKeys = Object.keys(obj).sort();
|
|
5
6
|
const sortedObj = sortedKeys.reduce((acc, key) => {
|
|
@@ -8,7 +9,7 @@ const stableStringify = (obj) => {
|
|
|
8
9
|
}, {});
|
|
9
10
|
return JSON.stringify(sortedObj);
|
|
10
11
|
};
|
|
11
|
-
export
|
|
12
|
+
export async function useAsyncStoryblok(url, options) {
|
|
12
13
|
const storyblokApiInstance = useStoryblokApi();
|
|
13
14
|
const { api, bridge, ...rest } = options;
|
|
14
15
|
const uniqueKey = `${stableStringify(api)}${url}`;
|
|
@@ -25,7 +26,13 @@ export const useAsyncStoryblok = async (url, options) => {
|
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
return {
|
|
28
|
-
|
|
29
|
+
data: result.data,
|
|
30
|
+
pending: result.pending,
|
|
31
|
+
error: result.error,
|
|
32
|
+
refresh: result.refresh,
|
|
33
|
+
execute: result.execute,
|
|
34
|
+
clear: result.clear,
|
|
29
35
|
story: computed(() => result.data.value?.data.story)
|
|
30
36
|
};
|
|
31
|
-
}
|
|
37
|
+
}
|
|
38
|
+
;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyblok/nuxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "8.0.
|
|
4
|
+
"version": "8.0.3",
|
|
5
5
|
"description": "Storyblok Nuxt module",
|
|
6
6
|
"homepage": "https://github.com/storyblok/monoblok/tree/main/packages/nuxt#readme",
|
|
7
7
|
"repository": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dist"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@storyblok/vue": "9.2.
|
|
28
|
+
"@storyblok/vue": "9.2.3"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@cypress/vite-dev-server": "^6.0.3",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build": "nuxt-module-build prepare && nuxt-module-build build",
|
|
69
|
-
"dev": "nuxi dev playground
|
|
69
|
+
"dev": "nuxi dev playground",
|
|
70
70
|
"dev:build": "nuxi build playground",
|
|
71
71
|
"dev:preview": "nuxi preview playground",
|
|
72
72
|
"prepare:playground": "nuxi prepare playground",
|