Playing around with SSR

This commit is contained in:
Tom Raithel
2017-02-19 23:34:28 +01:00
parent 856befc423
commit 4fd02cc52e
7 changed files with 265 additions and 41 deletions

View File

@@ -1,3 +1,3 @@
{ {
"presets": ["latest", "stage-0"] "presets": ["latest", "stage-0", "react"]
} }

140
components/App.js Normal file
View File

@@ -0,0 +1,140 @@
import React from 'react';
import { connect } from 'react-redux';
function App({ items, releses, pageName }) {
return (
<div className="js--body">
<div className="page">
<div className="page__header">
<div className="branding">
<a className="branding__logo" href="/"><img src="/assets/logo.svg"/></a>
<div className="branding__content">
<div className="nav">
<div className="nav__item"><a className="icon-link" href="/howto.html"><span className="icon icon--question icon-link__icon"></span>How to Use Technology Radar?</a></div>
<div className="nav__item"><a className="icon-link" href="/overview.html"><span className="icon icon--overview icon-link__icon"></span>Technologies Overview</a></div>
<div className="nav__item"><a className="icon-link" href="#todo"><span className="icon icon--search icon-link__icon"></span>Search</a></div>
</div>
</div>
</div>
</div>
<div className="page__content">
<div className="headline-group">
<div className="hero-headline">Technology Radar<span className="hero-headline__alt"> Mar 2017</span></div>
</div>
<div className="quadrant-grid">
<div className="quadrant-grid__quadrant">
<div className="quadrant-section">
<div className="quadrant-section__header">
<div className="split">
<div className="split__left">
<h4 className="headline">Platforms and AOE Services</h4>
</div>
<div className="split__right"><a className="icon-link" href="/platforms-and-aoe-services.html"><span className="icon icon--pie icon-link__icon"></span>Quadrant Overview</a></div>
</div>
</div>
<div className="quadrant-section__rings">
<div className="quadrant-section__ring">
<div className="ring-list">
<div className="ring-list__header"><span className="badge badge--assess">assess</span></div>
<span className="ring-list__item"><a className="link" href="/platforms-and-aoe-services/bar.html">Bar</a></span>
</div>
</div>
</div>
</div>
</div>
<div className="quadrant-grid__quadrant">
<div className="quadrant-section">
<div className="quadrant-section__header">
<div className="split">
<div className="split__left">
<h4 className="headline">Methods &amp; Patterns</h4>
</div>
<div className="split__right"><a className="icon-link" href="/methods-and-patterns.html"><span className="icon icon--pie icon-link__icon"></span>Quadrant Overview</a></div>
</div>
</div>
<div className="quadrant-section__rings">
<div className="quadrant-section__ring">
<div className="ring-list">
<div className="ring-list__header"><span className="badge badge--trial">trial</span></div>
<span className="ring-list__item"><a className="link" href="/methods-and-patterns/foo.html">Foo</a></span>
</div>
</div>
</div>
</div>
</div>
<div className="quadrant-grid__quadrant">
<div className="quadrant-section">
<div className="quadrant-section__header">
<div className="split">
<div className="split__left">
<h4 className="headline">Tools</h4>
</div>
<div className="split__right"><a className="icon-link" href="/tools.html"><span className="icon icon--pie icon-link__icon"></span>Quadrant Overview</a></div>
</div>
</div>
<div className="quadrant-section__rings">
<div className="quadrant-section__ring">
<div className="ring-list">
<div className="ring-list__header"><span className="badge badge--hold">hold</span></div>
<span className="ring-list__item"><a className="link" href="/tools/grunt.html">Grunt 2</a></span>
</div>
</div>
</div>
</div>
</div>
<div className="quadrant-grid__quadrant">
<div className="quadrant-section">
<div className="quadrant-section__header">
<div className="split">
<div className="split__left">
<h4 className="headline">Languages &amp; Frameworks</h4>
</div>
<div className="split__right"><a className="icon-link" href="/languages-and-frameworks.html"><span className="icon icon--pie icon-link__icon"></span>Quadrant Overview</a></div>
</div>
</div>
<div className="quadrant-section__rings">
<div className="quadrant-section__ring">
<div className="ring-list">
<div className="ring-list__header"><span className="badge badge--trial">trial</span></div>
<span className="ring-list__item"><a className="link" href="/languages-and-frameworks/react.html">React</a></span>
</div>
</div>
<div className="quadrant-section__ring">
<div className="ring-list">
<div className="ring-list__header"><span className="badge badge--assess">assess</span></div>
<span className="ring-list__item"><a className="link" href="/languages-and-frameworks/react123.html">This is a long title</a></span><span className="ring-list__item"><a className="link" href="/languages-and-frameworks/vue123.html">Vue 123</a></span>
</div>
</div>
<div className="quadrant-section__ring">
<div className="ring-list">
<div className="ring-list__header"><span className="badge badge--adopt">adopt</span></div>
<span className="ring-list__item"><a className="link" href="/languages-and-frameworks/vue.html">Vue</a></span>
</div>
</div>
<div className="quadrant-section__ring">
<div className="ring-list">
<div className="ring-list__header"><span className="badge badge--hold">hold</span></div>
<span className="ring-list__item"><a className="link" href="/languages-and-frameworks/vue1230.html">Something else</a></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="page__footer">
<div className="branding">
<span className="branding__logo"><img src="/assets/logo.svg"/></span>
<div className="branding__content"><span className="footnote">AOE is a leading provider of Enterprise Open Source web solutions.
Using current agile development methods, more than 250+ developers
and consultants in 8 global locations develop customized Open Source
solutions for global companies and corporations.</span>
</div>
</div>
</div>
</div>
</div>
)
}
export default connect(({ items, releases, pageName }) => ({ items, releases, pageName }))(App);

View File

@@ -22,6 +22,7 @@
"babel-cli": "6.22.2", "babel-cli": "6.22.2",
"babel-loader": "6.2.10", "babel-loader": "6.2.10",
"babel-preset-latest": "6.22.0", "babel-preset-latest": "6.22.0",
"babel-preset-react": "6.23.0",
"babel-preset-stage-0": "6.22.0", "babel-preset-stage-0": "6.22.0",
"front-matter": "2.1.2", "front-matter": "2.1.2",
"fs-extra": "2.0.0", "fs-extra": "2.0.0",
@@ -34,6 +35,10 @@
"postcss-easy-import": "2.0.0", "postcss-easy-import": "2.0.0",
"postcss-nested": "1.0.0", "postcss-nested": "1.0.0",
"pug": "2.0.0-beta9", "pug": "2.0.0-beta9",
"react": "15.4.2",
"react-dom": "15.4.2",
"react-redux": "5.0.2",
"redux": "3.6.0",
"vue": "2.1.10", "vue": "2.1.10",
"walk": "2.3.9", "walk": "2.3.9",
"webpack": "2.2.0" "webpack": "2.2.0"

0
react/index.js Normal file
View File

View File

@@ -4,17 +4,18 @@ import {
outputRadar, outputRadar,
} from './radar'; } from './radar';
import { import {
createStatic, renderApp,
} from './static'; } from './static';
(async () => { (async () => {
try { try {
const radar = await createRadar(); const radar = await createRadar();
outputRadar(radar); renderApp(radar, 'index');
// outputRadar(radar);
// const radarByQuadrants = groupByQuadrants(radar); // const radarByQuadrants = groupByQuadrants(radar);
createStatic(radar); // createStatic(radar);
console.log('Built radar'); console.log('Built radar');
// console.log(JSON.stringify(radar, null, 2)); // console.log(JSON.stringify(radar, null, 2));

View File

@@ -1,42 +1,78 @@
import { outputFile } from 'fs-extra'; import { outputFile } from 'fs-extra';
import pug from 'pug'; import React from 'react';
import frontmatter from 'front-matter'; import { renderToString } from 'react-dom/server';
import marked from 'marked'; import { createStore } from 'redux';
import { import { Provider } from 'react-redux';
staticPath,
distPath,
getAllPugFiles,
} from './file';
import {
vars,
} from './template';
export const createStatic = async (radar) => { import { distPath } from './file';
const paths = await getAllPugFiles(staticPath()); import App from '../components/App';
const fileNames = getPlainFileNames(paths);
return renderStaticPages(radar, fileNames);
return fileNames;
};
const getPlainFileNames = (paths) => ( const appReducer = (state = {}, action) => {
paths.map((fileName) => { return state;
const [ nameWithSuffix ] = fileName.split('/').slice(-1); }
return nameWithSuffix.substr(0, nameWithSuffix.length - 4);
})
)
const renderStaticPages = (radar, fileNames) => ( export const renderApp = (radar, pageName) => {
Promise.all(fileNames.map((name) => ( // Create a new Redux store instance
new Promise((resolve, reject) => ( const store = createStore(appReducer, {
outputFile(distPath(`${name}.html`), pug.renderFile(staticPath(`${name}.pug`), vars({ ...radar,
...radar, pageName
})), (err, data) => { });
if (err) {
reject(err); // Render the component to a string
} else { const html = renderToString(
resolve(data); <Provider store={store}>
} <App />
}) </Provider>
)) )
)))
// Grab the initial state from our Redux store
const preloadedState = store.getState()
// Send the rendered page back to the client
const fullHtml = renderFullPage(html, preloadedState);
// Save file
save(fullHtml, pageName);
}
const renderFullPage = (html, preloadedState) => {
return `
<html>
<head>
<title>AOE Technology Radar - AOE Tech Radar</title>
<link rel="stylesheet" href="/styles.css"/>
</head>
<body>
<div id="root">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}
</script>
<script src="/bundle.js"></script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>Redux Universal Example</title>
</head>
<body>
<script src="/static/bundle.js"></script>
</body>
</html>
`
}
const save = (html, pageName) => (
new Promise((resolve, reject) => (
outputFile(distPath(`${pageName}.html`), html, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
})
))
); );

42
tasks/static2.js Normal file
View File

@@ -0,0 +1,42 @@
import { outputFile } from 'fs-extra';
import pug from 'pug';
import frontmatter from 'front-matter';
import marked from 'marked';
import {
staticPath,
distPath,
getAllPugFiles,
} from './file';
import {
vars,
} from './template';
export const createStatic = async (radar) => {
const paths = await getAllPugFiles(staticPath());
const fileNames = getPlainFileNames(paths);
return renderStaticPages(radar, fileNames);
return fileNames;
};
const getPlainFileNames = (paths) => (
paths.map((fileName) => {
const [ nameWithSuffix ] = fileName.split('/').slice(-1);
return nameWithSuffix.substr(0, nameWithSuffix.length - 4);
})
)
const renderStaticPages = (radar, fileNames) => (
Promise.all(fileNames.map((name) => (
new Promise((resolve, reject) => (
outputFile(distPath(`${name}.html`), pug.renderFile(staticPath(`${name}.pug`), vars({
...radar,
})), (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
})
))
)))
);