Skip to content

Instantly share code, notes, and snippets.

@smontlouis
Last active October 17, 2017 20:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smontlouis/769a532ed191d8f366fd26fdec7b95a2 to your computer and use it in GitHub Desktop.
Save smontlouis/769a532ed191d8f366fd26fdec7b95a2 to your computer and use it in GitHub Desktop.
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 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));
});
}
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>
);
}
}
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;
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