├── example └── simple-site │ ├── src │ ├── content │ │ ├── pages │ │ │ ├── blog.md │ │ │ └── about.md │ │ └── posts │ │ │ └── first-post.md │ ├── index.md │ ├── styles │ │ └── main.scss │ └── scripts │ │ └── main.coffee │ ├── server.js │ ├── templates │ ├── Blog.jsx │ └── Layout.jsx │ ├── package.json │ ├── Readme.md │ └── index.js ├── package.json ├── Readme.md └── index.js /example/simple-site/src/content/pages/blog.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Blog 3 | template: blog.jsx 4 | --- 5 | -------------------------------------------------------------------------------- /example/simple-site/src/content/pages/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | template: blog.jsx 4 | --- 5 | Tell the world something about yourself here! -------------------------------------------------------------------------------- /example/simple-site/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | template: blog.jsx 4 | --- 5 | Hi, this is my start page; neat ain't it? ;) 6 | 7 | ###Some info! 8 | -------------------------------------------------------------------------------- /example/simple-site/src/content/posts/first-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "First Post" 3 | date: 2014-04-18 4 | foooo: barrrrrr 5 | cooo: doooooo 6 | template: blog.jsx 7 | --- 8 | This is an amazing blogpost! -------------------------------------------------------------------------------- /example/simple-site/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | $accent: #d85312; 4 | 5 | $main-font: #0e0e0e; 6 | 7 | body { 8 | color: $main-font; 9 | } 10 | 11 | a { 12 | color: $accent; 13 | } 14 | 15 | .main-wrapper { 16 | width: 800px; 17 | margin: 0 auto; 18 | } -------------------------------------------------------------------------------- /example/simple-site/src/scripts/main.coffee: -------------------------------------------------------------------------------- 1 | 2 | class App 3 | constructor: (@name) -> 4 | console.log "#{name} was initialized" 5 | 6 | doStuff: -> 7 | console.log "Te Most Useful Method Ever!" 8 | 9 | 10 | 11 | 12 | a = new App 'Hello World App' 13 | 14 | a.doStuff() -------------------------------------------------------------------------------- /example/simple-site/server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // node libs 4 | var url = require('url'); 5 | var http = require('http'); 6 | var express = require('express'); 7 | 8 | var app = express(); 9 | 10 | app.use(express.static('./build/')); 11 | 12 | // start the HTTP server 13 | var httpServer = http.createServer(app); 14 | 15 | // 16 | httpServer.listen( 3000, function (err) { 17 | if (err) { 18 | console.warn('Can\'t start server. Error: ', err, err.stack); 19 | return; 20 | } 21 | console.log('server started port', 3000); 22 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "metalsmith-reactjs", 3 | "version": "1.0.0", 4 | "description": "Use reactjs as template engine for metalsmith", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/coodoo/metalsmith-reactjs.git" 12 | }, 13 | "author": "Jeremy Lu ", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/coodoo/metalsmith-reactjs/issues" 17 | }, 18 | "homepage": "https://github.com/coodoo/metalsmith-reactjs", 19 | "devDependencies": {}, 20 | "dependencies": { 21 | "async": "^0.9.0", 22 | "debug": "^2.1.2", 23 | "extend": "^2.0.0", 24 | "node-jsx": "^0.12.4", 25 | "react": "^0.12.1" 26 | }, 27 | "readme": "See github page" 28 | } 29 | -------------------------------------------------------------------------------- /example/simple-site/templates/Blog.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 3 | var React = require('react'); 4 | var Layout = require('./Layout.jsx'); 5 | 6 | // This is just a simple example of a component that can be rendered on both 7 | // the server and browser 8 | 9 | module.exports = React.createClass({ 10 | 11 | // We initialise its state by using the `props` that were passed in when it 12 | // was first rendered 13 | getInitialState: function() { 14 | 15 | // jx: 注意這裏接收了 this.props 傳入的參數 16 | // 就算在 server 上也可以傳進來喔 17 | return {items: this.props.pages} 18 | }, 19 | 20 | // 21 | handleClick: function() { 22 | // this.setState({items: this.state.items.concat(this.state.items.length)}) 23 | }, 24 | 25 | // 26 | render: function() { 27 | 28 | return ( 29 | 30 | 31 |

Blog contents

32 |

33 | {this.state.items.map( function(item) { 34 | return {item.title}
35 | } 36 | )} 37 |

38 | 39 |
40 | ) 41 | } 42 | 43 | }) 44 | -------------------------------------------------------------------------------- /example/simple-site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "metalsmith-reactjs", 3 | "version": "0.0.1", 4 | "description": "ff", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/coodoo/metalsmith-reactjs.git" 12 | }, 13 | "author": "Robin Thrift ", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/coodoo/metalsmith-reactjs/issues" 17 | }, 18 | "homepage": "https://github.com/coodoo/metalsmith-reactjs", 19 | "devDependencies": { 20 | "metalsmith": "^1.0.0", 21 | "metalsmith-markdown": "^0.2.1", 22 | "metalsmith-collections": "^0.4.0", 23 | "metalsmith-permalinks": "^0.3.0", 24 | "metalsmith-coffee": "^0.0.1", 25 | "metalsmith-sass": "^0.1.1" 26 | }, 27 | "dependencies": { 28 | "async": "^0.9.0", 29 | "express": "^4.10.4", 30 | "extend": "^2.0.0", 31 | "metalsmith-coffee": "0.0.2", 32 | "metalsmith-sass": "^0.5.0", 33 | "node-jsx": "^0.12.4", 34 | "react": "^0.12.1" 35 | }, 36 | "readme": "rrrr" 37 | } 38 | -------------------------------------------------------------------------------- /example/simple-site/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # metalsmith-reactjs example 3 | 4 | This example demonstrates how to use react.js as the template engine to compose each page. 5 | 6 | 7 | ## Installation 8 | 9 | $ npm install 10 | 11 | ## Run 12 | 13 | ``` 14 | $ node server 15 | ``` 16 | 17 | then visit `http://localhost:3000` 18 | 19 | ## Usage 20 | 21 | ### Layout.jsx 22 | 23 | This is the base view component, all top level pages should start with this component. You could change each page's meta tag like `title`, `description` in this component, or better yet, make them metatags in markdown file and bind to each field at build time. 24 | 25 | ### Blog.jsx 26 | 27 | This is a top level page, it's contents should all be wrapped in the `` component, which looks like this: 28 | 29 | ``````javascript 30 | 31 | render: function() { 32 | 33 | return ( 34 | 35 | 36 |

Blog contents

37 |

38 | {this.state.items.map( function(item) { 39 | return {item.title}
40 | } 41 | )} 42 |

43 | 44 |
45 | ) 46 | } 47 | 48 | 49 | ``` 50 | 51 | Since this is a standard reactjs comonent, you enjoy the **ultimate** freedom of assembling the page with sub-components (in a sense of `partials` in traditional templating system like `Handlebars`) however you like. 52 | 53 | ## License 54 | 55 | MIT -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # metalsmith-reactjs 3 | 4 | A **[metalsmith](https://github.com/segmentio/metalsmith)** plugin to render files using [React.js](http://facebook.github.io/react/) as the template engine, hence allowing you to use familiar `jsx` syntax to compose pages in a component manner instead of partials. 5 | 6 | In short, it's a replacement for traditional templating system like `Handlebars` or `Jade`. 7 | 8 | 9 | ## Installation 10 | 11 | $ npm install metalsmith-reactjs 12 | 13 | ## Javascript Usage 14 | 15 | For the simplest use case, just pass your templating engine: 16 | 17 | ```js 18 | var template = require('metalsmith-reactjs'); 19 | 20 | metalsmith.use(template()); 21 | ``` 22 | 23 | To specify additional options: 24 | 25 | ```js 26 | metalsmith.use(template({ 27 | staticPage: true, 28 | templateDir: __dirname + '/templates/' 29 | })); 30 | ``` 31 | 32 | ### staticPage 33 | When true, will use `React.renderToStaticMarkup()` to generate content string, which contains no `data-react-id` hence it's pure static content without any react component functionality. 34 | 35 | When set to false, will use `React.renderToString()` to generate content string, each generated element will come with `data-react-id` attribute so you can control it just like any react component. 36 | 37 | ### templateDir 38 | Assign path to template folder, default is `./templates`. 39 | 40 | 41 | ## CLI Usage 42 | 43 | Install the node modules and then add the `metalsmith-reactjs` key to your `metalsmith.json` plugins. If you want to specify additional options, pass an object: 44 | 45 | ```json 46 | { 47 | "plugins": { 48 | "metalsmith-reactjs": { 49 | "staticPage": true, 50 | "templateDir": "./templates/" 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | ## Example 57 | 58 | See `example/`. 59 | 60 | ## License 61 | 62 | MIT -------------------------------------------------------------------------------- /example/simple-site/templates/Layout.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 3 | var React = require('react'); 4 | 5 | // This is just a simple example of a component that can be rendered on both 6 | // the server and browser 7 | 8 | module.exports = React.createClass({ 9 | 10 | // We initialise its state by using the `props` that were passed in when it 11 | // was first rendered 12 | getInitialState: function() { 13 | 14 | // jx: 注意這裏接收了 this.props 傳入的參數 15 | // 就算在 server 上也可以傳進來喔 16 | return {items: this.props.pages} 17 | }, 18 | 19 | // Then we just update the state whenever its clicked - but you could imagine 20 | // this being updated with the results of AJAX calls, etc 21 | handleClick: function() { 22 | this.setState({items: this.state.items.concat(this.state.items.length)}) 23 | }, 24 | 25 | // 這是最外層基底元件,放 , , 等元素 26 | render: function() { 27 | 28 | return ( 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {this.props.title} 39 | 40 | 41 | 42 | {/*