From 006ece5fe4628d483f42492e0075db1eec21982d Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Thu, 31 Jan 2019 20:49:13 -0500 Subject: [PATCH 1/3] Check in WIP --- frontend/.env.example | 5 ++- frontend/client/Routes.tsx | 1 + frontend/config/webpack.config.js/loaders.js | 6 --- frontend/config/webpack.config.js/plugins.js | 22 ---------- frontend/server/components/HTML.tsx | 12 +++++- frontend/server/index.tsx | 6 +-- frontend/server/render.tsx | 43 ++++++++++++-------- 7 files changed, 44 insertions(+), 51 deletions(-) diff --git a/frontend/.env.example b/frontend/.env.example index eb4528ba..6999ad1c 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1,7 +1,7 @@ # Disable typescript checking for dev building (reduce build time & resource usage) NO_DEV_TS_CHECK=true -NODE_ENV=development +# NODE_ENV=development # Set the public host url (no trailing slash) PUBLIC_HOST_URL=https://grants.zfnd.org @@ -15,3 +15,6 @@ BACKEND_URL=http://localhost:5000 # Blockchain explorer to link to. Top for mainnet, bottom for testnet. # EXPLORER_URL="https://explorer.zcha.in/" EXPLORER_URL="https://testnet.zcha.in/" + +# Normally production runs with SSL, this disables that +DISABLE_SSL=true diff --git a/frontend/client/Routes.tsx b/frontend/client/Routes.tsx index 9a50557d..d3595661 100644 --- a/frontend/client/Routes.tsx +++ b/frontend/client/Routes.tsx @@ -13,6 +13,7 @@ import AuthRoute from 'components/AuthRoute'; import Template, { TemplateProps } from 'components/Template'; // wrap components in loadable...import & they will be split +// Make sure you specify chunkname! Must replace slashes with dashes. const opts = { fallback: }; const Home = loadable(() => import('pages/index'), opts); const Create = loadable(() => import('pages/create'), opts); diff --git a/frontend/config/webpack.config.js/loaders.js b/frontend/config/webpack.config.js/loaders.js index 303701cb..4f96a66e 100644 --- a/frontend/config/webpack.config.js/loaders.js +++ b/frontend/config/webpack.config.js/loaders.js @@ -4,12 +4,6 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const isDev = process.env.NODE_ENV === 'development'; -const babelPresets = [ - '@babel/react', - // '@babel/typescript', (using ts-loader) - ['@babel/env', { useBuiltIns: 'entry', modules: false }], -]; - const lessLoader = { loader: 'less-loader', options: { javascriptEnabled: true }, diff --git a/frontend/config/webpack.config.js/plugins.js b/frontend/config/webpack.config.js/plugins.js index 1ba29e89..c39e42f3 100644 --- a/frontend/config/webpack.config.js/plugins.js +++ b/frontend/config/webpack.config.js/plugins.js @@ -1,7 +1,6 @@ const webpack = require('webpack'); const path = require('path'); const ManifestPlugin = require('webpack-manifest-plugin'); -const { StatsWriterPlugin } = require('webpack-stats-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const ModuleDependencyWarning = require('./module-dependency-warning'); const WebappWebpackPlugin = require('webapp-webpack-plugin'); @@ -55,27 +54,6 @@ const client = [ }, }, ]), - // this allows the server access to the dependency graph - // so it can find which js/css to add to initial page - new StatsWriterPlugin({ - fileName: 'stats.json', - fields: null, - transform(data) { - const trans = {}; - trans.publicPath = data.publicPath; - trans.modules = data.modules.map(m => ({ - id: m.id, - chunks: m.chunks, - reasons: m.reasons, - })); - trans.chunks = data.chunks.map(c => ({ - id: c.id, - files: c.files, - origins: c.origins, - })); - return JSON.stringify(trans, null, 2); - }, - }), new LoadablePlugin(), ]; diff --git a/frontend/server/components/HTML.tsx b/frontend/server/components/HTML.tsx index 2194f253..89609e92 100644 --- a/frontend/server/components/HTML.tsx +++ b/frontend/server/components/HTML.tsx @@ -24,6 +24,16 @@ const HTML: React.SFC = ({ extractor, }) => { const head = Helmet.renderStatic(); + console.log(extractor); + console.log((extractor as any).chunks); + console.log((extractor as any).entrypoints); + try { + console.log('About to extract'); + console.log(extractor.getStyleTags()); + console.log(extractor.getStyleElements()); + } catch(err) { + console.log(err); + } return ( @@ -61,7 +71,7 @@ const HTML: React.SFC = ({ {extractor.getStyleElements()} {css.map(href => { - return ; + return ; })} {extractor.getScriptElements()} diff --git a/frontend/server/index.tsx b/frontend/server/index.tsx index 6f904886..57ae7e04 100644 --- a/frontend/server/index.tsx +++ b/frontend/server/index.tsx @@ -28,8 +28,8 @@ Sentry.init({ const app = express(); // ssl -if (!isDev) { - console.log('Enabling HTTPS redirect.'); +if (!isDev && !process.env.DISABLE_SSL) { + log.warn('PRODUCTION mode, enforcing HTTPS redirect'); app.use(enforce.HTTPS({ trustProtoHeader: true })); } @@ -51,7 +51,7 @@ if (isDev) { res.send(''); }); } else { - log.warn('PRODUCTION mode, serving static assets from node server.'); + log.warn('PRODUCTION mode, serving static assets from node server'); app.use( paths.publicPath, express.static(path.join(paths.clientBuild, paths.publicPath)), diff --git a/frontend/server/render.tsx b/frontend/server/render.tsx index bb7be32e..240fa6d2 100644 --- a/frontend/server/render.tsx +++ b/frontend/server/render.tsx @@ -6,6 +6,7 @@ import { ChunkExtractor } from '@loadable/server'; import { StaticRouter as Router } from 'react-router-dom'; import { Provider } from 'react-redux'; import { I18nextProvider } from 'react-i18next'; +import * as Sentry from '@sentry/node'; import log from './log'; import { configureStore } from '../client/store/configure'; @@ -53,11 +54,12 @@ const serverRenderer = () => async (req: Request, res: Response) => { const disp = `Error getting loadable state for SSR`; e.message = disp + ': ' + e.message; log.error(e); + Sentry.captureException(e); return res.status(500).send(disp + ' (more info in server logs)'); } // 2. render and collect state - const content = renderToString(reactApp); + const content = renderToString(extractor.collectChunks(reactApp)); const state = JSON.stringify(store.getState()); // ! ensure manifest.json is available @@ -66,7 +68,8 @@ const serverRenderer = () => async (req: Request, res: Response) => { } catch (e) { const disp = 'ERROR: Could not load client manifest.json, there was probably a client build error.'; - log.error(disp); + log.error(e); + Sentry.captureException(e); return res.status(500).send(disp); } @@ -83,22 +86,26 @@ const serverRenderer = () => async (req: Request, res: Response) => { .map(m => ({ ...m, content: res.locals.assetPath(m.content) })) .filter(m => !!m.content); - return res.send( - '' + - renderToString( - - {content} - , - ), - ); + try { + const html = renderToString( + + {content} + , + ); + return res.send('' + html); + } catch (e) { + log.error(e); + Sentry.captureException(e); + return res.send('ERROR: Failed to render app'); + } }; export default serverRenderer; From 33ac4db56430570603bd50e2c2c9369bd6b30772 Mon Sep 17 00:00:00 2001 From: Will O'Beirne Date: Thu, 31 Jan 2019 22:09:52 -0500 Subject: [PATCH 2/3] Fix SSR, fix uncaught async errors, fix style cascade. --- .../client/components/Proposals/style.less | 2 +- frontend/config/webpack.config.js/loaders.js | 2 - frontend/package.json | 3 - frontend/server/components/HTML.tsx | 14 +--- frontend/server/render.tsx | 76 +++++++------------ frontend/server/ssrAsync.ts | 17 +++++ frontend/yarn.lock | 9 +-- 7 files changed, 48 insertions(+), 75 deletions(-) diff --git a/frontend/client/components/Proposals/style.less b/frontend/client/components/Proposals/style.less index bf9e7b30..fb17174d 100644 --- a/frontend/client/components/Proposals/style.less +++ b/frontend/client/components/Proposals/style.less @@ -22,7 +22,7 @@ &-search { display: flex; - &-filterButton { + &-filterButton.ant-btn { display: none; margin-left: 0.5rem; diff --git a/frontend/config/webpack.config.js/loaders.js b/frontend/config/webpack.config.js/loaders.js index 4f96a66e..464fd680 100644 --- a/frontend/config/webpack.config.js/loaders.js +++ b/frontend/config/webpack.config.js/loaders.js @@ -16,7 +16,6 @@ const tsBabelLoaderClient = { loader: 'babel-loader', options: { plugins: [ - 'dynamic-import-webpack', // for client '@loadable/babel-plugin', 'react-hot-loader/babel', '@babel/plugin-proposal-object-rest-spread', @@ -40,7 +39,6 @@ const tsBabelLoaderServer = { loader: 'babel-loader', options: { plugins: [ - 'dynamic-import-node', // for server '@loadable/babel-plugin', '@babel/plugin-proposal-object-rest-spread', '@babel/plugin-proposal-class-properties', diff --git a/frontend/package.json b/frontend/package.json index 7dd0dca7..4a62a715 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -32,7 +32,6 @@ "@babel/core": "^7.0.1", "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-transform-modules-commonjs": "^7.0.0", "@babel/polyfill": "^7.0.0", "@babel/preset-env": "^7.0.0", @@ -74,8 +73,6 @@ "axios": "^0.18.0", "babel-core": "^7.0.0-bridge.0", "babel-loader": "^8.0.2", - "babel-plugin-dynamic-import-node": "^2.1.0", - "babel-plugin-dynamic-import-webpack": "^1.0.2", "babel-plugin-import": "^1.8.0", "babel-plugin-module-resolver": "^3.1.1", "bn.js": "4.11.8", diff --git a/frontend/server/components/HTML.tsx b/frontend/server/components/HTML.tsx index 89609e92..5c976eb8 100644 --- a/frontend/server/components/HTML.tsx +++ b/frontend/server/components/HTML.tsx @@ -24,16 +24,6 @@ const HTML: React.SFC = ({ extractor, }) => { const head = Helmet.renderStatic(); - console.log(extractor); - console.log((extractor as any).chunks); - console.log((extractor as any).entrypoints); - try { - console.log('About to extract'); - console.log(extractor.getStyleTags()); - console.log(extractor.getStyleElements()); - } catch(err) { - console.log(err); - } return ( @@ -69,12 +59,11 @@ const HTML: React.SFC = ({ {head.link.toComponent()} {head.script.toComponent()} - {extractor.getStyleElements()} {css.map(href => { return ; })} + {extractor.getStyleElements()} - {extractor.getScriptElements()}