@storyblok/nuxt 2.0.4 → 3.0.0-beta.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 CHANGED
@@ -13,7 +13,7 @@
13
13
  <a href="https://npmjs.com/package/@storyblok/nuxt" rel="nofollow">
14
14
  <img src="https://img.shields.io/npm/dt/@storyblok/nuxt.svg?style=flat-square" alt="npm">
15
15
  </a>
16
- </p>
16
+ </p>
17
17
 
18
18
  <p align="center">
19
19
  <a href="https://discord.gg/jKrbAMz">
@@ -27,37 +27,45 @@
27
27
  </a>
28
28
  </p>
29
29
 
30
- **Note**: This plugin is for Nuxt 2. [Check out the @next version for Nuxt 3](https://github.com/storyblok/storyblok-nuxt/tree/next)
30
+ **Note**: This plugin is for Nuxt 3. [Check out the docs for Nuxt 2 version](https://github.com/storyblok/storyblok-nuxt/tree/master)
31
31
 
32
32
  ## 🚀 Usage
33
33
 
34
- > If you are first-time user of the Storyblok, read the [Getting Started](https://www.storyblok.com/docs/guide/getting-started?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt) guide to get a project ready in less than 5 minutes.
34
+ > If you are first-time user of the Storyblok, read the [Getting Started](https://www.storyblok.com/docs/guide/getting-started?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-vue) guide to get a project ready in less than 5 minutes.
35
35
 
36
36
  ### Installation
37
37
 
38
- Install `@storyblok/nuxt` and `axios` as its peer dependency:
38
+ Install `@storyblok/nuxt@next` and `axios` as its peer dependency:
39
39
 
40
40
  ```bash
41
- npm install --save-dev @storyblok/nuxt axios
42
- # yarn add -D @storyblok/nuxt axios
41
+ npm install --save-dev @storyblok/nuxt@next axios
42
+ # yarn add -D @storyblok/nuxt@next axios
43
43
  ```
44
44
 
45
- > _Hint: You don't have to install Axios if you already installed Axios module of Nuxt._
46
-
47
45
  Add following code to modules section of `nuxt.config.js` and replace the accessToken with API token from Storyblok space.
48
46
 
49
47
  ```js
50
- {
48
+ import { defineNuxtConfig } from "nuxt3";
49
+
50
+ export default defineNuxtConfig({
51
51
  modules: [
52
- [
53
- "@storyblok/nuxt",
54
- {
55
- accessToken: "YOUR_PREVIEW_TOKEN",
56
- cacheProvider: "memory",
57
- },
58
- ],
59
- ];
60
- }
52
+ ["@storyblok/nuxt", { accessToken: "YOUR_ACCESS_TOKEN" }],
53
+ // ...
54
+ ],
55
+ });
56
+ ```
57
+
58
+ You can also use the `storyblok` config if you prefer:
59
+
60
+ ```js
61
+ import { defineNuxtConfig } from "nuxt3";
62
+
63
+ export default defineNuxtConfig({
64
+ modules: ["@storyblok/nuxt"],
65
+ storyblok: {
66
+ accessToken: "YOUR_ACCESS_TOKEN",
67
+ },
68
+ });
61
69
  ```
62
70
 
63
71
  ### Getting started
@@ -65,9 +73,60 @@ Add following code to modules section of `nuxt.config.js` and replace the access
65
73
  This module adds two objects to the the Nuxt.js context.
66
74
 
67
75
  1. $storyapi: The [Storyblok API client](https://github.com/storyblok/storyblok-nuxt).
68
- 2. $storybridge: A loader for the [Storyblok JS bridge](https://www.storyblok.com/docs/Guides/storyblok-latest-js?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt) that is responsible for adding the editing interface to your website.
76
+ 2. $storybridge: A loader for the [Storyblok JS bridge](https://www.storyblok.com/docs/Guides/storyblok-latest-js) that is responsible for adding the editing interface to your website.
69
77
 
70
- Example of fetching data of the homepage and listening to the change events of the JS bridge:
78
+ ### Examples
79
+
80
+ #### Fetching data
81
+
82
+ Use `useStoryApi` composable, auto-imported when using `<script setup>`:
83
+
84
+ ```html
85
+ <template>
86
+ <div>
87
+ <p v-for="story in stories" :key="story.id">{{ story.name }}</p>
88
+ </div>
89
+ </template>
90
+
91
+ <script setup>
92
+ const storyapi = useStoryApi();
93
+ const { data } = await storyapi.get("cdn/stories", { version: "draft" });
94
+ </script>
95
+ ```
96
+
97
+ If you need to import them manually, do it from `composables`:
98
+
99
+ ```js
100
+ import { useStoryApi, useStoryBridge } from "@storyblok/nuxt/composables";
101
+ ```
102
+
103
+ #### Listen to Storyblok editor events
104
+
105
+ Use `useStoryBridge`. You need to pass the story id as first param, and a callback function as second param to update the new story:
106
+
107
+ ```html
108
+ <script setup>
109
+ const storyapi = useStoryApi();
110
+ const { data } = await storyapi.get("cdn/stories/home", { version: "draft" });
111
+ const state = reactive({ stories: data.story });
112
+
113
+ onMounted(() => {
114
+ useStoryBridge(state.story.id, story => (state.story = story));
115
+ });
116
+ </script>
117
+ ```
118
+
119
+ You can pass [Bridge options](https://www.storyblok.com/docs/Guides/storyblok-latest-js?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt) as a third parameter as well:
120
+
121
+ ```js
122
+ useStoryBridge(state.story.id, (story) => (state.story = story), {
123
+ resolveRelations: ["Article.author"],
124
+ });
125
+ ```
126
+
127
+ ### Options API
128
+
129
+ Traditional Option API is used just like in [version 2](/../../):
71
130
 
72
131
  ```js
73
132
  export default {
@@ -127,73 +186,23 @@ export default {
127
186
 
128
187
  ### API
129
188
 
130
- Like described above, this package includes two objects into Nuxt.js context:
189
+ Like described above, this package includes two composablestwo objects into Nuxt.js context:
131
190
 
132
- #### $storyapi
133
-
134
- This object is a instance of StoryblokClient. You can check the documentation about StoryblokClient in the repository: https://github.com/storyblok/storyblok-nuxt
135
-
136
- #### $storybridge(successCallback, errorCallback)
137
-
138
- You can use this object to load the [Storyblok JS Bridge](https://www.storyblok.com/docs/Guides/storyblok-latest-js?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt). In the success callback you will it have available in the window variable StoryblokBridge.
191
+ #### useStoryApi()
139
192
 
140
- ### Migrate from 1.x to 2.x
193
+ It's basically a convenient way to access `$storyapi`
141
194
 
142
- #### Listening to Visual Editor events in 1.x
195
+ #### useStoryBridge(storyId, callback, bridgeOptions)
143
196
 
144
- Most of our tutorials and recordings still using following deprecated approach for real-time editing and listening to Storyblok's Visual Editor events. **This approach can be used only with 1.x version of the storyblok-nuxt.**
197
+ Use this one-line composable to cover the most common use case: updating the story when any kind of change happens on Storyblok side. It's the equivalent to the [Options API code you've seen above](/../../tree/next#options-api).
145
198
 
146
- ```js
147
- export default {
148
- mounted() {
149
- // Use the input event for instant update of content
150
- this.$storybridge.on("input", (event) => {
151
- if (event.story.id === this.story.id) {
152
- this.story.content = event.story.content;
153
- }
154
- });
155
- // Use the bridge to listen the events
156
- this.$storybridge.on(["published", "change"], (event) => {
157
- this.$nuxt.$router.go({
158
- path: this.$nuxt.$router.currentRoute,
159
- force: true,
160
- });
161
- });
162
- },
163
- };
164
- ```
165
-
166
- #### Listening to Visual Editor events in 2.x
199
+ #### $storyapi
167
200
 
168
- The recommended approach for 2.x storyblok-nuxt plugin.
201
+ This object is a instance of StoryblokClient. You can check the documentation about StoryblokClient in the repository: https://github.com/storyblok/storyblok-nuxt
169
202
 
170
- ```js
171
- export default {
172
- mounted() {
173
- this.$storybridge(
174
- () => {
175
- const storyblokInstance = new StoryblokBridge();
203
+ #### $storybridge(successCallback, errorCallback)
176
204
 
177
- storyblokInstance.on(["input", "published", "change"], (event) => {
178
- if (event.action == "input") {
179
- if (event.story.id === this.story.id) {
180
- this.story.content = event.story.content;
181
- }
182
- } else {
183
- this.$nuxt.$router.go({
184
- path: this.$nuxt.$router.currentRoute,
185
- force: true,
186
- });
187
- }
188
- });
189
- },
190
- (error) => {
191
- console.error(error);
192
- }
193
- );
194
- },
195
- };
196
- ```
205
+ You can use this object to load the [Storyblok JS Bridge](https://www.storyblok.com/docs/Guides/storyblok-latest-js?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt). In the success callback you will it have available in the window variable StoryblokBridge.
197
206
 
198
207
  ## 🔗 Related Links
199
208
 
@@ -206,6 +215,7 @@ export default {
206
215
  ### Support
207
216
 
208
217
  - Bugs or Feature Requests? [Submit an issue](/../../issues/new);
218
+
209
219
  - Do you have questions about Storyblok or you need help? [Join our Discord Community](https://discord.gg/jKrbAMz).
210
220
 
211
221
  ### Contributing
@@ -0,0 +1 @@
1
+ (function(e,r){typeof exports=="object"&&typeof module!="undefined"?r(exports,require("#app"),require("vue-router")):typeof define=="function"&&define.amd?define(["exports","#app","vue-router"],r):(e=typeof globalThis!="undefined"?globalThis:e||self,r(e.composables={},e._app,e.VueRouter))})(this,function(e,r,n){"use strict";var s=(t,d,f={})=>{if(typeof window=="undefined")return;const c=r.useNuxtApp(),u=n.useRouter();c.$storybridge(()=>{new window.StoryblokBridge(f).on(["input","published","change"],o=>{o.action=="input"&&o.story.id===t?d(o.story):u.go({path:u.currentRoute,force:!0})})},i=>{console.error(i)})},p=()=>r.useNuxtApp().$storyapi;e.useStoryApi=p,e.useStoryBridge=s,Object.defineProperty(e,"__esModule",{value:!0}),e[Symbol.toStringTag]="Module"});
@@ -0,0 +1,24 @@
1
+ import { useNuxtApp } from "#app";
2
+ import { useRouter } from "vue-router";
3
+ var useStoryBridge = (id, cb, options = {}) => {
4
+ if (typeof window === "undefined")
5
+ return;
6
+ const app = useNuxtApp();
7
+ const router = useRouter();
8
+ app.$storybridge(() => {
9
+ const sbBridge = new window.StoryblokBridge(options);
10
+ sbBridge.on(["input", "published", "change"], (event) => {
11
+ if (event.action == "input" && event.story.id === id)
12
+ cb(event.story);
13
+ else
14
+ router.go({ path: router.currentRoute, force: true });
15
+ });
16
+ }, (error) => {
17
+ console.error(error);
18
+ });
19
+ };
20
+ var useStoryApi = () => {
21
+ const app = useNuxtApp();
22
+ return app.$storyapi;
23
+ };
24
+ export { useStoryApi, useStoryBridge };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@storyblok/nuxt-composables",
3
+ "version": "0.0.0",
4
+ "main": "./dist/composables.js",
5
+ "module": "./dist/composables.mjs",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/composables.mjs",
9
+ "require": "./dist/composables.js"
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,2 @@
1
+ export { default as useStoryBridge } from "./useStoryBridge";
2
+ export { default as useStoryApi } from "./useStoryApi";
@@ -0,0 +1,6 @@
1
+ import { useNuxtApp } from "#app";
2
+
3
+ export default () => {
4
+ const app = useNuxtApp();
5
+ return app.$storyapi;
6
+ };
@@ -0,0 +1,22 @@
1
+ import { useNuxtApp } from "#app";
2
+ import { useRouter } from "vue-router";
3
+
4
+ export default (id, cb, options = {}) => {
5
+ if (typeof window === "undefined") return;
6
+ const app = useNuxtApp();
7
+ const router = useRouter();
8
+
9
+ app.$storybridge(
10
+ () => {
11
+ const sbBridge = new window.StoryblokBridge(options);
12
+
13
+ sbBridge.on(["input", "published", "change"], (event) => {
14
+ if (event.action == "input" && event.story.id === id) cb(event.story);
15
+ else router.go({ path: router.currentRoute, force: true });
16
+ });
17
+ },
18
+ (error) => {
19
+ console.error(error);
20
+ }
21
+ );
22
+ };
package/module.js CHANGED
@@ -1,12 +1,57 @@
1
- const path = require("path");
1
+ import path from "path"
2
+ import { defineNuxtModule, addPluginTemplate } from "@nuxt/kit"
2
3
 
3
- module.exports = function nuxtStoryblok(moduleOptions) {
4
- let options = Object.assign({}, this.options.storyblok, moduleOptions);
4
+ export const noopTransform = () => {
5
+ return {
6
+ props: [],
7
+ needRuntime: true,
8
+ }
9
+ }
5
10
 
6
- this.addPlugin({
7
- src: path.resolve(__dirname, "templates/plugin.js"),
8
- options,
9
- });
10
- };
11
+ export default defineNuxtModule({
12
+ name: "@storyblok/nuxt",
13
+ configKey: "storyblok",
14
+ defaults: {},
15
+ setup(options, nuxt) {
16
+ addPluginTemplate({
17
+ src: path.resolve(__dirname, "templates/plugin.js"),
18
+ options,
19
+ })
11
20
 
12
- module.exports.meta = require("./package.json");
21
+ nuxt.options.build.transpile.push(
22
+ path.resolve(__dirname, "composables/dist")
23
+ )
24
+ },
25
+ // We need to add the v-editable SSR impl or it will crash
26
+ // info here: https://github.com/vuejs/vue-next/issues/3298
27
+ hooks: {
28
+ "build:before": ({ nuxt }, config) => {
29
+ // If it's using Webpack
30
+ const isWebpack = nuxt.options.vite === false
31
+ const isProduction = nuxt.options.dev === false
32
+ if (isWebpack || (!isWebpack && isProduction)) {
33
+ config.transpile = [
34
+ ...(config.transpile || []),
35
+ "@storyblok/vue",
36
+ "storyblok-js-client",
37
+ ]
38
+ }
39
+
40
+ const opts = config.loaders.vue.compilerOptions
41
+ const transforms = opts.directiveTransforms || {}
42
+ opts.directiveTransforms = { ...transforms, editable: noopTransform }
43
+ },
44
+ "autoImports:extend": (autoimports) => {
45
+ autoimports.push({
46
+ from: "@storyblok/nuxt/composables",
47
+ name: "useStoryBridge",
48
+ as: "useStoryBridge",
49
+ })
50
+ autoimports.push({
51
+ from: "@storyblok/nuxt/composables",
52
+ name: "useStoryApi",
53
+ as: "useStoryApi",
54
+ })
55
+ },
56
+ },
57
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storyblok/nuxt",
3
- "version": "2.0.4",
3
+ "version": "3.0.0-beta.3",
4
4
  "description": "Storyblok Nuxt.js module",
5
5
  "license": "MIT",
6
6
  "contributors": [
@@ -11,20 +11,24 @@
11
11
  "main": "./module.js",
12
12
  "repository": "https://github.com/storyblok/storyblok-nuxt",
13
13
  "scripts": {
14
+ "build": "vite build",
15
+ "test": "npm run test:unit && npm run test:e2e",
16
+ "test:unit": "jest __tests__",
14
17
  "cy:open": "cypress open",
15
18
  "cy:run": "cypress run",
16
19
  "playground:run": "cd ../playground && npm run start",
17
20
  "pretest:e2e": "cd ../playground && npm run build",
18
21
  "test:e2e": "start-server-and-test playground:run http://localhost:3000 cy:run",
19
22
  "test:e2e-watch": "start-server-and-test playground:run http://localhost:3000 cy:open",
20
- "prepublishOnly": "cp ../README.md ./"
23
+ "prepublishOnly": "npm run build && cp ../README.md ./"
21
24
  },
22
25
  "files": [
23
26
  "module.js",
24
- "templates"
27
+ "templates",
28
+ "composables"
25
29
  ],
26
30
  "dependencies": {
27
- "@storyblok/vue": "^2.0.0",
31
+ "@storyblok/vue": "^3.0.0",
28
32
  "storyblok-js-client": "^4.1.5"
29
33
  },
30
34
  "devDependencies": {
@@ -33,11 +37,22 @@
33
37
  "cypress": "^8.3.0",
34
38
  "eslint-plugin-cypress": "^2.12.1",
35
39
  "jest": "^26.6.3",
36
- "start-server-and-test": "^1.14.0"
40
+ "start-server-and-test": "^1.14.0",
41
+ "vite": "^2.7.6"
37
42
  },
38
43
  "eslintConfig": {
39
44
  "env": {
40
45
  "node": true
41
46
  }
47
+ },
48
+ "release": {
49
+ "branches": [
50
+ "master",
51
+ {
52
+ "name": "next",
53
+ "channel": "next",
54
+ "prerelease": "beta"
55
+ }
56
+ ]
42
57
  }
43
58
  }
@@ -1,82 +1,67 @@
1
- import Vue from 'vue'
2
- import StoryblokClient from 'storyblok-js-client'
3
- import StoryblokVue from '@storyblok/vue'
1
+ import StoryblokVue from "@storyblok/vue";
2
+ import StoryblokClient from 'storyblok-js-client/source'
3
+ import { defineNuxtPlugin } from '#app'
4
4
 
5
- const loadScript = function(src, cb) {
6
- if (document.getElementById('storyblok-javascript-bridge')) {
7
- return cb()
5
+ const loadScript = (src, cb) => {
6
+ if (document.getElementById("storyblok-javascript-bridge")) {
7
+ return cb();
8
8
  }
9
9
 
10
- var script = document.createElement('script')
11
- script.async = true
12
- script.src = src
13
- script.id = 'storyblok-javascript-bridge'
10
+ const script = document.createElement("script");
11
+ script.async = true;
12
+ script.src = src;
13
+ script.id = "storyblok-javascript-bridge";
14
14
 
15
- script.onerror = function() {
16
- cb(new Error('Failed to load' + src))
17
- }
18
-
19
- script.onload = function() {
20
- cb()
21
- }
15
+ script.onerror = function () {
16
+ cb(new Error("Failed to load" + src));
17
+ };
22
18
 
23
- document.getElementsByTagName('head')[0].appendChild(script)
24
- }
19
+ script.onload = function () {
20
+ cb();
21
+ };
25
22
 
26
- let doLoadScript = true
23
+ document.getElementsByTagName("head")[0].appendChild(script);
24
+ };
27
25
 
28
- const Client = {
29
- install () {
30
- if (!Vue.prototype.$storyapi) {
31
- Vue.prototype.$storyapi = new StoryblokClient({
32
- accessToken: '<%= options.accessToken %>',
33
- cache: {
34
- clear: 'auto',
35
- type: '<%= options.cacheProvider || 'memory' %>'
36
- },
37
- timeout: <%= options.timeout || 0 %><% if (options.region) { %>,
38
- region: '<%= options.region %>'<% } %><% if (typeof options.https !== 'undefined') { %>,
39
- https: <%= options.https %><% } %>
40
- }<% if (typeof options.endpoint !== 'undefined') { %>, '<%= options.endpoint %>'<% } %>)
26
+ let doLoadScript = true;
41
27
 
42
- Vue.prototype.$storybridge = function(cb, errorCb) {
43
- if (typeof errorCb !== 'function') {
44
- errorCb = function() {}
45
- }
46
-
47
- if (window.location == window.parent.location) {
48
- errorCb('You are not in the edit mode.')
49
- return
50
- }
51
-
52
- if (!doLoadScript) {
53
- if (!window.StoryblokBridge) {
54
- errorCb('The Storyblok bridge script is already loading.')
55
- return
56
- }
57
- cb()
58
- return
59
- }
28
+ const initStoryapi = () => {
29
+ return new StoryblokClient({
30
+ accessToken: '<%= options.accessToken %>',
31
+ cache: {
32
+ clear: 'auto',
33
+ type: '<%= options.cacheProvider || 'memory' %>'
34
+ },
35
+ timeout: <%= options.timeout || 0 %><% if (options.region) { %>,
36
+ region: '<%= options.region %>'<% } %><% if (typeof options.https !== 'undefined') { %>,
37
+ https: <%= options.https %><% } %>
38
+ }<% if (typeof options.endpoint !== 'undefined') { %>, '<%= options.endpoint %>'<% } %>)
39
+ }
60
40
 
61
- doLoadScript = false
62
- loadScript('https://app.storyblok.com/f/storyblok-v2-latest.js', cb)
63
- }
41
+ const storybridge = (cb, errorCb) => {
42
+ if (typeof errorCb !== "function") {
43
+ errorCb = function () {};
44
+ }
45
+ if (window.location == window.parent.location) {
46
+ errorCb("You are not in the edit mode.");
47
+ return;
48
+ }
49
+ if (!doLoadScript) {
50
+ if (!window.StoryblokBridge) {
51
+ errorCb("The Storyblok bridge script is already loading.");
52
+ return;
64
53
  }
54
+ cb();
55
+ return;
65
56
  }
66
- }
67
-
68
- Vue.use(Client)
69
- Vue.use(StoryblokVue)
57
+ doLoadScript = false;
58
+ loadScript("https://app.storyblok.com/f/storyblok-v2-latest.js", cb);
59
+ };
70
60
 
71
- export default (ctx) => {
72
- const { app, store } = ctx
73
61
 
74
- app.$storyapi = Vue.prototype.$storyapi
75
- ctx.$storyapi = Vue.prototype.$storyapi
76
- app.$storybridge = Vue.prototype.$storybridge
77
- ctx.$storybridge = Vue.prototype.$storybridge
78
-
79
- if (store) {
80
- store.$storyapi = Vue.prototype.$storyapi
81
- }
82
- }
62
+ export default defineNuxtPlugin(({vueApp, provide}) => {
63
+ vueApp.use(StoryblokVue);
64
+
65
+ provide("storyapi", initStoryapi());
66
+ provide("storybridge", storybridge);
67
+ })