Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Static sites with react

961 views

Published on

react-static: a React static site generator framework for Node.js

Published in: Software
  • Login to see the comments

Static sites with react

  1. 1. static sites with react github.com/rpearce @RobertWPearce The Iron Yard 1
  2. 2. 2 Jekyll Middleman Static Site Generators Octopress Metalsmith Hexo Wintersmith
  3. 3. 3
  4. 4. 4 the original static site generator?
  5. 5. 5
  6. 6. 6 react.js what is out there?
  7. 7. 7
  8. 8. 8 awesome! but I need more
  9. 9. 9 solution: reinvent all the things
  10. 10. 10 problems to solve
  11. 11. 11 1. define structure of pages 2. create HTML files from rendered react
  12. 12. 12 stop there? nope.
  13. 13. 13 3. bundle client-side JS and also provide instant page linking
  14. 14. 14 1. define structure of pages 2. create HTML files from rendered react 3. bundle client-side JS and provide instant page linking
  15. 15. 15 react-router
  16. 16. 16 import React from 'react'; const Example = () => <main role="main"> <header> <h1>Example</h1> </header> </main> Example.meta = { title: 'Example', description: 'This is the example' }; export default Example; Example.react.js
  17. 17. 17 import Root from './Root.react'; import Index from './Index.react'; import Example from './Example.react'; import NestedExample from './NestedExample.react'; const routes = { IndexRoute: { component: Index }, ExampleRoute: { path: 'example.html', component: Example }, NestedExampleRoute: { path: 'this/is/a/ridiculously/nested/example.html', component: NestedExample } }; // ... routes.js
  18. 18. 18 // ... const getChildRoutes = () => { let childRoutes = []; for (let key in routes) { if (key !== 'IndexRoute') { childRoutes.push(routes[key]); } } return childRoutes; }; export default { path: '/', component: Root, indexRoute: routes.IndexRoute, childRoutes: getChildRoutes() }; routes.js
  19. 19. 19 1. define structure of pages 2. create HTML files from rendered react 3. bundle client-side JS and provide instant page linking
  20. 20. 20 react + react-router + fs-promise
  21. 21. 21 import { match, RoutingContext } from ‘react-router'; import routes from '../src/components/routes'; /* * For the `indexRoute` plus all * `childRoutes`, do the following */ const location = '/'.concat(path || ''); match( { routes, location }, async function handleMatch(err, redirectLocation, renderProps) { /* * Render component markup, create output directories * and write markup to a file whose filename is * extracted from the route's path. * Provide fallback of `index.html` for IndexRoute. */ } ); match each location
  22. 22. 22 import { exec } from 'child_process'; import React from 'react'; import { renderToString } from ‘react-dom/server'; import fsp from ‘fs-promise'; const html = renderToString(<RoutingContext {...renderProps} />), directory = determineDirectory(path), filePath = path || 'index.html'; await exec(`mkdir -p _site/${directory}`, execCallback); await fsp.writeFile( `_site/${filePath}`, `<!DOCTYPE html>${componentHTML}`, 'utf8', fspCallback ); render react and write files
  23. 23. 23 1. define structure of pages 2. create HTML files from rendered react 3. bundle client-side JS and provide instant page linking
  24. 24. 24 npm scripts + gulp + browserify
  25. 25. 25 import gulp from 'gulp'; import browserify from 'browserify'; import babelify from 'babelify'; import source from 'vinyl-source-stream'; const client = async () => { return browserify({ entries: 'src/browser.js', debug: true }) .transform(babelify) .bundle() .pipe(source('app.js')) .pipe(gulp.dest('_site')); } export default client;
  26. 26. 26 …and the instant page linking?
  27. 27. 27 already using react-router
  28. 28. 28 export const path = (route) => { return '/'.concat(routes[route].path || ''); } <Link to="/">Home</Link> <Link to={ path('ExampleRoute') }>Example</Link> <Link to={ path('NestedExampleRoute') }>Nested Example</Link> routes.js react component
  29. 29. 29 import React from 'react'; import { render } from 'react-dom'; import Router from 'react-router'; import history from 'history/lib/createBrowserHistory'; import routes from './components/routes'; render(( <Router history={ history() }> { routes } </Router> ), document); browser.js
  30. 30. 30 let’s make a tool out of this
  31. 31. 31 problems to solve
  32. 32. 32 3. dev server that watches and reloads 2. copy file structure defaults to consumer 1. find CLI tool
  33. 33. 33 1. find CLI tool 3. dev server that watches and reloads 2. copy file structure defaults to consumer
  34. 34. 34 commander (is so badass) 34
  35. 35. 3535
  36. 36. 36 1. create CLI 3. dev server that watches and reloads 2. copy file structure defaults to consumer
  37. 37. 37 #!/usr/bin/env node import program from ‘commander'; program .command('new [path]') .description('create a new react-static project') .action(function handleNew(path, options) { if (path) { // copy over defaults } else { // handle no path } }); $ react-static new portfolio/
  38. 38. 38 1. create CLI 3. dev server that watches and reloads 2. copy file structure defaults to consumer
  39. 39. 39 nodemon + express
  40. 40. 40 program .command('serve') .description('run the dev server and have it watch for changes') .action(function handleServe() { execSync('node_modules/.bin/nodemon', { stdio: [0,1,2] }); }); $ react-static serve // build HTML & JS & then... const app = express(); app.use('/', express.static('_site')); app.listen(port); console.log(`=> A development server is running at http:// localhost:${port}`);
  41. 41. 41 you can make this on your own or…
  42. 42. 42
  43. 43. 43 [video demo]
  44. 44. 44 find problems with react-static & help make some people’s lives a bit easier
  45. 45. react-static npmjs.org/react-static github.com/rpearce @RobertWPearce The Iron Yard 45

×