Skip to content

Commit

Permalink
Big Upgrade (#28)
Browse files Browse the repository at this point in the history
* update deps, lint with prettier

* pagination architecture upgrade

* refactor out old logic

* readme-driven dev

* add markdown layout option

* test fixes

* update readme
  • Loading branch information
jescalan authored Aug 18, 2017
1 parent 1f3e8e0 commit 3e0621f
Show file tree
Hide file tree
Showing 10 changed files with 660 additions and 1,015 deletions.
38 changes: 35 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Some jekyll-esque features for spike
### Why should you care?

Hi there! Coming from jekyll to check this out? You've found your happy place. This plugin adds more or less all the essential features from jekyll to spike, giving you the capability to use front matter, date format posts, and paginate. If you are working on a small blog, this is a great plugin for you. And if you're working on a large blog, it's still great because you can use hard-source cacheing to produce incremental builds and still have lightning fast compile times.
Hi there! Coming from jekyll to check this out? You've found your happy place. This plugin adds more or less all the essential features from jekyll to spike, giving you the capability to use front matter, date format posts, and paginate. If you are working on a small blog, this is a great plugin for you. And if you're working on a large blog, you should use a real database to store your posts, rather than a github repo 😁

### Installation

Expand All @@ -37,8 +37,6 @@ module.exports = {
}
```

> **NOTE:** Because of [an unfortunate webpack issue](https://github.com/webpack/webpack/issues/2515), you cannot use the globally installed spike CLI with this plugin. Instead, you must install spike locally (`npm i spike -S`), then execute that version. Typically adding an npm script that runs `spike watch` is the best approach.
This default configuration will look for a folder called `posts` and compile all the content into that folder in the same way that jekyll does. You can also customize your collections. For example, the default config really resolves to this:

```js
Expand Down Expand Up @@ -239,6 +237,39 @@ new Collections({

More information on pagination options can be found below.

### Using Raw Markdown Files

We strongly recommend using reshape templates with a markdown block when trying to write markdown due to the higher flexibility of using full html templates. However, there are some applications such as porting from other systems that require the use of raw markdown files without html layouts at all, and some people just still prefer this method. Spike Collections can handle this case if it is needed using the `markdownLayout` option. For example:

```js
new Collections({
addDataTo: locals,
collections: {
posts: {
files: 'posts/**',
markdownLayout: 'layouts/post.html'
}
}
})
```

The `markdownLayout` option is an accepts a glob-compatible path, resolved relative to the project root, pointing to a reshape layout. All front matter locals will be available within the layout, and the contents of the markdown file will be available via an automatically injected `_content` local, rendered as html. An example of how a layout might look:

```
<doctype html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
{{{ _content }}}
</body>
</html>
```

Note that if the `markdownLayout` option is present, any file with a `.md` or `.markdown` extension in your collection folder will be rendered into the layout. Any other file will be rendered as usual.

### Options

| Name | Description | Default |
Expand All @@ -248,6 +279,7 @@ More information on pagination options can be found below.
| **collections.[name].files** | A [globstar](http://globtester.com) string relative to the project root matching any files to be processed as posts | |
| **collections.[name].permalinks** | A function that accepts the relative path to a given file and returns a desired output path. | |
| **collections.[name].transform** | A function that accepts the full locals for each post and returns a modified locals object. | |
| **collections.[name].markdownLayout** | Path relative to the project layout specifying a layout file to render any raw markdown files into | |
| **collections.[name].paginate** | Object with keys as described below | |
| **collections.[name].paginate.perPage** | Integer representing the number of posts per page. | `10` |
| **collections.[name].paginate.template** | _(required if paginate is provided)_ Path (relative to the project root) to a template to render additional pages into. | |
Expand Down
27 changes: 26 additions & 1 deletion lib/frontmatter_loader.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,43 @@
const yaml = require('js-yaml')
const File = require('filewrap')
const path = require('path')
const fs = require('fs')
const MarkdownIt = require('markdown-it')
const { map } = require('objectfn')
const md = new MarkdownIt()

// this loader will put out front matter, adding the props to the loader context for plugin to grab later
module.exports = function frontmatterLoader (source) {
module.exports = function frontmatterLoader(source) {
this.cacheable && this.cacheable()
if (!this.options.__frontmatter) this.options.__frontmatter = {}

// TODO: this regex doesn't handle \r\n line breaks
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n?---\s*\n?([\s\S]*)/

// Let's find out if we need to render markdown into a layout
// Basically, if the post is in a collection that has markdownLayout...
let markdownLayout
map(this.options._collectionsLayoutMap || {}, (v, k) => {
if (v.indexOf(this.resourcePath) > -1) markdownLayout = k
})

// ...and it has a markdown extension, then we need to do some extra work
// below
const mdExtension =
['.md', '.markdown', '.mdown'].indexOf(path.extname(this.resourcePath)) > -1

// pull front matter, add to options, return just the body
return source.replace(frontmatterRegex, (match, fm, body) => {
const f = new File(this.options.context, this.resourcePath)
this.options.__frontmatter[f.relative] = yaml.safeLoad(fm)

// first, we compile the markdown and add it as _content to the front matter
if (markdownLayout && mdExtension) {
this.options.__frontmatter[f.relative]._content = md.render(body)
// then we pull the source for the layout and return that instead
// TODO: cache it
return fs.readFileSync(markdownLayout, 'utf8')
}
return body
})
}
Loading

0 comments on commit 3e0621f

Please sign in to comment.