Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"dependencies": {
"@babel/runtime": "^7.11.2",
"@formatjs/intl-relativetimeformat": "^4.2.1",
"@loadable/component": "^5.14.1",
"@loadable/server": "^5.14.0",
"@mapbox/polyline": "^1.1.1",
"@sentry/browser": "5.20.1",
"@sentry/node": "5.20.1",
Expand Down Expand Up @@ -57,7 +59,7 @@
"redux-thunk": "^2.3.0",
"seedrandom": "^3.0.5",
"sharetribe-flex-sdk": "1.13.0",
"sharetribe-scripts": "4.0.0",
"sharetribe-scripts": "4.0.0-alpha21",
"smoothscroll-polyfill": "^0.4.0",
"source-map-support": "^0.5.9",
"url": "^0.11.0"
Expand Down
3 changes: 3 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
<!-- End Favicons -->

<!--!link-->
<!--!ssrStyles-->
<!--!ssrLinks-->

<style>
/**
Expand Down Expand Up @@ -160,6 +162,7 @@
<script src="https://js.stripe.com/v3/"></script>
<!--!preloadedStateScript-->
<!--!script-->
<!--!ssrScripts-->

<!--
Note when adding new external scripts/styles/fonts/etc.:
Expand Down
24 changes: 12 additions & 12 deletions server/dataLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ const log = require('./log');

exports.loadData = function(requestUrl, sdk) {
const { pathname, query } = url.parse(requestUrl);
const matchedRoutes = matchPathname(pathname, routeConfiguration());
// const matchedRoutes = matchPathname(pathname, routeConfiguration());

const store = configureStore({}, sdk);

const dataLoadingCalls = matchedRoutes.reduce((calls, match) => {
const { route, params } = match;
if (typeof route.loadData === 'function' && !route.auth) {
calls.push(store.dispatch(route.loadData(params, query)));
}
return calls;
}, []);
// const store = configureStore({}, sdk);

// const dataLoadingCalls = matchedRoutes.reduce((calls, match) => {
// const { route, params } = match;
// if (typeof route.loadData === 'function' && !route.auth) {
// calls.push(store.dispatch(route.loadData(params, query)));
// }
// return calls;
// }, []);
const dataLoadingCalls = [];
return Promise.all(dataLoadingCalls)
.then(() => {
return store.getState();
return {};//store.getState();
})
.catch(e => {
log.error(e, 'server-side-data-load-failed');

// Call to loadData failed, let client handle the data loading errors.
// (It might be recoverable error like lost connection.)
// Return "empty" store.
return store.getState();
return {};//store.getState();
});
};
6 changes: 6 additions & 0 deletions server/importer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ const manifest = require(manifestPath);
const mainJsPath = path.join(buildPath, manifest['files']['main.js']);
const mainJs = require(mainJsPath);

console.log('mainJs', mainJs);
const nodeStats = path.join(buildPath,'node/loadable-stats.json');
const webStats = path.join(buildPath,'loadable-stats.json');

module.exports = {
renderApp: mainJs.default,
matchPathname: mainJs.matchPathname,
configureStore: mainJs.configureStore,
routeConfiguration: mainJs.routeConfiguration,
nodeStats,
webStats,
};
38 changes: 36 additions & 2 deletions server/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ const path = require('path');
const fs = require('fs');
const _ = require('lodash');
const { types } = require('sharetribe-flex-sdk');
const { renderApp } = require('./importer');
const { ChunkExtractor } = require('@loadable/server');
const { renderApp, nodeStats, webStats } = require('./importer');

const buildPath = path.resolve(__dirname, '..', 'build');

Expand Down Expand Up @@ -92,7 +93,37 @@ const replacer = (key = null, value) => {
};

exports.render = function(requestUrl, context, preloadedState) {
const { head, body } = renderApp(requestUrl, context, preloadedState);
const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats });
console.log('nodeStats:', nodeStats);

const nodeEntrypoint = nodeExtractor.requireEntrypoint();
console.log('nodeEntrypoint:', nodeEntrypoint);

const {
default: renderApp,
matchPathname,
configureStore,
routeConfiguration,
} = nodeEntrypoint;
console.log('nodeEntrypoint spread:', renderApp, matchPathname, configureStore, routeConfiguration);
console.log();
// console.log(JSON.stringify(nodeEntrypoint));

const webExtractor = new ChunkExtractor({ statsFile: webStats });
// const webEntrypoint = webExtractor.requireEntrypoint();
// console.log('webEntrypoint:', webEntrypoint);

const { head, body } = renderApp(requestUrl, context, preloadedState, webExtractor.collectChunks);
// const jsx = webExtractor.collectChunks(<App />);
// const body = ReactDOMServer.renderToString(jsx);

console.log('typeof body:', typeof body, '\nstart-of-body\n', body, '\nend-of-body');
console.log('head.title.toString()', head.title.toString());

console.log('webExtractor.getStyleTags():\n', webExtractor.getStyleTags());
console.log('webExtractor.getLinkTags():\n', webExtractor.getLinkTags());
console.log('webExtractor.getScriptTags():\n', webExtractor.getScriptTags());


// Preloaded state needs to be passed for client side too.
// For security reasons we ensure that preloaded state is considered as a string
Expand Down Expand Up @@ -133,6 +164,9 @@ exports.render = function(requestUrl, context, preloadedState) {
script: head.script.toString(),
preloadedStateScript,
googleAnalyticsScript,
ssrStyles: webExtractor.getStyleTags(),
ssrLinks: webExtractor.getLinkTags(),
ssrScripts: webExtractor.getScriptTags(),
body,
});
};
8 changes: 5 additions & 3 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,19 @@ ServerApp.propTypes = { url: string.isRequired, context: any.isRequired, store:
* - {String} body: Rendered application body of the given route
* - {Object} head: Application head metadata from react-helmet
*/
export const renderApp = (url, serverContext, preloadedState) => {
export const renderApp = (url, serverContext, preloadedState, collectChunks) => {
// Don't pass an SDK instance since we're only rendering the
// component tree with the preloaded store state and components
// shouldn't do any SDK calls in the (server) rendering lifecycle.
const store = configureStore(preloadedState);

const helmetContext = {};

const body = ReactDOMServer.renderToString(
<ServerApp url={url} context={serverContext} helmetContext={helmetContext} store={store} />
const WithChunks = collectChunks(
<ServerApp url={url} context={serverContext} helmetContext={helmetContext} store={store} />
);
console.log('WithChunks', WithChunks);
const body = ReactDOMServer.renderToString(WithChunks);
const { helmet: head } = helmetContext;
return { head, body };
};
4 changes: 2 additions & 2 deletions src/containers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export { default as ContactDetailsPage } from './ContactDetailsPage/ContactDetai
export { default as EditListingPage } from './EditListingPage/EditListingPage';
export { default as EmailVerificationPage } from './EmailVerificationPage/EmailVerificationPage';
export { default as InboxPage } from './InboxPage/InboxPage';
export { default as LandingPage } from './LandingPage/LandingPage';
// export { default as LandingPage } from './LandingPage/LandingPage';
export { default as ListingPage } from './ListingPage/ListingPage';
export { default as ManageListingsPage } from './ManageListingsPage/ManageListingsPage';
export { default as NotFoundPage } from './NotFoundPage/NotFoundPage';
Expand All @@ -19,7 +19,7 @@ export { default as ProfilePage } from './ProfilePage/ProfilePage';
export { default as ProfileSettingsPage } from './ProfileSettingsPage/ProfileSettingsPage';
export { default as SearchPage } from './SearchPage/SearchPage';
export { default as StaticPage } from './StaticPage/StaticPage';
export { default as StyleguidePage } from './StyleguidePage/StyleguidePage';
// export { default as StyleguidePage } from './StyleguidePage/StyleguidePage';
export { default as TermsOfServicePage } from './TermsOfServicePage/TermsOfServicePage';
export { default as TopbarContainer } from './TopbarContainer/TopbarContainer';
export { default as TransactionPage } from './TransactionPage/TransactionPage';
27 changes: 27 additions & 0 deletions src/index-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { renderApp } from './app';
import configureStore from './store';
import { matchPathname } from './util/routes';
import routeConfiguration from './routeConfiguration';
import config from './config';

// Show warning if CSP is not enabled
const CSP = process.env.REACT_APP_CSP;
const cspEnabled = CSP === 'block' || CSP === 'report';

if (CSP === 'report' && process.env.REACT_APP_ENV === 'production') {
console.warn(
'Your production environment should use CSP with "block" mode. Read more from: https://www.sharetribe.com/docs/ftw-security/how-to-set-up-csp-for-ftw/'
);
} else if (!cspEnabled) {
console.warn(
"CSP is currently not enabled! You should add an environment variable REACT_APP_CSP with the value 'report' or 'block'. Read more from: https://www.sharetribe.com/docs/ftw-security/how-to-set-up-csp-for-ftw/"
);
}

// Export the function for server side rendering.
export default renderApp;

// exporting matchPathname and configureStore for server side rendering.
// matchPathname helps to figure out which route is called and if it has preloading needs
// configureStore is used for creating initial store state for Redux after preloading
export { matchPathname, configureStore, routeConfiguration, config };
26 changes: 4 additions & 22 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import 'raf/polyfill';

import React from 'react';
import ReactDOM from 'react-dom';
import { loadableReady } from '@loadable/component';
import { createInstance, types as sdkTypes } from './util/sdkLoader';
import { ClientApp, renderApp } from './app';
import configureStore from './store';
Expand All @@ -43,6 +44,9 @@ const render = (store, shouldHydrate) => {
info
.then(() => {
store.dispatch(fetchCurrentUser());
return loadableReady();
})
.then(() => {
if (shouldHydrate) {
ReactDOM.hydrate(<ClientApp store={store} />, document.getElementById('root'));
} else {
Expand Down Expand Up @@ -105,25 +109,3 @@ if (typeof window !== 'undefined') {
};
}
}

// Show warning if CSP is not enabled
const CSP = process.env.REACT_APP_CSP;
const cspEnabled = CSP === 'block' || CSP === 'report';

if (CSP === 'report' && process.env.REACT_APP_ENV === 'production') {
console.warn(
'Your production environment should use CSP with "block" mode. Read more from: https://www.sharetribe.com/docs/ftw-security/how-to-set-up-csp-for-ftw/'
);
} else if (!cspEnabled) {
console.warn(
"CSP is currently not enabled! You should add an environment variable REACT_APP_CSP with the value 'report' or 'block'. Read more from: https://www.sharetribe.com/docs/ftw-security/how-to-set-up-csp-for-ftw/"
);
}

// Export the function for server side rendering.
export default renderApp;

// exporting matchPathname and configureStore for server side rendering.
// matchPathname helps to figure out which route is called and if it has preloading needs
// configureStore is used for creating initial store state for Redux after preloading
export { matchPathname, configureStore, routeConfiguration, config };
7 changes: 5 additions & 2 deletions src/routeConfiguration.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import loadable from '@loadable/component'
import {
AboutPage,
AuthenticationPage,
Expand All @@ -7,7 +8,7 @@ import {
EditListingPage,
EmailVerificationPage,
InboxPage,
LandingPage,
//LandingPage,
ListingPage,
ManageListingsPage,
NotFoundPage,
Expand All @@ -20,11 +21,13 @@ import {
ProfilePage,
ProfileSettingsPage,
SearchPage,
StyleguidePage,
TermsOfServicePage,
TransactionPage,
} from './containers';

const LandingPage = loadable(() => import(/* webpackChunkName: "LandingPage" */ './containers/LandingPage/LandingPage'));
const StyleguidePage = loadable(() => import(/* webpackChunkName: "StyleguidePage" */ './containers/StyleguidePage/StyleguidePage'));

// routeConfiguration needs to initialize containers first
// Otherwise, components will import form container eventually and
// at that point css bundling / imports will happen in wrong order.
Expand Down
Loading