commit ac26f5446a6d6ea6c29bc4129a26b2976a351495
parent bdd6c70f5f3693ca5f6ca5b850d8898c8c95a290
Author: Konstantin Tarkus <koistya@gmail.com>
Date: Wed, 21 Dec 2016 10:17:56 +0300
Add markdown-loader for static pages (#1043)
- Remove /src/content folder with .md files in favor of /src/routes/about, /src/routes/privacy etc.
- Remove "content" API endpoint (src/data/queries/content.js)
- Add markdown-loader for .md files that you can easily customize in tools/lib/markdown-loader.js
Diffstat:
21 files changed, 233 insertions(+), 319 deletions(-)
diff --git a/README.md b/README.md
@@ -1,22 +1,22 @@
-## React Starter Kit — "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" web app boilerplate
-
-> [React Starter Kit](https://www.reactstarterkit.com) is an opinionated
-> boilerplate for web development built on top of [Node.js](https://nodejs.org/),
-> [Express](http://expressjs.com/), [GraphQL](http://graphql.org/) and
-> [React](https://facebook.github.io/react/), containing modern web development
-> tools such as [Webpack](http://webpack.github.io/), [Babel](http://babeljs.io/)
-> and [Browsersync](http://www.browsersync.io/). Helping you to stay productive
-> following the best practices. A solid starting point for both professionals
-> and newcomers to the industry.
-
-**See** [getting started](./docs/getting-started.md) guide,
-[demo](http://demo.reactstarterkit.com), [docs](https://github.com/kriasoft/react-starter-kit/tree/master/docs),
-[to-do list](https://waffle.io/kriasoft/react-starter-kit) |
-**Join** [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) chat room to stay up to date |
+## React Starter Kit — "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" web app boilerplate <a href="https://github.com/kriasoft/react-starter-kit/stargazers"><img src="https://img.shields.io/github/stars/kriasoft/react-starter-kit.svg?style=social&label=Star&maxAge=3600" height="20"></a> <a href="https://twitter.com/ReactStarter"><img src="https://img.shields.io/twitter/follow/ReactStarter.svg?style=social&label=Follow&maxAge=3600" height="20"></a>
+
+[React Starter Kit](https://www.reactstarterkit.com) is an opinionated boilerplate for web
+development built on top of [Node.js](https://nodejs.org/),
+[Express](http://expressjs.com/), [GraphQL](http://graphql.org/) and
+[React](https://facebook.github.io/react/), containing modern web development
+tools such as [Webpack](http://webpack.github.io/), [Babel](http://babeljs.io/)
+and [Browsersync](http://www.browsersync.io/). Helping you to stay productive
+following the best practices. A solid starting point for both professionals
+and newcomers to the industry.
+
+**See** [getting started guide](./docs/getting-started.md), [demo][demo],
+[docs](https://github.com/kriasoft/react-starter-kit/tree/master/docs),
+[roadmap](https://github.com/kriasoft/react-starter-kit/projects/1) |
+**Join** [#react-starter-kit][chat] chat room on Gitter |
**Visit our sponsors**:<br><br>
-[](https://rollbar.com/?utm_source=reactstartkit(github)&utm_medium=link&utm_campaign=reactstartkit(github))
-[](https://localizejs.com/?cid=802&utm_source=rsk)
+[](https://rollbar.com/?utm_source=reactstartkit(github)&utm_medium=link&utm_campaign=reactstartkit(github))
+[](https://localizejs.com/?cid=802&utm_source=rsk)
### Getting Started
@@ -201,6 +201,7 @@ requests](CONTRIBUTING.md#pull-requests).
### Related Projects
+ * [GraphQL Starter Kit](https://github.com/kriasoft/graphql-starter-kit) — Boilerplate for building data APIs with Node.js, JavaScript (via Babel) and GraphQL
* [Membership Database](https://github.com/membership/membership.db) — SQL schema boilerplate for user accounts, profiles, roles, and auth claims
* [Babel Starter Kit](https://github.com/kriasoft/babel-starter-kit) — Boilerplate for authoring JavaScript/React.js libraries
@@ -213,6 +214,7 @@ requests](CONTRIBUTING.md#pull-requests).
* [appear.in/react](https://appear.in/react) — Open hours! Exchange ideas and experiences (React, GraphQL, startups and pet projects)
* [@koistya](https://twitter.com/koistya) on [Codementor](https://www.codementor.io/koistya), or [Skype](http://hatscripts.com/addskype?koistya) — Private consulting
+
### License
Copyright © 2014-2016 Kriasoft, LLC. This source code is licensed under the MIT
@@ -222,3 +224,8 @@ file. The documentation to the project is licensed under the
---
Made with ♥ by Konstantin Tarkus ([@koistya](https://twitter.com/koistya)) and [contributors](https://github.com/kriasoft/react-starter-kit/graphs/contributors)
+
+[rsk]: https://www.reactstarterkit.com
+[demo]: http://demo.reactstarterkit.com
+[node]: https://nodejs.org
+[chat]: https://gitter.im/kriasoft/react-starter-kit
diff --git a/docs/getting-started.md b/docs/getting-started.md
@@ -20,7 +20,6 @@ Before you start, take a moment to see how the project structure looks like:
├── /public/ # Static files which are copied into the /build/public folder
├── /src/ # The source code of the application
│ ├── /components/ # React components
-│ ├── /content/ # Static pages like About Us, Privacy Policy etc.
│ ├── /core/ # Core framework and utility functions
│ ├── /data/ # GraphQL server schema and data models
│ ├── /routes/ # Page/screen components along with the routing information
@@ -45,7 +44,7 @@ Before you start, take a moment to see how the project structure looks like:
**Note**: The current version of RSK does not contain a Flux implementation.
It can be easily integrated with any Flux library of your choice. The most
commonly used Flux libraries are [Flux](http://facebook.github.io/flux/),
-[Redux](http://redux.js.org/), and [Relay](http://facebook.github.io/relay/).
+[Redux](http://redux.js.org/) and [Relay](http://facebook.github.io/relay/).
### Quick Start
diff --git a/package.json b/package.json
@@ -7,8 +7,8 @@
"npm": ">=3.10"
},
"dependencies": {
- "babel-polyfill": "6.16.0",
- "babel-runtime": "6.18.0",
+ "babel-polyfill": "6.20.0",
+ "babel-runtime": "6.20.0",
"bluebird": "3.4.6",
"body-parser": "1.15.2",
"classnames": "2.2.5",
@@ -19,21 +19,19 @@
"express-jwt": "5.1.0",
"fastclick": "1.0.6",
"fbjs": "0.8.6",
- "front-matter": "2.1.1",
"graphql": "0.8.2",
- "history": "4.4.0",
+ "history": "4.5.0",
"isomorphic-style-loader": "1.1.0",
- "jsonwebtoken": "7.1.9",
- "markdown-it": "8.1.0",
+ "jsonwebtoken": "7.2.1",
"node-fetch": "1.6.3",
"normalize.css": "5.0.0",
"passport": "0.3.2",
"passport-facebook": "2.1.1",
"pretty-error": "2.0.2",
"query-string": "4.2.3",
- "react": "15.4.0",
- "react-dom": "15.4.0",
- "sequelize": "3.27.0",
+ "react": "15.4.1",
+ "react-dom": "15.4.1",
+ "sequelize": "3.28.0",
"source-map-support": "0.4.6",
"sqlite3": "3.1.8",
"universal-router": "2.0.0",
@@ -69,9 +67,11 @@
"eslint-plugin-react": "^6.7.1",
"extend": "^3.0.0",
"file-loader": "^0.9.0",
+ "front-matter": "^2.1.1",
"git-repository": "^0.1.4",
"glob": "^7.1.1",
"json-loader": "^0.5.4",
+ "markdown-it": "^8.2.2",
"mkdirp": "^0.5.1",
"mocha": "^3.1.2",
"pixrem": "^3.0.2",
@@ -93,7 +93,7 @@
"postcss-selector-not": "^2.0.0",
"postcss-url": "^5.1.2",
"raw-loader": "^0.5.1",
- "react-addons-test-utils": "15.4.0",
+ "react-addons-test-utils": "15.4.1",
"react-deep-force-update": "^2.0.1",
"react-hot-loader": "^3.0.0-beta.6",
"redbox-react": "^1.3.3",
diff --git a/src/components/Page/Page.css b/src/components/Page/Page.css
@@ -0,0 +1,21 @@
+/**
+ * React Starter Kit (https://www.reactstarterkit.com/)
+ *
+ * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE.txt file in the root directory of this source tree.
+ */
+
+@import '../variables.css';
+
+.root {
+ padding-left: 20px;
+ padding-right: 20px;
+}
+
+.container {
+ margin: 0 auto;
+ padding: 0 0 40px;
+ max-width: var(--max-content-width);
+}
diff --git a/src/components/Page/Page.js b/src/components/Page/Page.js
@@ -0,0 +1,33 @@
+/**
+ * React Starter Kit (https://www.reactstarterkit.com/)
+ *
+ * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE.txt file in the root directory of this source tree.
+ */
+
+import React, { PropTypes } from 'react';
+import withStyles from 'isomorphic-style-loader/lib/withStyles';
+import s from './Page.css';
+
+class Page extends React.Component {
+ static propTypes = {
+ title: PropTypes.string,
+ html: PropTypes.string.isRequired,
+ };
+
+ render() {
+ const { title, html } = this.props;
+ return (
+ <div className={s.root}>
+ <div className={s.container}>
+ {title && <h1>{title}</h1>}
+ <div dangerouslySetInnerHTML={{ __html: html }} />
+ </div>
+ </div>
+ );
+ }
+}
+
+export default withStyles(s)(Page);
diff --git a/src/components/Page/package.json b/src/components/Page/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "Page",
+ "version": "0.0.0",
+ "private": true,
+ "main": "./Page.js"
+}
diff --git a/src/content/index.md b/src/content/index.md
@@ -1,19 +0,0 @@
----
-title: React.js Starter Kit
-component: ContentPage
----
-### Runtime Components
-
-[React](https://facebook.github.io/react/) - A JavaScript library for building user interfaces, developed by Facebook
-
-[Flux](http://facebook.github.io/flux/) - Application architecture for building user interfaces
-
-### Development Tools
-
-[Webpack](http://webpack.github.io/) - Compiles front-end source code into modules / bundles
-
-[BrowserSync](http://www.browsersync.io/) - A lightweight HTTP server for development
-
-### Fork me on GitHub
-
-[github.com/kriasoft/react-starter-kit](https://github.com/kriasoft/react-starter-kit)
diff --git a/src/content/privacy.md b/src/content/privacy.md
@@ -1,46 +0,0 @@
----
-title: Privacy Policy
-component: ContentPage
----
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean consequat
-tortor fermentum mi fermentum dignissim. Nullam vel ipsum ut ligula elementum
-lobortis. Maecenas aliquam, massa laoreet lacinia pretium, nisi urna venenatis
-tortor, nec imperdiet tellus libero efficitur metus. Fusce semper posuere
-ligula, et facilisis metus bibendum interdum. Mauris at mauris sit amet sem
-pharetra commodo a eu leo. Nam at est non risus cursus maximus. Nam feugiat
-augue libero, id consectetur tortor bibendum non. Quisque nec fringilla lorem.
-Nullam efficitur vulputate mauris, nec maximus leo dignissim id.
-
-In hac habitasse platea dictumst. Duis sagittis dui ac ex suscipit maximus.
-Morbi pellentesque venenatis felis sed convallis. Nulla varius, nibh vitae
-placerat tempus, mauris sem elementum ipsum, eget sollicitudin nisl est vel
-purus. Fusce malesuada odio velit, non cursus leo fermentum id. Cras pharetra
-sodales fringilla. Etiam quis est a dolor egestas pellentesque. Maecenas non
-scelerisque purus, congue cursus arcu. Donec vel dapibus mi. Mauris maximus
-posuere placerat. Sed et libero eu nibh tristique mollis a eget lectus. Donec
-interdum augue sollicitudin vehicula hendrerit. Vivamus justo orci, molestie
-ac sollicitudin ac, lobortis at tellus. Etiam rhoncus ullamcorper risus eu
-tempor. Sed porttitor, neque ac efficitur gravida, arcu lacus pharetra dui, in
-consequat elit tellus auctor nulla. Donec placerat elementum diam, vitae
-imperdiet lectus luctus at.
-
-Nullam eu feugiat mi. Quisque nec tristique nisl, dignissim dictum leo. Nam
-non quam nisi. Donec rutrum turpis ac diam blandit, id pulvinar mauris
-suscipit. Pellentesque tincidunt libero ultricies risus iaculis, sit amet
-consequat velit blandit. Fusce quis varius nulla. Nullam nisi nisi, suscipit
-ut magna quis, feugiat porta nibh. Sed id enim lectus. Suspendisse elementum
-justo sapien, sit amet consequat orci accumsan et. Aliquam ornare ullamcorper
-sem sed finibus. Nullam ac lacus pulvinar, egestas felis ut, accumsan est.
-
-Pellentesque sagittis vehicula sem quis luctus. Proin sodales magna in lorem
-hendrerit aliquam. Integer eu varius orci. Vestibulum ante ipsum primis in
-faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum
-primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut at mauris
-nibh. Suspendisse maximus ac eros at vestibulum.
-
-Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque egestas
-tortor et dui consequat faucibus. Nunc vitae odio ornare, venenatis ligula a,
-vulputate nisl. Aenean congue varius ex, sit amet bibendum odio posuere at.
-Nulla facilisi. In finibus, nulla vitae tincidunt ornare, sapien nulla
-fermentum mauris, sed consectetur tortor arcu eget arcu. Vestibulum vel quam
-enim.
diff --git a/src/data/queries/content.js b/src/data/queries/content.js
@@ -1,101 +0,0 @@
-/**
- * React Starter Kit (https://www.reactstarterkit.com/)
- *
- * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE.txt file in the root directory of this source tree.
- */
-
-import fs from 'fs';
-import { join } from 'path';
-import Promise from 'bluebird';
-import fm from 'front-matter';
-import MarkdownIt from 'markdown-it';
-
-import {
- GraphQLString as StringType,
- GraphQLNonNull as NonNull,
-} from 'graphql';
-
-import ContentType from '../types/ContentType';
-
-const md = new MarkdownIt();
-
-// A folder with Markdown/HTML content pages
-const CONTENT_DIR = join(__dirname, './content');
-
-// Extract 'front matter' metadata and generate HTML
-const parseContent = (path, fileContent, extension) => {
- const fmContent = fm(fileContent);
- let htmlContent;
- switch (extension) {
- case '.md':
- htmlContent = md.render(fmContent.body);
- break;
- case '.html':
- htmlContent = fmContent.body;
- break;
- default:
- return null;
- }
- return Object.assign({ path, content: htmlContent }, fmContent.attributes);
-};
-
-const readFile = Promise.promisify(fs.readFile);
-const fileExists = filename => new Promise(resolve => {
- fs.exists(filename, resolve);
-});
-
-async function resolveExtension(path, extension) {
- let fileNameBase = join(CONTENT_DIR, `${path === '/' ? '/index' : path}`);
- let ext = extension;
- if (!ext.startsWith('.')) {
- ext = `.${extension}`;
- }
-
- let fileName = fileNameBase + ext;
-
- if (!(await fileExists(fileName))) {
- fileNameBase = join(CONTENT_DIR, `${path}/index`);
- fileName = fileNameBase + ext;
- }
-
- if (!(await fileExists(fileName))) {
- return { success: false };
- }
-
- return { success: true, fileName };
-}
-
-async function resolveFileName(path) {
- const extensions = ['.md', '.html'];
-
- for (let i = 0; i < extensions.length; i += 1) {
- const extension = extensions[i];
- const maybeFileName = await resolveExtension(path, extension);
- if (maybeFileName.success) {
- return { success: true, fileName: maybeFileName.fileName, extension };
- }
- }
-
- return { success: false, fileName: null, extension: null };
-}
-
-const content = {
- type: ContentType,
- args: {
- path: { type: new NonNull(StringType) },
- },
- async resolve({ request }, { path }) {
- const { success, fileName, extension } = await resolveFileName(path);
- if (!success) {
- return null;
- }
-
- const source = await readFile(fileName, { encoding: 'utf8' });
- return parseContent(path, source, extension);
- },
-};
-
-export default content;
diff --git a/src/data/schema.js b/src/data/schema.js
@@ -13,7 +13,6 @@ import {
} from 'graphql';
import me from './queries/me';
-import content from './queries/content';
import news from './queries/news';
const schema = new Schema({
@@ -21,7 +20,6 @@ const schema = new Schema({
name: 'Query',
fields: {
me,
- content,
news,
},
}),
diff --git a/src/data/types/ContentType.js b/src/data/types/ContentType.js
@@ -1,26 +0,0 @@
-/**
- * React Starter Kit (https://www.reactstarterkit.com/)
- *
- * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE.txt file in the root directory of this source tree.
- */
-
-import {
- GraphQLObjectType as ObjectType,
- GraphQLString as StringType,
- GraphQLNonNull as NonNull,
-} from 'graphql';
-
-const ContentType = new ObjectType({
- name: 'Content',
- fields: {
- path: { type: new NonNull(StringType) },
- title: { type: new NonNull(StringType) },
- content: { type: new NonNull(StringType) },
- component: { type: new NonNull(StringType) },
- },
-});
-
-export default ContentType;
diff --git a/src/content/about.md b/src/routes/about/about.md
diff --git a/src/routes/about/index.js b/src/routes/about/index.js
@@ -0,0 +1,31 @@
+/**
+ * React Starter Kit (https://www.reactstarterkit.com/)
+ *
+ * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE.txt file in the root directory of this source tree.
+ */
+
+import React from 'react';
+import Layout from '../../components/Layout';
+import Page from '../../components/Page';
+
+export default {
+
+ path: '/about',
+
+ async action() {
+ const data = await new Promise((resolve) => {
+ require.ensure([], require => {
+ resolve(require('./about.md'));
+ }, 'about');
+ });
+
+ return {
+ title: data.title,
+ component: <Layout><Page {...data} /></Layout>,
+ };
+ },
+
+};
diff --git a/src/routes/content/Content.css b/src/routes/content/Content.css
@@ -1,21 +0,0 @@
-/**
- * React Starter Kit (https://www.reactstarterkit.com/)
- *
- * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE.txt file in the root directory of this source tree.
- */
-
-@import '../../components/variables.css';
-
-.root {
- padding-left: 20px;
- padding-right: 20px;
-}
-
-.container {
- margin: 0 auto;
- padding: 0 0 40px;
- max-width: var(--max-content-width);
-}
diff --git a/src/routes/content/Content.js b/src/routes/content/Content.js
@@ -1,34 +0,0 @@
-/**
- * React Starter Kit (https://www.reactstarterkit.com/)
- *
- * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE.txt file in the root directory of this source tree.
- */
-
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Content.css';
-
-class Content extends React.Component {
- static propTypes = {
- path: PropTypes.string.isRequired,
- content: PropTypes.string.isRequired,
- title: PropTypes.string,
- };
-
- render() {
- const { path, title, content } = this.props;
- return (
- <div className={s.root}>
- <div className={s.container}>
- {title && path !== '/' && <h1>{title}</h1>}
- <div dangerouslySetInnerHTML={{ __html: content }} />
- </div>
- </div>
- );
- }
-}
-
-export default withStyles(s)(Content);
diff --git a/src/routes/content/index.js b/src/routes/content/index.js
@@ -1,40 +0,0 @@
-/**
- * React Starter Kit (https://www.reactstarterkit.com/)
- *
- * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE.txt file in the root directory of this source tree.
- */
-
-import React from 'react';
-import fetch from '../../core/fetch';
-import Layout from '../../components/Layout';
-import Content from './Content';
-
-export default {
-
- path: '*',
-
- async action({ path }) { // eslint-disable-line react/prop-types
- const resp = await fetch('/graphql', {
- method: 'post',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- query: `{content(path:"${path}"){path,title,content,component}}`,
- }),
- credentials: 'include',
- });
- if (resp.status !== 200) throw new Error(resp.statusText);
- const { data } = await resp.json();
- if (!data || !data.content) return undefined;
- return {
- title: data.content.title,
- component: <Layout><Content {...data.content} /></Layout>,
- };
- },
-
-};
diff --git a/src/routes/index.js b/src/routes/index.js
@@ -20,10 +20,11 @@ export default {
require('./contact').default,
require('./login').default,
require('./register').default,
+ require('./about').default,
+ require('./privacy').default,
require('./admin').default,
// Wildcard routes, e.g. { path: '*', ... } (must go last)
- require('./content').default,
require('./notFound').default,
],
diff --git a/src/routes/privacy/index.js b/src/routes/privacy/index.js
@@ -0,0 +1,31 @@
+/**
+ * React Starter Kit (https://www.reactstarterkit.com/)
+ *
+ * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE.txt file in the root directory of this source tree.
+ */
+
+import React from 'react';
+import Layout from '../../components/Layout';
+import Page from '../../components/Page';
+
+export default {
+
+ path: '/privacy',
+
+ async action() {
+ const data = await new Promise((resolve) => {
+ require.ensure([], require => {
+ resolve(require('./privacy.md'));
+ }, 'privacy');
+ });
+
+ return {
+ title: data.title,
+ component: <Layout><Page {...data} /></Layout>,
+ };
+ },
+
+};
diff --git a/src/routes/privacy/privacy.md b/src/routes/privacy/privacy.md
@@ -0,0 +1,45 @@
+---
+title: Privacy Policy
+---
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean consequat
+tortor fermentum mi fermentum dignissim. Nullam vel ipsum ut ligula elementum
+lobortis. Maecenas aliquam, massa laoreet lacinia pretium, nisi urna venenatis
+tortor, nec imperdiet tellus libero efficitur metus. Fusce semper posuere
+ligula, et facilisis metus bibendum interdum. Mauris at mauris sit amet sem
+pharetra commodo a eu leo. Nam at est non risus cursus maximus. Nam feugiat
+augue libero, id consectetur tortor bibendum non. Quisque nec fringilla lorem.
+Nullam efficitur vulputate mauris, nec maximus leo dignissim id.
+
+In hac habitasse platea dictumst. Duis sagittis dui ac ex suscipit maximus.
+Morbi pellentesque venenatis felis sed convallis. Nulla varius, nibh vitae
+placerat tempus, mauris sem elementum ipsum, eget sollicitudin nisl est vel
+purus. Fusce malesuada odio velit, non cursus leo fermentum id. Cras pharetra
+sodales fringilla. Etiam quis est a dolor egestas pellentesque. Maecenas non
+scelerisque purus, congue cursus arcu. Donec vel dapibus mi. Mauris maximus
+posuere placerat. Sed et libero eu nibh tristique mollis a eget lectus. Donec
+interdum augue sollicitudin vehicula hendrerit. Vivamus justo orci, molestie
+ac sollicitudin ac, lobortis at tellus. Etiam rhoncus ullamcorper risus eu
+tempor. Sed porttitor, neque ac efficitur gravida, arcu lacus pharetra dui, in
+consequat elit tellus auctor nulla. Donec placerat elementum diam, vitae
+imperdiet lectus luctus at.
+
+Nullam eu feugiat mi. Quisque nec tristique nisl, dignissim dictum leo. Nam
+non quam nisi. Donec rutrum turpis ac diam blandit, id pulvinar mauris
+suscipit. Pellentesque tincidunt libero ultricies risus iaculis, sit amet
+consequat velit blandit. Fusce quis varius nulla. Nullam nisi nisi, suscipit
+ut magna quis, feugiat porta nibh. Sed id enim lectus. Suspendisse elementum
+justo sapien, sit amet consequat orci accumsan et. Aliquam ornare ullamcorper
+sem sed finibus. Nullam ac lacus pulvinar, egestas felis ut, accumsan est.
+
+Pellentesque sagittis vehicula sem quis luctus. Proin sodales magna in lorem
+hendrerit aliquam. Integer eu varius orci. Vestibulum ante ipsum primis in
+faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum
+primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut at mauris
+nibh. Suspendisse maximus ac eros at vestibulum.
+
+Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque egestas
+tortor et dui consequat faucibus. Nunc vitae odio ornare, venenatis ligula a,
+vulputate nisl. Aenean congue varius ex, sit amet bibendum odio posuere at.
+Nulla facilisi. In finibus, nulla vitae tincidunt ornare, sapien nulla
+fermentum mauris, sed consectetur tortor arcu eget arcu. Vestibulum vel quam
+enim.
diff --git a/tools/lib/markdown-loader.js b/tools/lib/markdown-loader.js
@@ -0,0 +1,25 @@
+/**
+ * React Starter Kit (https://www.reactstarterkit.com/)
+ *
+ * Copyright © 2014-2016 Kriasoft, LLC. All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE.txt file in the root directory of this source tree.
+ */
+
+const MarkdownIt = require('markdown-it');
+const fm = require('front-matter');
+
+module.exports = function markdownLoader(source) {
+ this.cacheable();
+
+ const md = new MarkdownIt({
+ html: true,
+ linkify: true,
+ });
+
+ const frontmatter = fm(source);
+ frontmatter.attributes.html = md.render(frontmatter.body);
+
+ return `module.exports = ${JSON.stringify(frontmatter.attributes)};`;
+};
diff --git a/tools/webpack.config.js b/tools/webpack.config.js
@@ -95,6 +95,10 @@ const config = {
],
},
{
+ test: /\.md$/,
+ loader: path.resolve(__dirname, './lib/markdown-loader.js'),
+ },
+ {
test: /\.json$/,
loader: 'json-loader',
},