Last active
October 17, 2017 20:11
-
-
Save smontlouis/769a532ed191d8f366fd26fdec7b95a2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import glamorous from 'glamorous' | |
const Row = glamorous.div(({ extended }) => ({ // THIS IS OK | |
position: 'relative', | |
maxWidth: extended ? 1330 : 1200, | |
margin: '0 auto', | |
boxsizing: 'border-box', | |
display: 'flex', | |
flexDirection: 'row', | |
flexWrap: 'wrap', | |
})) | |
const Row = glamorous('div')(({ extended }) => ({ // THIS IS NOT OK | |
position: 'relative', | |
maxWidth: extended ? 1330 : 1200, | |
margin: '0 auto', | |
boxsizing: 'border-box', | |
display: 'flex', | |
flexDirection: 'row', | |
flexWrap: 'wrap', | |
})) | |
export default Row |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* THIS IS THE ENTRY POINT FOR THE CLIENT, JUST LIKE server.js IS THE ENTRY POINT FOR THE SERVER. | |
*/ | |
import 'babel-polyfill'; | |
import React from 'react'; | |
import ReactDOM from 'react-dom'; | |
... | |
// -- rehydrating styles | |
import { rehydrate } from 'glamor' | |
rehydrate(window._glam) | |
import getRoutes from './routes'; | |
const client = new ApiClient(); | |
const dest = document.getElementById('content'); | |
const store = createStore(browserHistory, client, window.__data); // Fuck scroll history | |
if (__DEVTOOLS__ && !window.devToolsExtension) { | |
const DevTools = require('./containers/DevTools/DevTools'); | |
component = ( | |
<div style={{display: 'flex', flexDirection: 'column'}}> | |
{component} | |
<DevTools /> | |
</div> | |
); | |
} | |
const renderApp = (routes) => { | |
ReactDOM.render( | |
<AppContainer> | |
<Provider store={store} key="provider"> | |
<Router | |
// onUpdate={logPageView} | |
render={(props) => | |
<ReduxAsyncConnect {...props} helpers={{client}} filter={item => !item.deferred} render={ | |
applyRouterMiddleware(useScroll((prevRouterProps, routerProps) => { | |
if (!prevRouterProps) return true; | |
return routerProps.location.pathname !== prevRouterProps.location.pathname; | |
} | |
))} | |
/> | |
} | |
history={browserHistory}> | |
{routes} | |
</Router> | |
</Provider> | |
</AppContainer>, | |
dest | |
) | |
} | |
if (process.env.NODE_ENV !== 'production') { | |
window.React = React; // enable debugger | |
if (!dest || !dest.firstChild || !dest.firstChild.attributes || !dest.firstChild.attributes['data-react-checksum']) { | |
console.error('Server-side React render was discarded. Make sure that your initial render does not contain any client-side code.'); | |
} | |
} | |
renderApp(getRoutes(store)); | |
if (module.hot) { | |
module.hot.accept('./routes', () => { | |
const getRoutes = require('./routes').default; | |
renderApp(getRoutes(store)); | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import PropTypes from 'prop-types'; | |
import React from 'react'; | |
import { ThemeProvider } from 'glamorous'; | |
import theme from 'ui/theme' | |
... | |
const styles = require('./App.scss'); | |
const cx = require('classnames/bind').bind(styles); | |
@asyncConnect([{ | |
/*...*/ | |
} | |
}]) | |
@connect( | |
/* ... */ | |
) | |
@withRouter | |
export default class App extends Component { | |
static propTypes = { | |
... | |
}; | |
componentDidMount() { | |
} | |
componentWillReceiveProps(nextProps) { | |
} | |
componentDidUpdate(prevProps) { | |
} | |
checkNotFoundError() { | |
} | |
renderRouting() { | |
} | |
render() { | |
// Using themeProvider | |
return ( | |
<ThemeProvider theme={theme}> | |
<Body isDisabled={hasMenuOpened}> | |
<div id="App" className={AppClasses}> | |
<Helmet {...config.app.head}/> | |
<Nav | |
isOpened={hasMenuOpened} | |
isLogged={isLogged} | |
onClickMenu={toggleMenu} | |
menuLastCampaigns={menuLastCampaigns} | |
megaMenu={megaMenu} | |
/> | |
<div className={AppContentClasses} id="main"> | |
<div className={styles.MobileSubHeader}> | |
<Link to="/agir"> | |
Agir | |
</Link> | |
<a target="_blank" href="https://soutenir.amnesty.fr/b?cid=54&reserved_originecode=WBF01W1010"> | |
Faire un don | |
</a> | |
</div> | |
<BandeauAlerte | |
item={bandeauAlerte} | |
location={location} | |
/> | |
<ReactCSSTransitionGroup | |
component="div" | |
transitionAppear | |
transitionName={this.props.location.action === 'PUSH' ? 'next' : 'prev'} | |
transitionAppearTimeout={5} | |
transitionEnterTimeout={5} | |
transitionLeaveTimeout={5} | |
> | |
{this.renderRouting()} | |
</ReactCSSTransitionGroup> | |
</div> | |
<Footer /> | |
<CookieContainer /> | |
</div> | |
</Body> | |
</ThemeProvider> | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import express from 'express'; | |
import React from 'react'; | |
import ReactDOM from 'react-dom/server'; | |
import Config from 'config'; | |
const config = Config.get('server'); | |
import createStore from './redux/create'; | |
import ApiClient from 'helpers/ApiClient'; | |
import Html from 'helpers/Html'; | |
import { match } from 'react-router'; | |
import { ReduxAsyncConnect, loadOnServer } from 'redux-connect'; | |
import createHistory from 'react-router/lib/createMemoryHistory'; | |
import {Provider} from 'react-redux'; | |
import getRoutes from './routes'; | |
const app = express.Router(); | |
app.use((req, res, next) => { | |
if (__DEVELOPMENT__) { | |
webpackIsomorphicTools.refresh(); | |
} | |
const client = new ApiClient({ req }); | |
const history = createHistory(req.originalUrl); | |
const isMobile = ['phone', 'tablet'].indexOf(req.device.type) > -1; | |
const initialState = { | |
...(req.initialState || {}), | |
layout: { | |
isMobile, | |
host: config.host, | |
}, | |
user: { | |
...req.user, | |
isAuthenticated: req.user ? true : false, | |
} | |
}; | |
const store = createStore(history, client, initialState); | |
function hydrateOnClient() { | |
res.send('<!doctype html>\n' + | |
ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store}/>)); | |
} | |
if (__DISABLE_SSR__) { | |
hydrateOnClient(); | |
return; | |
} | |
match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { | |
if (redirectLocation) { | |
res.redirect(redirectLocation.pathname + redirectLocation.search); | |
} else if (error) { | |
res.status(500); | |
hydrateOnClient(); | |
} else if (renderProps) { | |
loadOnServer({...renderProps, store, helpers: {client}}).then(() => { | |
renderProps.coucou = 'cazdazd'; | |
const component = ( | |
<Provider store={store} key="provider"> | |
<ReduxAsyncConnect {...renderProps} /> | |
</Provider> | |
); | |
global.navigator = {userAgent: req.headers['user-agent']}; | |
const render = '<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>); | |
const { | |
layout: { | |
error: finalError | |
}, | |
routing: { | |
location: { | |
pathname: finalPathname | |
} | |
} | |
} = store.getState(); | |
if (finalPathname === '/404' || finalError && finalError.get('status') === 404) { | |
res.status('404'); | |
} else { | |
res.status(200); | |
} | |
res.send(render); | |
}) | |
.catch(err => { | |
next(err); | |
}); | |
} else { | |
res.status(404).send('Not found'); | |
} | |
}); | |
}); | |
export default app; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import PropTypes from 'prop-types'; | |
import React, { Component } from 'react'; | |
import ReactDOM from 'react-dom/server'; | |
import serialize from 'serialize-javascript'; | |
import Helmet from 'react-helmet'; | |
import Config from 'config'; | |
import { renderStatic } from 'glamor/server' | |
const config = Config.get('api'); | |
export default class Html extends Component { | |
static propTypes = { | |
assets: PropTypes.object, | |
component: PropTypes.node, | |
store: PropTypes.object | |
} | |
render() { | |
const {assets, component, store} = this.props; | |
// RenderStatic glamor/server here | |
let { html, css, ids } = component ? renderStatic(() => ReactDOM.renderToString(component)) : { html: '', css: '', ids: '' } | |
const head = Helmet.rewind(); | |
return ( | |
<html lang="fr"> | |
<head> | |
{head.base.toComponent()} | |
{head.title.toComponent()} | |
{head.meta.toComponent()} | |
{head.link.toComponent()} | |
{head.script.toComponent()} | |
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico" /> | |
<link rel="apple-touch-icon" sizes="57x57" href="/assets/images/favicon/apple-icon-57x57.png" /> | |
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/apple-icon-60x60.png" /> | |
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/apple-icon-72x72.png" /> | |
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/apple-icon-76x76.png" /> | |
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/apple-icon-114x114.png" /> | |
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/apple-icon-120x120.png" /> | |
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/apple-icon-144x144.png" /> | |
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/apple-icon-152x152.png" /> | |
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/apple-icon-180x180.png" /> | |
<link rel="icon" type="image/png" sizes="192x192" href="/assets/images/favicon/android-icon-192x192.png" /> | |
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32x32.png" /> | |
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96x96.png" /> | |
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16x16.png" /> | |
<link rel="manifest" href="/assets/images/favicon/manifest.json" /> | |
<meta name="msapplication-TileImage" content="/assets/images/favicon/ms-icon-144x144.png" /> | |
{/* <meta name="msapplication-TileColor" content="#ffff00" /> */} | |
{/* <meta name="theme-color" content="#ffff00" /> */} | |
{/* <meta name="apple-mobile-web-app-status-bar-style" content="#ffff00" /> */} | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
{/* styles (will be present only in production with webpack extract text plugin) */} | |
{Object.keys(assets.styles).map((style, key) => | |
<link href={assets.styles[style]} key={key} media="screen, projection, print" | |
rel="stylesheet" type="text/css" charSet="UTF-8"/> | |
)} | |
<style dangerouslySetInnerHTML={{ __html: css }} /> | |
{ Object.keys(assets.styles).length === 0 ? <style dangerouslySetInnerHTML={{__html: require('containers/App/App.scss')._style}}/> : null } | |
</head> | |
<body> | |
<a className="a11y" href="#main">Accéder au contenu</a> | |
<div id="content" dangerouslySetInnerHTML={{__html: html}}/> | |
<script async src={assets.javascript.main} charSet="UTF-8"/> | |
<script defer src="/assets/prismic.js" /> | |
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.10/clipboard.min.js" async></script> | |
// Inject ids here | |
<script dangerouslySetInnerHTML={{__html: `window._glam = ${JSON.stringify(ids)};`}} charSet="UTF-8"/> | |
<script dangerouslySetInnerHTML={{__html: `window.__data=${serialize(store.getState())};`}} charSet="UTF-8"/> | |
<script dangerouslySetInnerHTML={{__html: `window.prismic = {endpoint: "${config.Prismic.api.url}"};`}} charSet="UTF-8"/> | |
<script dangerouslySetInnerHTML={{__html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-MBQ25R');`}} charSet="UTF-8"/> | |
{/* <script src="/assets/ga.js"/> */} | |
</body> | |
</html> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment