Skip to content

Commit

Permalink
Front matter in JS (closes #2 and #439) (#591)
Browse files Browse the repository at this point in the history
* pull "frontmatter" from jsx or js via exports.data = {}

* return empty object if no exports.data set in js(x)

* add explanation for js|x exports.data metadata
  • Loading branch information
jbolda authored and KyleAMathews committed Dec 9, 2016
1 parent 2648738 commit b1a1850
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 8 deletions.
29 changes: 29 additions & 0 deletions README.md
Expand Up @@ -274,6 +274,35 @@ module.exports = React.createClass({
})
```

#### frontmatter and metadata
Gatsby uses frontmatter and html-frontmatter to pull metadata out of files. This data is typically used in links leading to each page. The most relevant example is a list of blog posts in which you display the title, description, tags, etc. in the form of `{post.title}` in the React.js component.

As seen in our previous markdown file, the title is part of the frontmatter
```
---
title: This is a title
---
# Hi friends.
This is a markdown file.
```

An html example as follows.
```
<!--
title: This is a title
-->
<h1>Hello World</h1>
```

Gatsby will additionally pull data out of js|jsx files. The files are statically analyzed and an `exports.data` object is pulled. An example as follows.
```
exports.data = {
title: 'This is a title'
}
```

### Structure of a Gatsby site
* `config.toml` - Core application configuration is stored here. Available via a `require`
or `import` of 'config'. Values:
Expand Down
10 changes: 2 additions & 8 deletions lib/isomorphic/create-routes.js
Expand Up @@ -132,14 +132,8 @@ module.exports = (files, pagesReq) => {
handler = wrappers[page.file.ext]
page.data = pagesReq(`./${page.requirePath}`)
} else if (reactComponentFileTypes.indexOf(page.file.ext) !== -1) {
handler = requireComponent(pagesReq(`./${page.requirePath}`))
page.data = (() => {
if (pagesReq(`./${page.requirePath}`).metadata) {
return pagesReq(`./${page.requirePath}`).metadata()
} else {
return {}
}
})()
handler = pagesReq(`./${page.requirePath}`)
page.data = page.data = (page.data === undefined) ? {} : page.data
}

// Determine parent template for page.
Expand Down
28 changes: 28 additions & 0 deletions lib/utils/build-page/load-frontmatter.js
Expand Up @@ -4,6 +4,8 @@ import path from 'path'
import frontMatter from 'front-matter'
import objectAssign from 'object-assign'
import htmlFrontMatter from 'html-frontmatter'
import * as babylon from 'babylon'
import traverse from 'babel-traverse'

export default function loadFrontmatter (pagePath: string): {} {
const ext: string = path.extname(pagePath).slice(1)
Expand All @@ -21,6 +23,32 @@ export default function loadFrontmatter (pagePath: string): {} {
const html = fs.readFileSync(pagePath, { encoding: 'utf-8' })
// $FlowIssue - https://github.com/facebook/flow/issues/1870
data = objectAssign({}, htmlFrontMatter(html), { body: html })
} else if (ext === 'js' || ext === 'jsx') {
try {
const code = fs.readFileSync(pagePath, { encoding: 'utf-8' })
const options = {
sourceType: 'module',
allowImportExportEverywhere: true,
plugins: ['*'] // may only need ['jsx', 'objectRestSpread']?
}
const ast = babylon.parse(code, options);

data = {}
traverse(ast, {
AssignmentExpression(path) {
if (path.node.left.type === 'MemberExpression' &&
path.node.left.property.name === 'data') {
path.node.right.properties.forEach((prop) => {
data[prop.key.name] = prop.value.value
})
}
}
})
} catch (e) {
console.log('Failed to parse file')
console.log(e)
data = {}
}
} else {
data = {}
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -25,6 +25,7 @@
"babel-preset-react": "^6.11.1",
"babel-preset-react-hmre": "^1.1.1",
"babel-preset-stage-0": "^6.5.0",
"babel-traverse": "^6.18.0",
"boom": "^2.7.2",
"cjsx-loader": "^3.0.0",
"coffee-loader": "^0.7.2",
Expand Down

0 comments on commit b1a1850

Please sign in to comment.