-
Notifications
You must be signed in to change notification settings - Fork 1
/
config.js
167 lines (151 loc) · 6.11 KB
/
config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
const fs = require('fs');
const ipaddr = require('ipaddr.js');
const fetch = require('node-fetch');
const NodeCache = require('node-cache');
// We keep a cached copy of the site dictionary for performance. Default is 60 seconds.
const dictionaryCache = new NodeCache({ stdTTL: 60 });
/**
* The JSS application name defaults to providing part of the bundle path as well as the dictionary service endpoint.
* If not passed as an environment variable or set here, any application name exported from the bundle will be used instead.
*/
let appName = process.env.SITECORE_JSS_APP_NAME;
/**
* The server.bundle.js file from your pre-built JSS app
*/
const bundlePath = process.env.SITECORE_JSS_SERVER_BUNDLE || `./dist/${appName}/server.bundle`;
const serverBundle = require(bundlePath);
appName = appName || serverBundle.appName;
/**
* @type {ProxyConfig}
*/
const config = {
/**
* The require'd server.bundle.js file from your pre-built JSS app
*/
serverBundle,
/**
* apiHost: your Sitecore instance hostname that is the backend for JSS
* Should be https for production. Must be https to use SSC auth service,
* if supporting Sitecore authentication.
*/
apiHost: process.env.SITECORE_API_HOST || 'http://my.sitecore.host',
/**
* layoutServiceRoot: The path to layout service for the JSS application.
* Some apps, like advanced samples, use a custom LS configuration,
* e.g. /sitecore/api/layout/render/jss-advanced-react
*/
layoutServiceRoute:
process.env.SITECORE_LAYOUT_SERVICE_ROUTE || '/sitecore/api/layout/render/jss',
/**
* apiKey: The Sitecore SSC API key your app uses.
* Required.
*/
apiKey: process.env.SITECORE_API_KEY || serverBundle.apiKey || '{YOUR API KEY HERE}',
/**
* pathRewriteExcludeRoutes: A list of absolute paths
* that are NOT app routes and should not attempt to render a route
* using SSR. These route prefixes are directly proxied to the apiHost,
* allowing the proxy to also proxy GraphQL requests, REST requests, etc.
* Local static assets, Sitecore API paths, Sitecore asset paths, etc should be listed here.
* URLs will be encoded, so e.g. for a space use '%20' in the exclude.
*
* Need to perform logic instead of a flat list? Remove this and use
* pathRewriteExcludePredicate function instead: (url) => boolean;
*/
pathRewriteExcludeRoutes: [
'/dist',
'/assets',
'/sitecore/api',
'/api',
'/-/jssmedia',
'/-/media',
'/layouts/system',
].concat((process.env.SITECORE_PATH_REWRITE_EXCLUDE_ROUTES || '').split('|')),
/**
* Writes verbose request info to stdout for debugging.
* Must be disabled in production for reasonable performance.
*/
debug: process.env.SITECORE_ENABLE_DEBUG || false,
/**
* Maximum allowed proxy reply size in bytes. Replies larger than this are not sent.
* Avoids starving the proxy of memory if large requests are proxied.
* Default: 10MB
*/
maxResponseSizeBytes: 10 * 1024 * 1024,
/**
* Options object for http-proxy-middleware. Consult its docs.
*/
proxyOptions: {
// Setting this to false will disable SSL certificate validation
// when proxying to a SSL Sitecore instance.
// This is a major security issue, so NEVER EVER set this to false
// outside local development. Use a real CA-issued certificate.
secure: true,
/**
* Add the original client IP as a header for Sitecore Analytics and GeoIP.
* We could use the xfwd option of http-proxy, but express will use ipv6 formatted
* IPs by default and there are reported issues using ipv6 with GeoIP.
*/
onProxyReq: (proxyReq, req, res) => {
let ipv4 = ipaddr.process(req.ip).toString(); // strip ipv6 prefix added by node/express
if (ipv4 === '::1') {
ipv4 = '127.0.0.1';
}
proxyReq.setHeader('X-Forwarded-For', ipv4);
// because this is a proxy, all headers are forwarded on to the Sitecore server
// but, if we SSR we only understand how to decompress gzip and deflate. Some
// modern browsers would send 'br' (brotli) as well, and if the Sitecore server
// supported that (maybe via CDN) it would fail SSR as we can't decode the Brotli
// response. So, we force the accept-encoding header to only include what we can understand.
if (req.headers['accept-encoding']) {
proxyReq.setHeader('Accept-Encoding', 'gzip, deflate');
}
},
},
/**
* Custom error handling in case our app fails to render.
* Return null to pass through server response, or { content, statusCode }
* to override server response.
*
* Note: 404s are not errors, and will have null route data + context sent to the JSS app,
* so the app can render a 404 route.
*/
onError: (err, response) => {
// http 200 = an error in rendering; http 500 = an error on layout service
if (response.statusCode !== 500 && response.statusCode !== 200) return null;
return {
statusCode: 500,
content: fs.readFileSync('error.html', 'utf8'),
};
},
createViewBag: (request, response, proxyResponse, layoutServiceData) => {
// fetches the dictionary from the Sitecore server for the current language so it can be SSR'ed
// has a default cache applied since dictionary data is quite static and it helps rendering performance a lot
if (!layoutServiceData || !layoutServiceData.sitecore || !layoutServiceData.sitecore.context) {
return {};
}
const language = layoutServiceData.sitecore.context.language || 'en';
const site =
layoutServiceData.sitecore.context.site && layoutServiceData.sitecore.context.site.name;
if (!site) {
return {};
}
const cacheKey = `${site}_${language}`;
const cached = dictionaryCache.get(cacheKey);
if (cached) return Promise.resolve(cached);
return fetch(
`${config.apiHost}/sitecore/api/jss/dictionary/${appName}/${language}?sc_apikey=${
config.apiKey
}`
)
.then((result) => result.json())
.then((json) => {
const viewBag = {
dictionary: json && json.phrases,
};
dictionaryCache.set(cacheKey, viewBag);
return viewBag;
});
},
};
module.exports = config;