ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

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:
MREADME.md | 41++++++++++++++++++++++++-----------------
Mdocs/getting-started.md | 3+--
Mpackage.json | 20++++++++++----------
Asrc/components/Page/Page.css | 21+++++++++++++++++++++
Asrc/components/Page/Page.js | 33+++++++++++++++++++++++++++++++++
Asrc/components/Page/package.json | 6++++++
Dsrc/content/index.md | 19-------------------
Dsrc/content/privacy.md | 46----------------------------------------------
Dsrc/data/queries/content.js | 101-------------------------------------------------------------------------------
Msrc/data/schema.js | 2--
Dsrc/data/types/ContentType.js | 26--------------------------
Rsrc/content/about.md -> src/routes/about/about.md | 0
Asrc/routes/about/index.js | 31+++++++++++++++++++++++++++++++
Dsrc/routes/content/Content.css | 21---------------------
Dsrc/routes/content/Content.js | 34----------------------------------
Dsrc/routes/content/index.js | 40----------------------------------------
Msrc/routes/index.js | 3++-
Asrc/routes/privacy/index.js | 31+++++++++++++++++++++++++++++++
Asrc/routes/privacy/privacy.md | 45+++++++++++++++++++++++++++++++++++++++++++++
Atools/lib/markdown-loader.js | 25+++++++++++++++++++++++++
Mtools/webpack.config.js | 4++++
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) &nbsp;|&nbsp; -**Join** [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) chat room to stay up to date &nbsp;|&nbsp; +## React Starter Kit — "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" web app boilerplate &nbsp; <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) &nbsp;|&nbsp; +**Join** [#react-starter-kit][chat] chat room on Gitter &nbsp;|&nbsp; **Visit our sponsors**:<br><br> -[![Rollbar - Full-stack error tracking for all apps in any language](https://dl.dropboxusercontent.com/u/16006521/react-starter-kit/rollbar.png)](https://rollbar.com/?utm_source=reactstartkit(github)&utm_medium=link&utm_campaign=reactstartkit(github)) &nbsp;&nbsp; -[![Localize - Translate your web app in minutes](https://dl.dropboxusercontent.com/u/16006521/react-starter-kit/localize.png)](https://localizejs.com/?cid=802&utm_source=rsk) +[![Rollbar - Full-stack error tracking for all apps in any language](https://koistya.github.io/files/rsk/rollbar.png)](https://rollbar.com/?utm_source=reactstartkit(github)&utm_medium=link&utm_campaign=reactstartkit(github)) &nbsp;&nbsp; +[![Localize - Translate your web app in minutes](https://koistya.github.io/files/rsk/localize.png)](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', },