Skip to content
This repository has been archived by the owner on Dec 28, 2017. It is now read-only.

Commit

Permalink
feat: render blog posts statically
Browse files Browse the repository at this point in the history
  • Loading branch information
mfellner committed Sep 13, 2016
1 parent 1c4a10d commit e166031
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 13 deletions.
3 changes: 2 additions & 1 deletion lib/blogging.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ export async function createPost(title: string, options: BloggingOptions = {}):
export function getPostFileName(title: string): string {
const date = new Date().toISOString().substring(0, '1970-01-01'.length)
const name = title
.trim()
.toLowerCase() // lowercase all characters
.replace(/[^a-z0-9\s]+/g, '') // remove non-alphanumeric characters
.replace(/\s+/g, '-') // replace consecutive whitespaces with '-'
.replace(/[^a-z0-9-]+/g, '') // remove non-alphanumeric characters
return `${date}-${name}.md`
}
20 changes: 12 additions & 8 deletions lib/building.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as futils from './file-utils'

type PackpressConfig = {
template: string;
dynamic?: boolean;
title?: string;
};

Expand All @@ -23,7 +24,7 @@ type BuildingOptions = {

type BlogPost = {
name: string;
content: string;
html: string;
};

const DIST_DIR = 'dist'
Expand All @@ -36,7 +37,7 @@ export async function buildProject(options: BuildingOptions = {}): Promise<strin
const rootDir = options.path || process.cwd()
const projectPath = await project.getProjectPath(rootDir)

const {template, ...props} = await parseConfig(projectPath)
const {template, dynamic, ...props} = await parseConfig(projectPath)
console.log('Found project in', projectPath)

const templatePath = path.resolve(projectPath, template)
Expand All @@ -46,19 +47,22 @@ export async function buildProject(options: BuildingOptions = {}): Promise<strin
// Write blog posts HTML
const posts = await loadPosts()
const postFiles = await Promise.all(posts.map(post =>
futils.writeFile(path.join(projectPath, POSTS_DST_DIR, post.name) + '.html', post.content)
futils.writeFile(path.join(projectPath, POSTS_DST_DIR, post.name) + '.html', post.html)
))

// Write index.html
const indexHTML = await renderHTML(indexPath, {...props, Root})
const indexHTML = await renderHTML(indexPath, {...props, posts, Root}, dynamic)
const indexHTMLFile = path.join(projectPath, DIST_DIR, 'index.html')
return await futils.writeFile(indexHTMLFile, indexHTML)
}

export async function renderHTML(jsxFile: string, props: Object = {}): Promise<string> {
export async function renderHTML(jsxFile: string, props: Object = {}, dynamic: boolean = false): Promise<string> {
const loader = await Loader.getInstance()
const ReactClass = await loader.loadModuleFromFile(jsxFile)
return ReactDOMServer.renderToStaticMarkup(<ReactClass {...props}/>)
if (dynamic)
return ReactDOMServer.renderToString(<ReactClass {...props}/>)
else
return ReactDOMServer.renderToStaticMarkup(<ReactClass {...props}/>)
}

export async function parseConfig(projectPath: string): Promise<PackpressConfig> {
Expand All @@ -78,8 +82,8 @@ export async function loadPosts(): Promise<Array<BlogPost>> {

return await Promise.all(postFiles.map(async (file) => {
const buffer = await fs.readFile(file)
const content = render.renderMarkdown(buffer.toString())
const html = render.renderMarkdown(buffer.toString())
const name = path.basename(file, '.md')
return {name, content}
return {name, html}
}))
}
13 changes: 11 additions & 2 deletions template/components/Blog.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import React, { Component } from 'react'
import BlogPost from './BlogPost'

export default class Blog extends Component {
props: {
posts: Array<{name: string, html: string}>
}

export default class Root extends Component {
render() {
return null
return <div>
{this.props.posts.map((post, i) =>
<BlogPost key={i} name={post.name} html={post.html}/>
)}
</div>
}
}
11 changes: 10 additions & 1 deletion template/components/BlogPost.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import React, { Component } from 'react'

export default class BlogPost extends Component {
props: {
name: string,
html: string
}

getMarkup() {
return {__html: this.props.html}
}

render() {
return null
return <div dangerouslySetInnerHTML={this.getMarkup()}/>
}
}
6 changes: 5 additions & 1 deletion template/components/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import Footer from './Footer'
import Header from './Header'

export default class Root extends Component {
props: {
posts: Array<{name: string, html: string}>
}

render() {
return <div>
<Header/>
<Blog/>
<Blog posts={this.props.posts}/>
<Footer/>
</div>
}
Expand Down
9 changes: 9 additions & 0 deletions test/building.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,13 @@ describe('building', () => {
expect(futils.writeFile).toBeCalledWith('/hello/dist/posts/1970-01-01-hello.html', '<div>hello</div>')
})
})

describe('#parseConfig()', () => {
it('should throw an error if the configuration is invalid', async () => {
futils.__setMockReturnValues({
readJSON: {}
})
await expectAsyncToThrow(building.parseConfig('packpress.json'))(/Invalid config/)
})
})
})
19 changes: 19 additions & 0 deletions test/template/Blog.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import renderer from 'react-test-renderer'
import Blog from '../../template/components/Blog'

describe('Blog', () => {
it('should render blog posts', () => {
const props = {
posts: [
{name: 'Hello', html: '<div>World!</div>'},
{name: 'Bonjour', html: '<div>Le monde!</div>'}
]
}
const component = renderer.create(
<Blog {...props}/>
)
const tree = component.toJSON()
expect(tree).toMatchSnapshot()
})
})
16 changes: 16 additions & 0 deletions test/template/__snapshots__/Blog.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
exports[`Blog should render blog posts 1`] = `
<div>
<div
dangerouslySetInnerHTML={
Object {
"__html": "<div>World!</div>"
}
} />
<div
dangerouslySetInnerHTML={
Object {
"__html": "<div>Le monde!</div>"
}
} />
</div>
`;

0 comments on commit e166031

Please sign in to comment.