diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js
index cb589adc89..4a2cc4a5d0 100644
--- a/src/.vuepress/config.js
+++ b/src/.vuepress/config.js
@@ -7,7 +7,8 @@ const sidebar = {
'/cookbook/',
'/cookbook/editable-svg-icons',
'/cookbook/debugging-in-vscode',
- '/cookbook/automatic-global-registration-of-base-components'
+ '/cookbook/automatic-global-registration-of-base-components',
+ '/cookbook/serverless-blog'
]
}
],
diff --git a/src/.vuepress/public/images/buttercms-blog-page-screenshot.png b/src/.vuepress/public/images/buttercms-blog-page-screenshot.png
new file mode 100644
index 0000000000..4b5cdd8d60
Binary files /dev/null and b/src/.vuepress/public/images/buttercms-blog-page-screenshot.png differ
diff --git a/src/.vuepress/public/images/buttercms-post-details-page.png b/src/.vuepress/public/images/buttercms-post-details-page.png
new file mode 100644
index 0000000000..ddcb68a31f
Binary files /dev/null and b/src/.vuepress/public/images/buttercms-post-details-page.png differ
diff --git a/src/cookbook/serverless-blog.md b/src/cookbook/serverless-blog.md
new file mode 100644
index 0000000000..30224fa34d
--- /dev/null
+++ b/src/cookbook/serverless-blog.md
@@ -0,0 +1,350 @@
+# Create a CMS-Powered Blog
+
+So you've just launched your Vue.js website, congrats! Now you want to add a blog that quickly plugs into your website and you don't want to have to spin up a whole server just to host a Wordpress instance (or any DB-powered CMS for that matter). You want to just be able to add a few Vue.js blog components and some routes and have it all just work, right? What you're looking for is a blog that's powered entirely by API's you can consume directly from your Vue.js application. This tutorial will teach you how to do just that, let's dive in!
+
+We're going to quickly build a CMS-powered blog with Vue.js. It uses [ButterCMS](https://buttercms.com/), an API-first CMS that lets you manage content using the ButterCMS dashboard and integrate our content API into your Vue.js app. You can use ButterCMS for new or existing Vue.js projects.
+
+
+
+## Install
+
+Run this in your command line:
+
+```bash
+npm install buttercms --save
+```
+
+Butter can also be loaded using a CDN:
+
+```html
+
+```
+
+## Base Example
+
+::: info
+You can find your api token on the [settings page](https://buttercms.com/settings/)
+:::
+
+Create file `buttercms.js` to create your butter instance using your API token:
+
+```javascript
+var butter = require('buttercms')('your_api_token');
+module.exports = butter
+```
+
+Using ES6:
+
+```javascript
+import Butter from 'buttercms';
+export const butter = Butter('your_api_token');
+```
+
+You could also create your butter instance using CDN:
+
+```html
+
+
+```
+
+Import this file into any component you want to use ButterCMS and add this code snippet to `onMounted`:
+
+```javascript
+butter.post.list({page: 1, page_size: 10}).then(function(response) {
+ console.log(response)
+})
+```
+
+This API request fetches your blog posts. Your account comes with one example post which you'll see in the response.
+
+## Display all posts and post details
+
+To display posts we create a `/blog` route (using Vue Router) in our app and fetch blog posts from the Butter API, as well as a `/blog/:slug` route to handle individual posts.
+
+Update routes in `router/index.js`:
+
+```javascript
+// ...
+import BlogHome from "@/views/BlogHome.vue"
+import BlogPost from "@/views/BlogPost.vue"
+
+const routes = [
+ // ...
+ {
+ component: BlogHome,
+ name: "Blog",
+ path: "/posts",
+ },
+ {
+ component: BlogPost,
+ name: "BlogPost",
+ path: "/posts/:slug",
+ }
+]
+
+// ...
+```
+
+Then create `views/BlogHome.vue` which will be your blog homepage that lists your most recent posts:
+
+```html
+
+
+
Blog
+
+
+
+
+
+
+
+
+
+
+
{{ post.title }}
+
{{ post.summary }}
+
+
+
+
+
+
+
+```
+
+::: info
+See the ButterCMS [API reference](https://buttercms.com/docs/api/?javascript#blog-posts) for additional options such as filtering by category or author. The response also includes some metadata that could be used for pagination.
+:::
+
+Here's what it looks like (note we added styling using [tailwind](https://tailwindcss.com/)):
+
+
+
+Now create `views/BlogPost.vue` which will be your Blog Post page to display post details:
+
+```html
+
+
+
+
+
+```
+
+Here's a preview:
+
+
+
+Now our app is pulling all blog posts and we can navigate to individual posts. However, our next/previous post links are not working.
+
+::: info
+When the user navigates from `/blog/foo` to `/blog/bar`, the same component instance will be reused. Since both routes render the same component, this is more efficient than destroying the old instance and then creating a new one.
+:::
+
+::: warning
+Using the component this way will mean that the lifecycle hooks of the component will not be called. Visit the Vue Router's docs to learn more about [Dynamic Route Matching](https://router.vuejs.org/en/essentials/dynamic-matching.html)
+:::
+
+To fix this we need to watch the `route.params.slug` value and call `getPost()` when it changes.
+
+Update `
+```
+
+Now your app has a working blog that can be updated easily in the [Blog posts ButterCMS dashboard](https://buttercms.com/blog_home/).
+
+## Categories, Tags, and Authors
+
+Use Butter's APIs for categories, tags, and authors to feature and filter content on your blog.
+
+See the ButterCMS API reference for more information about these objects:
+
+* [Categories](https://buttercms.com/docs/api/?javascript#categories)
+* [Tags](https://buttercms.com/docs/api/?javascript#tags)
+* [Authors](https://buttercms.com/docs/api/?javascript#authors)
+
+Here's an example of listing all categories and getting posts by category. Call these methods on the `onMounted` hook inside `setup`:
+
+```javascript
+onMounted( async () => {
+ const categories = await getCategories()
+ const postsByCategory = await getPostsByCategory( "example-category" )
+
+ console.log({ categories, postsByCategory })
+
+ async function getCategories () {
+ return ( await butter.category.list() ).data.data
+ }
+
+ function getPostsByCategory ( category ) {
+ return butter.category.retrieve( category, {
+ include: "recent_posts"
+ })
+ }
+
+ // ...
+
+})
+```
+
+## Alternative Patterns
+
+An alternative pattern to consider, especially if you prefer writing only in Markdown, is using something like [Nuxtent](https://nuxtent-module.netlify.com/guide/writing/#async-components). Nuxtent allows you to use `Vue Component` inside of Markdown files. This approach would be akin to a static site approach (i.e. Jekyll) where you compose your blog posts in Markdown files. Nuxtent adds a nice integration between Vue.js and Markdown allowing you to live in a 100% Vue.js world.
+
+## Wrap up
+
+That's it! You now have a fully functional CMS-powered blog running in your app. We hope this tutorial was helpful and made your development experience with Vue.js even more enjoyable :)
\ No newline at end of file