Skip to content

Commit 51bbd39

Browse files
committed
Prepare for SSR lambda deployment
1 parent a08189f commit 51bbd39

File tree

7 files changed

+198
-22
lines changed

7 files changed

+198
-22
lines changed

config/paths.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ module.exports = {
8181
appNodeModules: resolveApp('node_modules'),
8282
publicUrl: getPublicUrl(resolveApp('package.json')),
8383
servedPath: getServedPath(resolveApp('package.json')),
84-
ssrIndexJs: resolveApp('src/index.server.tsx'),
84+
ssrIndexJs: resolveApp('src/index.server.ts'),
8585
ssrBuild: resolveApp('dist'),
8686
};
8787

config/webpack.config.lambda.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
const nodeExternals = require('webpack-node-externals');
2+
const paths = require('./paths');
3+
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
4+
const webpack = require('webpack');
5+
const getClientEnvironment = require('./env');
6+
const cssRegex = /\.css$/;
7+
const cssModuleRegex = /\.module\.css$/;
8+
const sassRegex = /\.(scss|sass)$/;
9+
const sassModuleRegex = /\.module\.(scss|sass)$/;
10+
const path = require('path');
11+
12+
const imageInlineSizeLimit = parseInt(
13+
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000',
14+
);
15+
16+
const publicUrl = paths.servedPath.slice(0, -1);
17+
const env = getClientEnvironment(publicUrl);
18+
19+
module.exports = {
20+
mode: 'production',
21+
entry: paths.ssrIndexJs,
22+
target: 'node',
23+
output: {
24+
path: paths.ssrBuild,
25+
filename: 'server.js',
26+
publicPath: paths.servedPath,
27+
},
28+
module: {
29+
rules: [
30+
{
31+
oneOf: [
32+
{
33+
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
34+
loader: require.resolve('url-loader'),
35+
options: {
36+
limit: imageInlineSizeLimit,
37+
name: 'static/media/[name].[hash:8].[ext]',
38+
emitFile: false,
39+
},
40+
},
41+
{
42+
test: /\.(js|mjs|jsx|ts|tsx)$/,
43+
include: paths.appSrc,
44+
loader: require.resolve('babel-loader'),
45+
options: {
46+
customize: require.resolve(
47+
'babel-preset-react-app/webpack-overrides',
48+
),
49+
50+
plugins: [
51+
[
52+
require.resolve('babel-plugin-named-asset-import'),
53+
{
54+
loaderMap: {
55+
svg: {
56+
ReactComponent:
57+
'@svgr/webpack?-svgo,+titleProp,+ref![path]',
58+
},
59+
},
60+
},
61+
],
62+
],
63+
cacheDirectory: true,
64+
cacheCompression: false,
65+
compact: false,
66+
},
67+
},
68+
{
69+
test: cssRegex,
70+
exclude: cssModuleRegex,
71+
loader: require.resolve('css-loader'),
72+
options: {
73+
onlyLocals: true,
74+
},
75+
},
76+
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
77+
// using the extension .module.css
78+
{
79+
test: cssModuleRegex,
80+
loader: require.resolve('css-loader'),
81+
options: {
82+
onlyLocals: true,
83+
module: true,
84+
getLocalIdent: getCSSModuleLocalIdent,
85+
},
86+
},
87+
{
88+
test: sassRegex,
89+
exclude: sassModuleRegex,
90+
use: [
91+
{
92+
loader: require.resolve('css-loader'),
93+
options: {
94+
onlyLocals: true,
95+
},
96+
},
97+
require.resolve('sass-loader'),
98+
],
99+
},
100+
{
101+
test: sassModuleRegex,
102+
use: [
103+
{
104+
loader: require.resolve('css-loader'),
105+
options: {
106+
onlyLocals: true,
107+
module: true,
108+
getLocalIdent: getCSSModuleLocalIdent,
109+
},
110+
},
111+
require.resolve('sass-loader'),
112+
],
113+
},
114+
{
115+
loader: require.resolve('file-loader'),
116+
// Exclude `js` files to keep "css" loader working as it injects
117+
// its runtime that would otherwise be processed through "file" loader.
118+
// Also exclude `html` and `json` extensions so they get processed
119+
// by webpacks internal loaders.
120+
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
121+
options: {
122+
emitFile: false,
123+
name: 'static/media/[name].[hash:8].[ext]',
124+
},
125+
},
126+
],
127+
},
128+
],
129+
},
130+
resolve: {
131+
modules: ['node_modules'],
132+
extensions: paths.moduleFileExtensions
133+
.map(ext => `.${ext}`)
134+
.filter(ext => true || !ext.includes('ts')),
135+
},
136+
plugins: [
137+
new webpack.DefinePlugin(env.stringified),
138+
new webpack.NormalModuleReplacementPlugin(
139+
/codemirror/,
140+
path.resolve(paths.appSrc, 'lib/replacedModule.ts'),
141+
),
142+
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
143+
],
144+
optimization: {
145+
minimize: false,
146+
},
147+
externals: [
148+
nodeExternals({
149+
whitelist: [/codemirror/, /\.css$/],
150+
}),
151+
],
152+
node: {
153+
__dirname: false,
154+
},
155+
};

config/webpack.config.server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ module.exports = {
2323
output: {
2424
path: paths.ssrBuild,
2525
filename: 'server.js',
26-
chunkFilename: 'js/[name].chunk.js',
2726
publicPath: paths.servedPath,
2827
},
2928
module: {
@@ -140,6 +139,7 @@ module.exports = {
140139
/codemirror/,
141140
path.resolve(paths.appSrc, 'lib/replacedModule.ts'),
142141
),
142+
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
143143
],
144144
optimization: {
145145
minimize: false,

src/index.server.tsx renamed to src/index.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Koa from 'koa';
22
import path from 'path';
33
import serve from 'koa-static';
4-
import serverRender from './server/serverRender';
54
import proxy from 'koa-better-http-proxy';
65
import Router from '@koa/router';
6+
import ssrMiddleware from './server/ssrMiddleware';
77

88
console.log(process.env.REACT_APP_SSR);
99

@@ -19,7 +19,7 @@ app.use(
1919
const proxyMiddleware = proxy('localhost', { port: 5000 });
2020
app.use(router.routes()).use(router.allowedMethods());
2121

22-
app.use(serverRender);
22+
app.use(ssrMiddleware);
2323
app.use(proxyMiddleware);
2424
// router.post('/graphql', proxyMiddleware);
2525

src/server/serverRender.tsx

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,26 @@ import CacheManager from './CacheManager';
2121
const statsFile = path.resolve(__dirname, '../build/loadable-stats.json');
2222
const cacheManager = new CacheManager();
2323

24-
const serverRender: Middleware = async (ctx, next) => {
24+
type SSROption = {
25+
url: string;
26+
loggedIn: boolean;
27+
cookie: string;
28+
};
29+
30+
const serverRender = async ({ url, loggedIn, cookie }: SSROption) => {
2531
// enable proxy to backend server in development mode
26-
if (/^\/(api|graphql)/.test(ctx.path)) {
27-
return next();
32+
if (/^\/(api|graphql)/.test(url)) {
33+
return null;
2834
}
2935

3036
// prepare redux store
3137
const store = createStore(rootReducer);
3238
// prepare apollo client
3339

34-
const loggedIn = !!(
35-
ctx.cookies.get('refresh_token') || ctx.cookies.get('access_token')
36-
);
37-
3840
if (!loggedIn) {
39-
const cachedPage = await cacheManager.get(ctx.url);
41+
const cachedPage = await cacheManager.get(url);
4042
if (cachedPage) {
41-
ctx.body = cachedPage;
42-
return;
43+
return cachedPage;
4344
}
4445
}
4546

@@ -49,7 +50,7 @@ const serverRender: Middleware = async (ctx, next) => {
4950
uri: 'http://localhost:5000/graphql',
5051
fetch: fetch as any,
5152
headers: {
52-
cookie: ctx.headers.cookie,
53+
cookie,
5354
},
5455
}),
5556
cache: new InMemoryCache(),
@@ -64,7 +65,7 @@ const serverRender: Middleware = async (ctx, next) => {
6465
<StyleSheetManager sheet={sheet.instance}>
6566
<Provider store={store}>
6667
<ApolloProvider client={client}>
67-
<StaticRouter location={ctx.url} context={context}>
68+
<StaticRouter location={url} context={context}>
6869
<App />
6970
</StaticRouter>
7071
</ApolloProvider>
@@ -76,9 +77,7 @@ const serverRender: Middleware = async (ctx, next) => {
7677
try {
7778
await getDataFromTree(Root);
7879
} catch (e) {
79-
console.log(e);
80-
ctx.throw(500);
81-
return;
80+
throw e;
8281
}
8382

8483
const content = ReactDOMServer.renderToString(Root);
@@ -99,13 +98,13 @@ const serverRender: Middleware = async (ctx, next) => {
9998
html,
10099
)}`;
101100

102-
ctx.body = pageHtml;
103-
104101
setImmediate(() => {
105102
if (!loggedIn) {
106-
cacheManager.set(ctx.url, pageHtml);
103+
cacheManager.set(url, pageHtml);
107104
}
108105
});
106+
107+
return pageHtml;
109108
};
110109

111110
export default serverRender;

src/server/ssrMiddleware.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Middleware } from 'koa';
2+
import serverRender from './serverRender';
3+
4+
const ssrMiddleware: Middleware = async (ctx, next) => {
5+
try {
6+
const html = await serverRender({
7+
url: ctx.url,
8+
cookie: ctx.headers.cookie,
9+
loggedIn: !!(
10+
ctx.cookies.get('refresh_token') || ctx.cookies.get('access_token')
11+
),
12+
});
13+
if (!html) {
14+
return next();
15+
}
16+
ctx.body = html;
17+
} catch (e) {
18+
ctx.throw(500, e);
19+
}
20+
};
21+
22+
export default ssrMiddleware;

src/serverless.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)