Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 92 additions & 33 deletions docs/content/en/writing.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,97 @@ Will be transformed into:

We internally add a `text` key with the markdown body that will be used for [searching](/fetching#searchfield-value) or [extending](/advanced#contentfilebeforeinsert) it.

## JSON / JSON5

Data defined will be injected into the document.

> No body will be generated.

### Arrays

<badge>v0.10.0+</badge>

You can now use arrays inside your `.json` files. Objects will be flattened and inserted into the collection. You can [fetch](/fetching) your content in the same way as your used to.

<alert type="warning">

Since the `slug` is by default taken from the path and missing in this case, you have to define it in your objects for this feature to work properly.

</alert>

> Check out our [example](https://github.com/nuxt/content/tree/dev/example) with articles and authors.

### Example

A file `content/home.json`:

```json
{
"title": "Home",
"description": "Welcome!"
}
```

Will be transformed into:

```json
{
"dir": "/",
"slug": "home",
"path": "/home",
"extension": ".json",
"title": "Home",
"description": "Welcome!"
}
```

A file `content/authors.json`:

```json
[
{
"name": "Sébastien Chopin",
"slug": "atinux"
},
{
"name": "Krutie Patel",
"slug": "krutiepatel"
},
{
"name": "Sergey Bedritsky",
"slug": "sergeybedritsky"
}
]
```

Will be transformed into:

```json
[
{
"name": "Sébastien Chopin",
"slug": "atinux",
"dir": "/authors",
"path": "/authors/atinux",
"extension": ".json"
},
{
"name": "Krutie Patel",
"slug": "krutiepatel",
"dir": "/authors",
"path": "/authors/krutiepatel",
"extension": ".json"
},
{
"name": "Sergey Bedritsky",
"slug": "sergeybedritsky",
"dir": "/authors",
"path": "/authors/sergeybedritsky",
"extension": ".json"
}
]
```

## CSV

Rows will be assigned to body variable.
Expand Down Expand Up @@ -503,7 +594,6 @@ Will be transformed into:
}
```


## YAML / YML

Data defined will be injected into the document.
Expand All @@ -530,35 +620,4 @@ Will be transformed into:
"title": "Home",
"description": "Welcome!"
}
```

## JSON / JSON5

Data defined will be injected into the document.

> No body will be generated.

### Example

A file `content/home.json`:

```json
{
"title": "Home",
"description": "Welcome!"
}

```

Will be transformed into:

```json
{
"dir": "/",
"slug": "home",
"path": "/home",
"extension": ".json",
"title": "Home",
"description": "Welcome!"
}
```
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@ description: Let’s build a blazing fast articles and tutorials app using Nuxt,
imgUrl: blog/build-dev-to-clone-with-nuxt-new-fetch/main.png
date: 2020-04-08
authors:
- name: Sergey Bedritsky
avatarUrl: https://pbs.twimg.com/profile_images/1244291720566669315/pGg6Xn-M_400x400.jpg
link: https://twitter.com/sergeybedritsky
- name: Sebastien Chopin
avatarUrl: https://pbs.twimg.com/profile_images/1042510623962275840/1Iw_Mvud_400x400.jpg
link: https://twitter.com/Atinux
- sergeybedritsky
- atinux
tags:
- Nuxt
- Fetch
Expand Down
4 changes: 1 addition & 3 deletions example/content/articles/introducing-smart-prefetching.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ description: "Starting from Nuxt v2.4.0, Nuxt.js will automagically prefetch the
imgUrl: blog/introducing-smart-prefetching/main.png
date: 2019-01-28
authors:
- name: Sébastien Chopin
avatarUrl: https://pbs.twimg.com/profile_images/1042510623962275840/1Iw_Mvud_400x400.jpg
link: https://twitter.com/atinux
- atinux
tags:
- framework
- feature
Expand Down
4 changes: 1 addition & 3 deletions example/content/articles/nuxtjs-from-terminal-to-browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ description: How we changed the developer experience to stop switching between t
imgUrl: blog/nuxtjs-from-terminal-to-browser/main.png
date: 2019-06-04
authors:
- name: Sébastien Chopin
avatarUrl: https://pbs.twimg.com/profile_images/1042510623962275840/1Iw_Mvud_400x400.jpg
link: https://twitter.com/atinux
- atinux
tags:
- webpack
- DX
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ description: Explore different features of the fetch hook and learn a brand new
imgUrl: blog/understanding-how-fetch-works-in-nuxt-2-12/main.png
date: 2020-04-06
authors:
- name: Krutie Patel
avatarUrl: https://pbs.twimg.com/profile_images/780651635932434432/YtbSkumD_400x400.jpg
link: https://twitter.com/KrutiePatel
- krutiepatel
tags:
- Nuxt
- Fetch
Expand Down
20 changes: 20 additions & 0 deletions example/content/authors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[
{
"name": "Sébastien Chopin",
"slug": "atinux",
"avatarUrl": "https://pbs.twimg.com/profile_images/1042510623962275840/1Iw_Mvud_400x400.jpg",
"link": "https://twitter.com/atinux"
},
{
"name": "Krutie Patel",
"slug": "krutiepatel",
"avatarUrl": "https://pbs.twimg.com/profile_images/780651635932434432/YtbSkumD_400x400.jpg",
"link": "https://twitter.com/KrutiePatel"
},
{
"name": "Sergey Bedritsky",
"slug": "sergeybedritsky",
"avatarUrl": "https://pbs.twimg.com/profile_images/1244291720566669315/pGg6Xn-M_400x400.jpg",
"link": "https://twitter.com/sergeybedritsky"
}
]
16 changes: 14 additions & 2 deletions example/pages/articles/_slug.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<div>
<nuxt-link to="/articles">Articles</nuxt-link>
<h2>{{ article.title }}</h2>
<p>{{ article.description }}</p>
<div v-for="author of authors" :key="author.slug">
<img :src="author.avatarUrl" width="50" height="50" />
{{ author.name }}
</div>
<nuxt-content :document="article" />
<nuxt-link
v-if="prev"
Expand All @@ -24,9 +27,11 @@ export default {
article = await $content('articles', params.slug).fetch()
// OR const article = await $content(`articles/${params.slug}`).fetch()
} catch (e) {
error({ message: 'Article not found' })
return error({ message: 'Article not found' })
}

const authors = await $content('authors').where({ slug: { $in: article.authors } }).fetch()

const [prev, next] = await $content('articles')
.only(['title', 'slug'])
.sortBy('date', 'desc')
Expand All @@ -35,9 +40,16 @@ export default {

return {
article,
authors,
prev,
next
}
},
head () {
return {
title: this.article.title,
description: this.article.description
}
}
}
</script>
88 changes: 57 additions & 31 deletions packages/content/lib/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,38 +111,47 @@ class Database extends Hookable {
* @param {string} path - The path of the file.
*/
async insertFile (path) {
const item = await this.parseFile(path)
const items = await this.parseFile(path)

if (!item) {
if (!items) {
return
}

await this.callHook('file:beforeInsert', item)
// Assume path is a directory if returning an array
if (items.length > 1) {
this.dirs.push(this.normalizePath(path))
}

for (const item of items) {
await this.callHook('file:beforeInsert', item)

this.items.insert(item)
this.items.insert(item)
}
}

/**
* Update file in collection
* @param {string} path - The path of the file.
*/
async updateFile (path) {
const item = await this.parseFile(path)
const items = await this.parseFile(path)

if (!item) {
if (!items) {
return
}

await this.callHook('file:beforeInsert', item)
for (const item of items) {
await this.callHook('file:beforeInsert', item)

const document = this.items.findOne({ path: item.path })
const document = this.items.findOne({ path: item.path })

logger.info(`Updated ${path.replace(this.cwd, '.')}`)
if (document) {
this.items.update({ $loki: document.$loki, meta: document.meta, ...item })
return
logger.info(`Updated ${path.replace(this.cwd, '.')}`)
if (document) {
this.items.update({ $loki: document.$loki, meta: document.meta, ...item })
return
}
this.items.insert(item)
}
this.items.insert(item)
}

/**
Expand Down Expand Up @@ -187,37 +196,54 @@ class Database extends Hookable {
'.xml': data => this.xml.toJSON(data),
...this.extendParser
})[extension]

// Collect data from file
let data = {}
let data = []
try {
data = await parser(file.data)
// Force data to be an array
data = Array.isArray(data) ? data : [data]
} catch (err) {
logger.warn(`Could not parse ${path.replace(this.cwd, '.')}:`, err.message)
return null
}

// Normalize path without dir and ext
const normalizedPath = this.normalizePath(path)
// Extract dir from path
const split = normalizedPath.split('/')
const dir = split.slice(0, split.length - 1).join('/')

// Overrides createdAt & updatedAt if it exists in the document
const existingCreatedAt = data.createdAt && new Date(data.createdAt)
const existingUpdatedAt = data.updatedAt && new Date(data.updatedAt)
// validate the existing dates to avoid wrong date format or typo

// Validate the existing dates to avoid wrong date format or typo
const isValidDate = (date) => {
return date instanceof Date && !isNaN(date)
}

return {
...data,
dir: dir || '/',
path: normalizedPath,
extension,
slug: split[split.length - 1],
createdAt: isValidDate(existingCreatedAt) ? existingCreatedAt : stats.birthtime,
updatedAt: isValidDate(existingUpdatedAt) ? existingUpdatedAt : stats.mtime
}
return data.map((item) => {
const paths = normalizedPath.split('/')
// `item.slug` is necessary with JSON arrays since `slug` comes from filename by default
if (data.length > 1 && item.slug) {
paths.push(item.slug)
}
// Extract `dir` from paths
const dir = paths.slice(0, paths.length - 1).join('/') || '/'
// Extract `slug` from paths
const slug = paths[paths.length - 1]
// Construct full path
const path = paths.join('/')

// Overrides createdAt & updatedAt if it exists in the document
const existingCreatedAt = item.createdAt && new Date(item.createdAt)
const existingUpdatedAt = item.updatedAt && new Date(item.updatedAt)

return {
slug,
// Allow slug override
...item,
dir,
path,
extension,
createdAt: isValidDate(existingCreatedAt) ? existingCreatedAt : stats.birthtime,
updatedAt: isValidDate(existingUpdatedAt) ? existingUpdatedAt : stats.mtime
}
})
}

/**
Expand Down
Loading