@dr.pogodin/react-utils 1.21.0 → 1.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/build/development/client/index.js +0 -7
  2. package/build/development/client/index.js.map +1 -1
  3. package/build/development/client/init.js +3 -17
  4. package/build/development/client/init.js.map +1 -1
  5. package/build/development/index.js +0 -13
  6. package/build/development/index.js.map +1 -1
  7. package/build/development/server/Cache.js +2 -9
  8. package/build/development/server/Cache.js.map +1 -1
  9. package/build/development/server/index.js +7 -32
  10. package/build/development/server/index.js.map +1 -1
  11. package/build/development/server/renderer.js +24 -80
  12. package/build/development/server/renderer.js.map +1 -1
  13. package/build/development/server/server.js +21 -61
  14. package/build/development/server/server.js.map +1 -1
  15. package/build/development/server/utils/errors.js +2 -9
  16. package/build/development/server/utils/errors.js.map +1 -1
  17. package/build/development/server/utils/index.js +0 -4
  18. package/build/development/shared/components/Button/index.js +2 -13
  19. package/build/development/shared/components/Button/index.js.map +1 -1
  20. package/build/development/shared/components/Checkbox/index.js +2 -9
  21. package/build/development/shared/components/Checkbox/index.js.map +1 -1
  22. package/build/development/shared/components/CodeSplit/index.js +11 -22
  23. package/build/development/shared/components/CodeSplit/index.js.map +1 -1
  24. package/build/development/shared/components/Dropdown/index.js +0 -11
  25. package/build/development/shared/components/Dropdown/index.js.map +1 -1
  26. package/build/development/shared/components/GenericLink/index.js +3 -9
  27. package/build/development/shared/components/GenericLink/index.js.map +1 -1
  28. package/build/development/shared/components/Input/index.js +0 -7
  29. package/build/development/shared/components/Input/index.js.map +1 -1
  30. package/build/development/shared/components/Link.js +3 -6
  31. package/build/development/shared/components/Link.js.map +1 -1
  32. package/build/development/shared/components/MetaTags.js +1 -8
  33. package/build/development/shared/components/MetaTags.js.map +1 -1
  34. package/build/development/shared/components/Modal/index.js +2 -19
  35. package/build/development/shared/components/Modal/index.js.map +1 -1
  36. package/build/development/shared/components/NavLink.js +2 -6
  37. package/build/development/shared/components/NavLink.js.map +1 -1
  38. package/build/development/shared/components/PageLayout/index.js +0 -7
  39. package/build/development/shared/components/PageLayout/index.js.map +1 -1
  40. package/build/development/shared/components/ScalableRect/index.js +1 -6
  41. package/build/development/shared/components/ScalableRect/index.js.map +1 -1
  42. package/build/development/shared/components/Throbber/index.js +0 -9
  43. package/build/development/shared/components/Throbber/index.js.map +1 -1
  44. package/build/development/shared/components/WithTooltip/Tooltip.js +9 -28
  45. package/build/development/shared/components/WithTooltip/Tooltip.js.map +1 -1
  46. package/build/development/shared/components/WithTooltip/index.js +0 -16
  47. package/build/development/shared/components/WithTooltip/index.js.map +1 -1
  48. package/build/development/shared/components/YouTubeVideo/index.js +3 -11
  49. package/build/development/shared/components/YouTubeVideo/index.js.map +1 -1
  50. package/build/development/shared/components/index.js +0 -17
  51. package/build/development/shared/components/index.js.map +1 -1
  52. package/build/development/shared/utils/Barrier.js +1 -13
  53. package/build/development/shared/utils/Barrier.js.map +1 -1
  54. package/build/development/shared/utils/Emitter.js +4 -13
  55. package/build/development/shared/utils/Emitter.js.map +1 -1
  56. package/build/development/shared/utils/Semaphore.js +13 -19
  57. package/build/development/shared/utils/Semaphore.js.map +1 -1
  58. package/build/development/shared/utils/config.js +0 -5
  59. package/build/development/shared/utils/config.js.map +1 -1
  60. package/build/development/shared/utils/index.js +5 -26
  61. package/build/development/shared/utils/index.js.map +1 -1
  62. package/build/development/shared/utils/isomorphy.js +6 -12
  63. package/build/development/shared/utils/isomorphy.js.map +1 -1
  64. package/build/development/shared/utils/jest/E2eSsrEnv.js +20 -41
  65. package/build/development/shared/utils/jest/E2eSsrEnv.js.map +1 -1
  66. package/build/development/shared/utils/jest/index.js +10 -31
  67. package/build/development/shared/utils/jest/index.js.map +1 -1
  68. package/build/development/shared/utils/splitComponent.js +2 -5
  69. package/build/development/shared/utils/splitComponent.js.map +1 -1
  70. package/build/development/shared/utils/time.js +6 -15
  71. package/build/development/shared/utils/time.js.map +1 -1
  72. package/build/development/shared/utils/webpack.js +1 -5
  73. package/build/development/shared/utils/webpack.js.map +1 -1
  74. package/build/development/style.css +5 -24
  75. package/build/development/web.bundle.js +27 -27
  76. package/build/production/client/index.js.map +1 -1
  77. package/build/production/client/init.js.map +1 -1
  78. package/build/production/index.js.map +1 -1
  79. package/build/production/server/Cache.js.map +1 -1
  80. package/build/production/server/index.js.map +1 -1
  81. package/build/production/server/renderer.js.map +1 -1
  82. package/build/production/server/server.js.map +1 -1
  83. package/build/production/server/utils/errors.js.map +1 -1
  84. package/build/production/shared/components/Button/index.js.map +1 -1
  85. package/build/production/shared/components/Checkbox/index.js.map +1 -1
  86. package/build/production/shared/components/CodeSplit/index.js.map +1 -1
  87. package/build/production/shared/components/Dropdown/index.js.map +1 -1
  88. package/build/production/shared/components/GenericLink/index.js.map +1 -1
  89. package/build/production/shared/components/Input/index.js.map +1 -1
  90. package/build/production/shared/components/Link.js.map +1 -1
  91. package/build/production/shared/components/MetaTags.js.map +1 -1
  92. package/build/production/shared/components/Modal/index.js.map +1 -1
  93. package/build/production/shared/components/NavLink.js.map +1 -1
  94. package/build/production/shared/components/PageLayout/index.js.map +1 -1
  95. package/build/production/shared/components/ScalableRect/index.js.map +1 -1
  96. package/build/production/shared/components/Throbber/index.js.map +1 -1
  97. package/build/production/shared/components/WithTooltip/Tooltip.js.map +1 -1
  98. package/build/production/shared/components/WithTooltip/index.js.map +1 -1
  99. package/build/production/shared/components/YouTubeVideo/index.js.map +1 -1
  100. package/build/production/shared/components/index.js.map +1 -1
  101. package/build/production/shared/utils/Barrier.js.map +1 -1
  102. package/build/production/shared/utils/Emitter.js.map +1 -1
  103. package/build/production/shared/utils/Semaphore.js.map +1 -1
  104. package/build/production/shared/utils/config.js.map +1 -1
  105. package/build/production/shared/utils/index.js.map +1 -1
  106. package/build/production/shared/utils/isomorphy.js.map +1 -1
  107. package/build/production/shared/utils/jest/E2eSsrEnv.js.map +1 -1
  108. package/build/production/shared/utils/jest/index.js.map +1 -1
  109. package/build/production/shared/utils/splitComponent.js.map +1 -1
  110. package/build/production/shared/utils/time.js.map +1 -1
  111. package/build/production/shared/utils/webpack.js.map +1 -1
  112. package/build/production/style.css +1 -1
  113. package/build/production/style.css.map +1 -1
  114. package/build/production/web.bundle.js.map +1 -1
  115. package/config/babel/node-ssr.js +1 -1
  116. package/package.json +26 -26
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
4
  Object.defineProperty(exports, "__esModule", {
6
5
  value: true
7
6
  });
@@ -9,48 +8,33 @@ exports.SCRIPT_LOCATIONS = void 0;
9
8
  exports.default = factory;
10
9
  exports.isBrotliAcceptable = isBrotliAcceptable;
11
10
  exports.newDefaultLogger = newDefaultLogger;
12
-
13
11
  var _stream = require("stream");
14
-
15
12
  var _reactGlobalState = require("@dr.pogodin/react-global-state");
16
-
17
13
  var _lodash = require("lodash");
18
-
19
14
  var _config = _interopRequireDefault(require("config"));
20
-
21
15
  var _nodeForge = _interopRequireDefault(require("node-forge"));
22
-
23
16
  var _fs = _interopRequireDefault(require("fs"));
24
-
25
17
  var _path = _interopRequireDefault(require("path"));
26
-
27
18
  var _zlib = require("zlib");
28
-
29
19
  var _server = require("react-dom/server");
30
-
31
20
  var _reactHelmet = require("react-helmet");
32
-
33
21
  var _server2 = require("react-router-dom/server");
34
-
35
22
  var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
36
-
37
23
  var _time = require("../shared/utils/time");
38
-
39
24
  var _winston = _interopRequireDefault(require("winston"));
40
-
41
25
  var _Cache = _interopRequireDefault(require("./Cache"));
42
-
43
26
  var _jsxRuntime = require("react/jsx-runtime");
44
-
45
27
  /**
46
28
  * ExpressJS middleware for server-side rendering of a ReactJS app.
47
29
  */
30
+
48
31
  const sanitizedConfig = (0, _lodash.omit)(_config.default, 'SECRET');
49
32
  const SCRIPT_LOCATIONS = {
50
33
  BODY_OPEN: 'BODY_OPEN',
51
34
  DEFAULT: 'DEFAULT',
52
35
  HEAD_OPEN: 'HEAD_OPEN'
53
36
  };
37
+
54
38
  /**
55
39
  * Reads build-time information about the app. This information is generated
56
40
  * by our standard Webpack config for apps, and it is written into
@@ -61,14 +45,12 @@ const SCRIPT_LOCATIONS = {
61
45
  * @param {String} context Webpack context path used during the build.
62
46
  * @return {Object} Resolves to the build-time information.
63
47
  */
64
-
65
48
  exports.SCRIPT_LOCATIONS = SCRIPT_LOCATIONS;
66
-
67
49
  function getBuildInfo(context) {
68
50
  const url = _path.default.resolve(context, '.build-info');
69
-
70
51
  return JSON.parse(_fs.default.readFileSync(url));
71
52
  }
53
+
72
54
  /**
73
55
  * Attempts to read from disk the named chunk groups mapping generated
74
56
  * by Webpack during the compilation.
@@ -78,21 +60,17 @@ function getBuildInfo(context) {
78
60
  * @param {string} buildDir
79
61
  * @return {object}
80
62
  */
81
-
82
-
83
63
  function readChunkGroupsJson(buildDir) {
84
64
  const url = _path.default.resolve(buildDir, '__chunk_groups__.json');
85
-
86
65
  let res;
87
-
88
66
  try {
89
67
  res = JSON.parse(_fs.default.readFileSync(url));
90
68
  } catch (err) {
91
69
  res = null;
92
70
  }
93
-
94
71
  return res;
95
72
  }
73
+
96
74
  /**
97
75
  * Prepares a new Cipher for data encryption.
98
76
  * @ignore
@@ -102,14 +80,11 @@ function readChunkGroupsJson(buildDir) {
102
80
  * 1. cipher - a new Cipher, ready for encryption;
103
81
  * 2. iv - initial vector used by the cipher.
104
82
  */
105
-
106
-
107
83
  function prepareCipher(key) {
108
84
  return new Promise((resolve, reject) => {
109
85
  _nodeForge.default.random.getBytes(32, (err, iv) => {
110
86
  if (err) reject(err);else {
111
87
  const cipher = _nodeForge.default.cipher.createCipher('AES-CBC', key);
112
-
113
88
  cipher.start({
114
89
  iv
115
90
  });
@@ -121,6 +96,7 @@ function prepareCipher(key) {
121
96
  });
122
97
  });
123
98
  }
99
+
124
100
  /**
125
101
  * Given an incoming HTTP requests, it deduces whether Brotli-encoded responses
126
102
  * are acceptable to the caller.
@@ -128,25 +104,20 @@ function prepareCipher(key) {
128
104
  * @return {boolean}
129
105
  * @ignore
130
106
  */
131
-
132
-
133
107
  function isBrotliAcceptable(req) {
134
108
  const acceptable = req.get('accept-encoding');
135
-
136
109
  if (acceptable) {
137
110
  const ops = acceptable.split(',');
138
-
139
111
  for (let i = 0; i < ops.length; ++i) {
140
112
  const [type, priority] = ops[i].trim().split(';q=');
141
-
142
113
  if ((type === '*' || type === 'br') && (!priority || parseFloat(priority) > 0)) {
143
114
  return true;
144
115
  }
145
116
  }
146
117
  }
147
-
148
118
  return false;
149
119
  }
120
+
150
121
  /**
151
122
  * Given an array of extra script strings / objects, it returns an object with
152
123
  * arrays of scripts to inject in different HTML template locations. During
@@ -161,18 +132,14 @@ function isBrotliAcceptable(req) {
161
132
  * HEAD_OPEN: string[];
162
133
  * }}
163
134
  */
164
-
165
-
166
135
  function groupExtraScripts(scripts = []) {
167
136
  const res = {
168
137
  [SCRIPT_LOCATIONS.BODY_OPEN]: '',
169
138
  [SCRIPT_LOCATIONS.DEFAULT]: '',
170
139
  [SCRIPT_LOCATIONS.HEAD_OPEN]: ''
171
140
  };
172
-
173
141
  for (let i = 0; i < scripts.length; ++i) {
174
142
  const script = scripts[i];
175
-
176
143
  if ((0, _lodash.isString)(script)) {
177
144
  if (script) res[SCRIPT_LOCATIONS.DEFAULT] += script;
178
145
  } else if (script.code) {
@@ -181,17 +148,15 @@ function groupExtraScripts(scripts = []) {
181
148
  } else throw Error(`Invalid location "${script.location}"`);
182
149
  }
183
150
  }
184
-
185
151
  return res;
186
152
  }
153
+
187
154
  /**
188
155
  * Creates a new default (Winston) logger.
189
156
  * @param {object} [options={}]
190
157
  * @param {string} [options.defaultLogLevel='info']
191
158
  * @return {object}
192
159
  */
193
-
194
-
195
160
  function newDefaultLogger({
196
161
  defaultLogLevel = 'info'
197
162
  } = {}) {
@@ -209,17 +174,16 @@ function newDefaultLogger({
209
174
  ...rest
210
175
  }) => {
211
176
  let res = `${level}\t(at ${timestamp}):\t${message}`;
212
-
213
177
  if (Object.keys(rest).length) {
214
178
  res += `\n${JSON.stringify(rest, null, 2)}`;
215
179
  }
216
-
217
180
  if (stack) res += `\n${stack}`;
218
181
  return res;
219
182
  })),
220
183
  transports: [new transports.Console()]
221
184
  });
222
185
  }
186
+
223
187
  /**
224
188
  * Creates the middleware.
225
189
  * @param {object} webpackConfig
@@ -251,27 +215,26 @@ function newDefaultLogger({
251
215
  * If undefined - infinite age is assumed.
252
216
  * @return {function} Created middleware.
253
217
  */
254
-
255
-
256
218
  function factory(webpackConfig, options) {
257
219
  const ops = (0, _lodash.defaults)((0, _lodash.clone)(options), {
258
220
  beforeRender: () => Promise.resolve({}),
259
221
  maxSsrRounds: 10,
260
222
  ssrTimeout: 1000,
261
223
  staticCacheSize: 1.e7
262
- }); // Note: in normal use the default logger is created and set in the root
224
+ });
225
+
226
+ // Note: in normal use the default logger is created and set in the root
263
227
  // server function, and this initialization is for testing uses, where
264
228
  // renderer is imported directly.
265
-
266
229
  if (ops.logger === undefined) {
267
230
  ops.logger = newDefaultLogger({
268
231
  defaultLogLevel: ops.defaultLoggerLogLevel
269
232
  });
270
233
  }
271
-
272
234
  const buildInfo = ops.buildInfo || getBuildInfo(webpackConfig.context);
273
- global.TRU_BUILD_INFO = buildInfo; // publicPath from webpack.output has a trailing slash at the end.
235
+ global.TRU_BUILD_INFO = buildInfo;
274
236
 
237
+ // publicPath from webpack.output has a trailing slash at the end.
275
238
  const {
276
239
  publicPath,
277
240
  path: outputPath
@@ -285,19 +248,15 @@ function factory(webpackConfig, options) {
285
248
  res.set('Cache-Control', 'no-cache');
286
249
  res.cookie('csrfToken', req.csrfToken());
287
250
  let cacheRef;
288
-
289
251
  if (cache) {
290
252
  cacheRef = ops.staticCacheController(req);
291
-
292
253
  if (cacheRef) {
293
254
  const data = cache.get(cacheRef);
294
-
295
255
  if (data !== null) {
296
256
  const {
297
257
  buffer,
298
258
  status
299
259
  } = data;
300
-
301
260
  if (ops.noCsp && isBrotliAcceptable(req)) {
302
261
  res.set('Content-Type', 'text/html');
303
262
  res.set('Content-Encoding', 'br');
@@ -308,7 +267,6 @@ function factory(webpackConfig, options) {
308
267
  (0, _zlib.brotliDecompress)(buffer, (error, html) => {
309
268
  if (error) failed(error);else {
310
269
  let h = html.toString();
311
-
312
270
  if (!ops.noCsp) {
313
271
  // TODO: Starting from Node v15 we'll be able to use string's
314
272
  // .replaceAll() method instead relying on reg. expression for
@@ -316,7 +274,6 @@ function factory(webpackConfig, options) {
316
274
  const regex = new RegExp(buffer.nonce, 'g');
317
275
  h = h.replace(regex, req.nonce);
318
276
  }
319
-
320
277
  if (status !== 200) res.status(status);
321
278
  res.send(h);
322
279
  done();
@@ -324,12 +281,10 @@ function factory(webpackConfig, options) {
324
281
  });
325
282
  });
326
283
  }
327
-
328
284
  return;
329
285
  }
330
286
  }
331
287
  }
332
-
333
288
  const [{
334
289
  configToInject,
335
290
  extraScripts,
@@ -339,8 +294,8 @@ function factory(webpackConfig, options) {
339
294
  iv
340
295
  }] = await Promise.all([ops.beforeRender(req, sanitizedConfig), prepareCipher(buildInfo.key)]);
341
296
  let helmet;
342
- /* Optional server-side rendering. */
343
297
 
298
+ /* Optional server-side rendering. */
344
299
  let App = ops.Application;
345
300
  const ssrContext = {
346
301
  req,
@@ -349,10 +304,8 @@ function factory(webpackConfig, options) {
349
304
  chunks: []
350
305
  };
351
306
  let stream;
352
-
353
307
  if (App) {
354
308
  const ssrStart = Date.now();
355
-
356
309
  const renderPass = async () => {
357
310
  ssrContext.chunks = [];
358
311
  return new Promise((resolve, reject) => {
@@ -369,16 +322,14 @@ function factory(webpackConfig, options) {
369
322
  });
370
323
  });
371
324
  };
372
-
373
325
  let ssrRound = 0;
374
326
  let bailed = false;
375
-
376
327
  for (; ssrRound < ops.maxSsrRounds; ++ssrRound) {
377
328
  stream = await renderPass(); // eslint-disable-line no-await-in-loop
378
329
 
379
330
  if (!ssrContext.dirty) break;
380
- /* eslint-disable no-await-in-loop */
381
331
 
332
+ /* eslint-disable no-await-in-loop */
382
333
  const timeout = ops.ssrTimeout + ssrStart - Date.now();
383
334
  bailed = timeout <= 0 || !(await Promise.race([Promise.allSettled(ssrContext.pending), (0, _time.timer)(timeout).then(() => false)]));
384
335
  if (bailed) break;
@@ -386,7 +337,6 @@ function factory(webpackConfig, options) {
386
337
  }
387
338
 
388
339
  let logMsg;
389
-
390
340
  if (ssrContext.dirty) {
391
341
  // NOTE: In the case of incomplete SSR one more round is necessary
392
342
  // to ensure the correct hydration when some pending promises have
@@ -394,7 +344,6 @@ function factory(webpackConfig, options) {
394
344
  stream = await renderPass();
395
345
  logMsg = bailed ? `SSR timed out after ${ops.ssrTimeout} second(s)` : `SSR bailed out after ${ops.maxSsrRounds} round(s)`;
396
346
  } else logMsg = `SSR completed in ${ssrRound + 1} round(s)`;
397
-
398
347
  ops.logger.log(ssrContext.dirty ? 'warn' : 'info', logMsg);
399
348
  App = '';
400
349
  stream.pipe(new _stream.Writable({
@@ -403,15 +352,13 @@ function factory(webpackConfig, options) {
403
352
  done();
404
353
  }
405
354
  }));
355
+
406
356
  /* This takes care about server-side rendering of page title and meta tags
407
357
  * (still demands injection into HTML template, which happens below). */
408
-
409
358
  helmet = _reactHelmet.Helmet.renderStatic();
410
359
  }
411
-
412
360
  let chunkGroups;
413
361
  const webpackStats = (0, _lodash.get)(res.locals, 'webpack.devMiddleware.stats');
414
-
415
362
  if (webpackStats) {
416
363
  chunkGroups = (0, _lodash.mapValues)(webpackStats.toJson({
417
364
  all: false,
@@ -420,13 +367,12 @@ function factory(webpackConfig, options) {
420
367
  name
421
368
  }) => name));
422
369
  } else if (CHUNK_GROUPS) chunkGroups = CHUNK_GROUPS;else chunkGroups = {};
370
+
423
371
  /* Encrypts data to be injected into HTML.
424
372
  * Keep in mind, that this encryption is no way secure: as the JS bundle
425
373
  * contains decryption key and is able to decode it at the client side.
426
374
  * Hovewer, for a number of reasons, encryption of injected data is still
427
375
  * better than injection of a plain text. */
428
-
429
-
430
376
  delete ssrContext.state.dr_pogodin_react_utils___split_components;
431
377
  const payload = (0, _serializeJavascript.default)({
432
378
  CHUNK_GROUPS: chunkGroups,
@@ -438,10 +384,10 @@ function factory(webpackConfig, options) {
438
384
  });
439
385
  cipher.update(_nodeForge.default.util.createBuffer(payload, 'utf8'));
440
386
  cipher.finish();
441
-
442
387
  const INJ = _nodeForge.default.util.encode64(`${iv}${cipher.output.data}`);
388
+ const chunkSet = new Set();
443
389
 
444
- const chunkSet = new Set(); // TODO: "main" chunk has to be added explicitly,
390
+ // TODO: "main" chunk has to be added explicitly,
445
391
  // because unlike all other chunks they are not managed by <CodeSplit>
446
392
  // component, thus they are not added to the ssrContext.chunks
447
393
  // automatically. Actually, names of these entry chunks should be
@@ -449,7 +395,6 @@ function factory(webpackConfig, options) {
449
395
  // remove or add other entry points, but it requires additional
450
396
  // efforts to figure out how to automatically order them right,
451
397
  // thus for now this handles the default config.
452
-
453
398
  ['main', ...ssrContext.chunks].forEach(chunk => {
454
399
  const assets = chunkGroups[chunk];
455
400
  if (assets) assets.forEach(asset => chunkSet.add(asset));
@@ -459,7 +404,8 @@ function factory(webpackConfig, options) {
459
404
  chunkSet.forEach(chunk => {
460
405
  if (chunk.endsWith('.css')) {
461
406
  styleChunkString += `<link href="${publicPath}${chunk}" rel="stylesheet">`;
462
- } else if (chunk.endsWith('.js') // In dev mode HMR adds JS updates into asset arrays,
407
+ } else if (chunk.endsWith('.js')
408
+ // In dev mode HMR adds JS updates into asset arrays,
463
409
  // and they (updates) should be ignored.
464
410
  && !chunk.endsWith('.hot-update.js')) {
465
411
  scriptChunkString += `<script src="${publicPath}${chunk}" type="application/javascript"></script>`;
@@ -499,7 +445,6 @@ function factory(webpackConfig, options) {
499
445
  </html>`;
500
446
  const status = ssrContext.status || 200;
501
447
  if (status !== 200) res.status(status);
502
-
503
448
  if (cacheRef && status < 500) {
504
449
  // Note: waiting for the caching to complete is not strictly necessary,
505
450
  // but it greately simplifies testing, and error reporting.
@@ -507,7 +452,6 @@ function factory(webpackConfig, options) {
507
452
  (0, _zlib.brotliCompress)(html, (error, buffer) => {
508
453
  if (error) failed(error);else {
509
454
  buffer.nonce = req.nonce; // eslint-disable-line no-param-reassign
510
-
511
455
  cache.add({
512
456
  buffer,
513
457
  status
@@ -516,11 +460,11 @@ function factory(webpackConfig, options) {
516
460
  }
517
461
  });
518
462
  });
519
- } // Note: as caching code above may throw in some cases, sending response
463
+ }
464
+
465
+ // Note: as caching code above may throw in some cases, sending response
520
466
  // before it completes will likely hide the error, making it difficult
521
467
  // to debug. Thus, at least for now, lets send response after it.
522
-
523
-
524
468
  res.send(html);
525
469
  } catch (error) {
526
470
  next(error);
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.js","names":["sanitizedConfig","omit","config","SCRIPT_LOCATIONS","BODY_OPEN","DEFAULT","HEAD_OPEN","getBuildInfo","context","url","path","resolve","JSON","parse","fs","readFileSync","readChunkGroupsJson","buildDir","res","err","prepareCipher","key","Promise","reject","forge","random","getBytes","iv","cipher","createCipher","start","isBrotliAcceptable","req","acceptable","get","ops","split","i","length","type","priority","trim","parseFloat","groupExtraScripts","scripts","script","isString","code","location","undefined","Error","newDefaultLogger","defaultLogLevel","format","transports","winston","createLogger","level","combine","splat","timestamp","colorize","printf","message","stack","rest","Object","keys","stringify","Console","factory","webpackConfig","options","defaults","clone","beforeRender","maxSsrRounds","ssrTimeout","staticCacheSize","logger","defaultLoggerLogLevel","buildInfo","global","TRU_BUILD_INFO","publicPath","outputPath","output","manifestLink","existsSync","cache","staticCacheController","Cache","CHUNK_GROUPS","next","set","cookie","csrfToken","cacheRef","data","buffer","status","noCsp","send","done","failed","brotliDecompress","error","html","h","toString","regex","RegExp","nonce","replace","configToInject","extraScripts","initialState","all","helmet","App","Application","ssrContext","state","cloneDeep","chunks","stream","ssrStart","Date","now","renderPass","pipeableStream","renderToPipeableStream","onAllReady","onError","ssrRound","bailed","dirty","timeout","race","allSettled","pending","timer","then","logMsg","log","pipe","Writable","write","chunk","_","Helmet","renderStatic","chunkGroups","webpackStats","locals","mapValues","toJson","namedChunkGroups","item","assets","map","name","dr_pogodin_react_utils___split_components","payload","serializeJs","CONFIG","ISTATE","ignoreFunction","unsafe","update","util","createBuffer","finish","INJ","encode64","chunkSet","Set","forEach","asset","add","styleChunkString","scriptChunkString","endsWith","grouppedExtraScripts","faviconLink","favicon","title","meta","brotliCompress"],"sources":["../../../src/server/renderer.jsx"],"sourcesContent":["/**\n * ExpressJS middleware for server-side rendering of a ReactJS app.\n */\n\nimport { Writable } from 'stream';\n\nimport { GlobalStateProvider } from '@dr.pogodin/react-global-state';\n\nimport {\n clone,\n cloneDeep,\n defaults,\n isString,\n get,\n mapValues,\n omit,\n} from 'lodash';\n\nimport config from 'config';\nimport forge from 'node-forge';\nimport fs from 'fs';\nimport path from 'path';\nimport { brotliCompress, brotliDecompress } from 'zlib';\n\nimport { renderToPipeableStream } from 'react-dom/server';\nimport { Helmet } from 'react-helmet';\nimport { StaticRouter } from 'react-router-dom/server';\nimport serializeJs from 'serialize-javascript';\nimport { timer } from 'utils/time';\nimport winston from 'winston';\n\nimport Cache from './Cache';\n\nconst sanitizedConfig = omit(config, 'SECRET');\n\nexport const SCRIPT_LOCATIONS = {\n BODY_OPEN: 'BODY_OPEN',\n DEFAULT: 'DEFAULT',\n HEAD_OPEN: 'HEAD_OPEN',\n};\n\n/**\n * Reads build-time information about the app. This information is generated\n * by our standard Webpack config for apps, and it is written into\n * \".build-info\" file in the context folder specified in Webpack config.\n * At the moment, that file contains build timestamp and a random 32-bit key,\n * suitable for cryptographical use.\n * @ignore\n * @param {String} context Webpack context path used during the build.\n * @return {Object} Resolves to the build-time information.\n */\nfunction getBuildInfo(context) {\n const url = path.resolve(context, '.build-info');\n return JSON.parse(fs.readFileSync(url));\n}\n\n/**\n * Attempts to read from disk the named chunk groups mapping generated\n * by Webpack during the compilation.\n * It will not work for development builds, where these stats should be captured\n * via compilator callback.\n * @ignore\n * @param {string} buildDir\n * @return {object}\n */\nfunction readChunkGroupsJson(buildDir) {\n const url = path.resolve(buildDir, '__chunk_groups__.json');\n let res;\n try {\n res = JSON.parse(fs.readFileSync(url));\n } catch (err) {\n res = null;\n }\n return res;\n}\n\n/**\n * Prepares a new Cipher for data encryption.\n * @ignore\n * @param {String} key Encryption key (32-bit random key is expected, see\n * node-forge documentation, in case of doubts).\n * @return {Promise} Resolves to the object with two fields:\n * 1. cipher - a new Cipher, ready for encryption;\n * 2. iv - initial vector used by the cipher.\n */\nfunction prepareCipher(key) {\n return new Promise((resolve, reject) => {\n forge.random.getBytes(32, (err, iv) => {\n if (err) reject(err);\n else {\n const cipher = forge.cipher.createCipher('AES-CBC', key);\n cipher.start({ iv });\n resolve({ cipher, iv });\n }\n });\n });\n}\n\n/**\n * Given an incoming HTTP requests, it deduces whether Brotli-encoded responses\n * are acceptable to the caller.\n * @param {object} req\n * @return {boolean}\n * @ignore\n */\nexport function isBrotliAcceptable(req) {\n const acceptable = req.get('accept-encoding');\n if (acceptable) {\n const ops = acceptable.split(',');\n for (let i = 0; i < ops.length; ++i) {\n const [type, priority] = ops[i].trim().split(';q=');\n if ((type === '*' || type === 'br')\n && (!priority || parseFloat(priority) > 0)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Given an array of extra script strings / objects, it returns an object with\n * arrays of scripts to inject in different HTML template locations. During\n * the script groupping it also filters out any empty scripts.\n * @param {({\n * code: string;\n * location: string;\n * }|string)[]} [scripts=[]]\n * @return {{\n * BODY_OPEN: string[];\n * DEFAULT: string[];\n * HEAD_OPEN: string[];\n * }}\n */\nfunction groupExtraScripts(scripts = []) {\n const res = {\n [SCRIPT_LOCATIONS.BODY_OPEN]: '',\n [SCRIPT_LOCATIONS.DEFAULT]: '',\n [SCRIPT_LOCATIONS.HEAD_OPEN]: '',\n };\n for (let i = 0; i < scripts.length; ++i) {\n const script = scripts[i];\n if (isString(script)) {\n if (script) res[SCRIPT_LOCATIONS.DEFAULT] += script;\n } else if (script.code) {\n if (res[script.location] !== undefined) {\n res[script.location] += script.code;\n } else throw Error(`Invalid location \"${script.location}\"`);\n }\n }\n return res;\n}\n\n/**\n * Creates a new default (Winston) logger.\n * @param {object} [options={}]\n * @param {string} [options.defaultLogLevel='info']\n * @return {object}\n */\nexport function newDefaultLogger({\n defaultLogLevel = 'info',\n} = {}) {\n const { format, transports } = winston;\n return winston.createLogger({\n level: defaultLogLevel,\n format: format.combine(\n format.splat(),\n format.timestamp(),\n format.colorize(),\n format.printf(\n ({\n level,\n message,\n timestamp,\n stack,\n ...rest\n }) => {\n let res = `${level}\\t(at ${timestamp}):\\t${message}`;\n if (Object.keys(rest).length) {\n res += `\\n${JSON.stringify(rest, null, 2)}`;\n }\n if (stack) res += `\\n${stack}`;\n return res;\n },\n ),\n ),\n transports: [new transports.Console()],\n });\n}\n\n/**\n * Creates the middleware.\n * @param {object} webpackConfig\n * @param {object} options Additional options:\n * @param {Component} [options.Application] The root ReactJS component of\n * the app to use for the server-side rendering. When not provided\n * the server-side rendering is disabled.\n * @param {object} [options.buildInfo] \"Build info\" object to use. If provided,\n * it will be used, instead of trying to load from the filesystem the one\n * generated by the Webpack build. It is intended for test environments,\n * where passing this stuff via file system is no bueno.\n * @param {boolean} [options.favicon] `true` will include favicon\n * link into the rendered HTML templates.\n * @param {boolean} [options.noCsp] `true` means that no\n * Content-Security-Policy (CSP) is used by server, thus the renderer\n * may cut a few corners.\n * @param {number} [options.maxSsrRounds=10] Maximum number of SSR rounds.\n * @param {number} [options.ssrTimeout=1000] SSR timeout in milliseconds,\n * defaults to 1 second.\n * @param {number} [options.staticCacheSize=1.e7] The maximum\n * static cache size in bytes. Defaults to ~10 MB.\n * @param {function} [options.staticCacheController] When given, it activates,\n * and controls the static caching of generated HTML markup. When this function\n * is provided, on each incoming request it is triggered with the request\n * passed in as the argument. To attempt to serve the response from the cache\n * it should return the object with the following fields:\n * - `key: string` &ndash; the cache key for the response;\n * - `maxage?: number` &ndash; the maximum age of cached result in ms.\n * If undefined - infinite age is assumed.\n * @return {function} Created middleware.\n */\nexport default function factory(webpackConfig, options) {\n const ops = defaults(clone(options), {\n beforeRender: () => Promise.resolve({}),\n maxSsrRounds: 10,\n ssrTimeout: 1000,\n staticCacheSize: 1.e7,\n });\n\n // Note: in normal use the default logger is created and set in the root\n // server function, and this initialization is for testing uses, where\n // renderer is imported directly.\n if (ops.logger === undefined) {\n ops.logger = newDefaultLogger({\n defaultLogLevel: ops.defaultLoggerLogLevel,\n });\n }\n\n const buildInfo = ops.buildInfo || getBuildInfo(webpackConfig.context);\n global.TRU_BUILD_INFO = buildInfo;\n\n // publicPath from webpack.output has a trailing slash at the end.\n const { publicPath, path: outputPath } = webpackConfig.output;\n\n const manifestLink = fs.existsSync(`${outputPath}/manifest.json`)\n ? `<link rel=\"manifest\" href=\"${publicPath}manifest.json\">` : '';\n\n const cache = ops.staticCacheController\n ? new Cache(ops.staticCacheSize) : null;\n\n const CHUNK_GROUPS = readChunkGroupsJson(outputPath);\n\n return async (req, res, next) => {\n try {\n // Ensures any caches always revalidate HTML markup before reuse.\n res.set('Cache-Control', 'no-cache');\n\n res.cookie('csrfToken', req.csrfToken());\n\n let cacheRef;\n if (cache) {\n cacheRef = ops.staticCacheController(req);\n if (cacheRef) {\n const data = cache.get(cacheRef);\n if (data !== null) {\n const { buffer, status } = data;\n if (ops.noCsp && isBrotliAcceptable(req)) {\n res.set('Content-Type', 'text/html');\n res.set('Content-Encoding', 'br');\n if (status !== 200) res.status(status);\n res.send(buffer);\n } else {\n await new Promise((done, failed) => {\n brotliDecompress(buffer, (error, html) => {\n if (error) failed(error);\n else {\n let h = html.toString();\n if (!ops.noCsp) {\n // TODO: Starting from Node v15 we'll be able to use string's\n // .replaceAll() method instead relying on reg. expression for\n // global matching.\n const regex = new RegExp(buffer.nonce, 'g');\n h = h.replace(regex, req.nonce);\n }\n if (status !== 200) res.status(status);\n res.send(h);\n done();\n }\n });\n });\n }\n return;\n }\n }\n }\n\n const [{\n configToInject,\n extraScripts,\n initialState,\n }, {\n cipher,\n iv,\n }] = await Promise.all([\n ops.beforeRender(req, sanitizedConfig),\n prepareCipher(buildInfo.key),\n ]);\n\n let helmet;\n\n /* Optional server-side rendering. */\n let App = ops.Application;\n const ssrContext = {\n req,\n state: cloneDeep(initialState || {}),\n\n // Array of chunk names encountered during the rendering.\n chunks: [],\n };\n let stream;\n if (App) {\n const ssrStart = Date.now();\n\n const renderPass = async () => {\n ssrContext.chunks = [];\n return new Promise((resolve, reject) => {\n const pipeableStream = renderToPipeableStream(\n <GlobalStateProvider\n initialState={ssrContext.state}\n ssrContext={ssrContext}\n >\n <StaticRouter location={req.url}>\n <App />\n </StaticRouter>\n </GlobalStateProvider>,\n {\n onAllReady: () => resolve(pipeableStream),\n onError: reject,\n },\n );\n });\n };\n\n let ssrRound = 0;\n let bailed = false;\n for (; ssrRound < ops.maxSsrRounds; ++ssrRound) {\n stream = await renderPass(); // eslint-disable-line no-await-in-loop\n\n if (!ssrContext.dirty) break;\n\n /* eslint-disable no-await-in-loop */\n const timeout = ops.ssrTimeout + ssrStart - Date.now();\n bailed = timeout <= 0 || !await Promise.race([\n Promise.allSettled(ssrContext.pending),\n timer(timeout).then(() => false),\n ]);\n if (bailed) break;\n /* eslint-enable no-await-in-loop */\n }\n\n let logMsg;\n if (ssrContext.dirty) {\n // NOTE: In the case of incomplete SSR one more round is necessary\n // to ensure the correct hydration when some pending promises have\n // resolved and placed their data into the initial global state.\n stream = await renderPass();\n\n logMsg = bailed ? `SSR timed out after ${ops.ssrTimeout} second(s)`\n : `SSR bailed out after ${ops.maxSsrRounds} round(s)`;\n } else logMsg = `SSR completed in ${ssrRound + 1} round(s)`;\n\n ops.logger.log(ssrContext.dirty ? 'warn' : 'info', logMsg);\n\n App = '';\n stream.pipe(new Writable({\n write: (chunk, _, done) => {\n App += chunk.toString();\n done();\n },\n }));\n\n /* This takes care about server-side rendering of page title and meta tags\n * (still demands injection into HTML template, which happens below). */\n helmet = Helmet.renderStatic();\n }\n\n let chunkGroups;\n const webpackStats = get(res.locals, 'webpack.devMiddleware.stats');\n if (webpackStats) {\n chunkGroups = mapValues(\n webpackStats.toJson({\n all: false,\n chunkGroups: true,\n }).namedChunkGroups,\n (item) => item.assets.map(({ name }) => name),\n );\n } else if (CHUNK_GROUPS) chunkGroups = CHUNK_GROUPS;\n else chunkGroups = {};\n\n /* Encrypts data to be injected into HTML.\n * Keep in mind, that this encryption is no way secure: as the JS bundle\n * contains decryption key and is able to decode it at the client side.\n * Hovewer, for a number of reasons, encryption of injected data is still\n * better than injection of a plain text. */\n delete ssrContext.state.dr_pogodin_react_utils___split_components;\n\n const payload = serializeJs({\n CHUNK_GROUPS: chunkGroups,\n CONFIG: configToInject || sanitizedConfig,\n ISTATE: ssrContext.state,\n }, {\n ignoreFunction: true,\n unsafe: true,\n });\n cipher.update(forge.util.createBuffer(payload, 'utf8'));\n cipher.finish();\n const INJ = forge.util.encode64(`${iv}${cipher.output.data}`);\n\n const chunkSet = new Set();\n\n // TODO: \"main\" chunk has to be added explicitly,\n // because unlike all other chunks they are not managed by <CodeSplit>\n // component, thus they are not added to the ssrContext.chunks\n // automatically. Actually, names of these entry chunks should be\n // read from Wepback config, as the end user may customize them,\n // remove or add other entry points, but it requires additional\n // efforts to figure out how to automatically order them right,\n // thus for now this handles the default config.\n [\n 'main',\n ...ssrContext.chunks,\n ].forEach((chunk) => {\n const assets = chunkGroups[chunk];\n if (assets) assets.forEach((asset) => chunkSet.add(asset));\n });\n\n let styleChunkString = '';\n let scriptChunkString = '';\n chunkSet.forEach((chunk) => {\n if (chunk.endsWith('.css')) {\n styleChunkString += `<link href=\"${publicPath}${chunk}\" rel=\"stylesheet\">`;\n } else if (\n chunk.endsWith('.js')\n // In dev mode HMR adds JS updates into asset arrays,\n // and they (updates) should be ignored.\n && !chunk.endsWith('.hot-update.js')\n ) {\n scriptChunkString += `<script src=\"${publicPath}${chunk}\" type=\"application/javascript\"></script>`;\n }\n });\n\n const grouppedExtraScripts = groupExtraScripts(extraScripts);\n\n const faviconLink = ops.favicon ? (\n '<link rel=\"shortcut icon\" href=\"/favicon.ico\">'\n ) : '';\n\n const html = `<!DOCTYPE html>\n <html lang=\"en\">\n <head>\n ${grouppedExtraScripts[SCRIPT_LOCATIONS.HEAD_OPEN]}\n ${helmet ? helmet.title.toString() : ''}\n ${helmet ? helmet.meta.toString() : ''}\n <meta name=\"theme-color\" content=\"#FFFFFF\">\n ${manifestLink}\n ${styleChunkString}\n ${faviconLink}\n <meta charset=\"utf-8\">\n <meta\n content=\"width=device-width,initial-scale=1.0\"\n name=\"viewport\"\n >\n </head>\n <body>\n ${grouppedExtraScripts[SCRIPT_LOCATIONS.BODY_OPEN]}\n <div id=\"react-view\">${App || ''}</div>\n <script\n id=\"inj\"\n type=\"application/javascript\"\n ${ops.noCsp ? '' : `nonce=\"${req.nonce}\"`}\n >\n window.INJ=\"${INJ}\"\n </script>\n ${scriptChunkString}\n ${grouppedExtraScripts[SCRIPT_LOCATIONS.DEFAULT]}\n </body>\n </html>`;\n\n const status = ssrContext.status || 200;\n if (status !== 200) res.status(status);\n\n if (cacheRef && status < 500) {\n // Note: waiting for the caching to complete is not strictly necessary,\n // but it greately simplifies testing, and error reporting.\n await new Promise((done, failed) => {\n brotliCompress(html, (error, buffer) => {\n if (error) failed(error);\n else {\n buffer.nonce = req.nonce; // eslint-disable-line no-param-reassign\n cache.add({ buffer, status }, cacheRef.key);\n done();\n }\n });\n });\n }\n\n // Note: as caching code above may throw in some cases, sending response\n // before it completes will likely hide the error, making it difficult\n // to debug. Thus, at least for now, lets send response after it.\n res.send(html);\n } catch (error) {\n next(error);\n }\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"renderer.js","names":["sanitizedConfig","omit","config","SCRIPT_LOCATIONS","BODY_OPEN","DEFAULT","HEAD_OPEN","getBuildInfo","context","url","path","resolve","JSON","parse","fs","readFileSync","readChunkGroupsJson","buildDir","res","err","prepareCipher","key","Promise","reject","forge","random","getBytes","iv","cipher","createCipher","start","isBrotliAcceptable","req","acceptable","get","ops","split","i","length","type","priority","trim","parseFloat","groupExtraScripts","scripts","script","isString","code","location","undefined","Error","newDefaultLogger","defaultLogLevel","format","transports","winston","createLogger","level","combine","splat","timestamp","colorize","printf","message","stack","rest","Object","keys","stringify","Console","factory","webpackConfig","options","defaults","clone","beforeRender","maxSsrRounds","ssrTimeout","staticCacheSize","logger","defaultLoggerLogLevel","buildInfo","global","TRU_BUILD_INFO","publicPath","outputPath","output","manifestLink","existsSync","cache","staticCacheController","Cache","CHUNK_GROUPS","next","set","cookie","csrfToken","cacheRef","data","buffer","status","noCsp","send","done","failed","brotliDecompress","error","html","h","toString","regex","RegExp","nonce","replace","configToInject","extraScripts","initialState","all","helmet","App","Application","ssrContext","state","cloneDeep","chunks","stream","ssrStart","Date","now","renderPass","pipeableStream","renderToPipeableStream","onAllReady","onError","ssrRound","bailed","dirty","timeout","race","allSettled","pending","timer","then","logMsg","log","pipe","Writable","write","chunk","_","Helmet","renderStatic","chunkGroups","webpackStats","locals","mapValues","toJson","namedChunkGroups","item","assets","map","name","dr_pogodin_react_utils___split_components","payload","serializeJs","CONFIG","ISTATE","ignoreFunction","unsafe","update","util","createBuffer","finish","INJ","encode64","chunkSet","Set","forEach","asset","add","styleChunkString","scriptChunkString","endsWith","grouppedExtraScripts","faviconLink","favicon","title","meta","brotliCompress"],"sources":["../../../src/server/renderer.jsx"],"sourcesContent":["/**\n * ExpressJS middleware for server-side rendering of a ReactJS app.\n */\n\nimport { Writable } from 'stream';\n\nimport { GlobalStateProvider } from '@dr.pogodin/react-global-state';\n\nimport {\n clone,\n cloneDeep,\n defaults,\n isString,\n get,\n mapValues,\n omit,\n} from 'lodash';\n\nimport config from 'config';\nimport forge from 'node-forge';\nimport fs from 'fs';\nimport path from 'path';\nimport { brotliCompress, brotliDecompress } from 'zlib';\n\nimport { renderToPipeableStream } from 'react-dom/server';\nimport { Helmet } from 'react-helmet';\nimport { StaticRouter } from 'react-router-dom/server';\nimport serializeJs from 'serialize-javascript';\nimport { timer } from 'utils/time';\nimport winston from 'winston';\n\nimport Cache from './Cache';\n\nconst sanitizedConfig = omit(config, 'SECRET');\n\nexport const SCRIPT_LOCATIONS = {\n BODY_OPEN: 'BODY_OPEN',\n DEFAULT: 'DEFAULT',\n HEAD_OPEN: 'HEAD_OPEN',\n};\n\n/**\n * Reads build-time information about the app. This information is generated\n * by our standard Webpack config for apps, and it is written into\n * \".build-info\" file in the context folder specified in Webpack config.\n * At the moment, that file contains build timestamp and a random 32-bit key,\n * suitable for cryptographical use.\n * @ignore\n * @param {String} context Webpack context path used during the build.\n * @return {Object} Resolves to the build-time information.\n */\nfunction getBuildInfo(context) {\n const url = path.resolve(context, '.build-info');\n return JSON.parse(fs.readFileSync(url));\n}\n\n/**\n * Attempts to read from disk the named chunk groups mapping generated\n * by Webpack during the compilation.\n * It will not work for development builds, where these stats should be captured\n * via compilator callback.\n * @ignore\n * @param {string} buildDir\n * @return {object}\n */\nfunction readChunkGroupsJson(buildDir) {\n const url = path.resolve(buildDir, '__chunk_groups__.json');\n let res;\n try {\n res = JSON.parse(fs.readFileSync(url));\n } catch (err) {\n res = null;\n }\n return res;\n}\n\n/**\n * Prepares a new Cipher for data encryption.\n * @ignore\n * @param {String} key Encryption key (32-bit random key is expected, see\n * node-forge documentation, in case of doubts).\n * @return {Promise} Resolves to the object with two fields:\n * 1. cipher - a new Cipher, ready for encryption;\n * 2. iv - initial vector used by the cipher.\n */\nfunction prepareCipher(key) {\n return new Promise((resolve, reject) => {\n forge.random.getBytes(32, (err, iv) => {\n if (err) reject(err);\n else {\n const cipher = forge.cipher.createCipher('AES-CBC', key);\n cipher.start({ iv });\n resolve({ cipher, iv });\n }\n });\n });\n}\n\n/**\n * Given an incoming HTTP requests, it deduces whether Brotli-encoded responses\n * are acceptable to the caller.\n * @param {object} req\n * @return {boolean}\n * @ignore\n */\nexport function isBrotliAcceptable(req) {\n const acceptable = req.get('accept-encoding');\n if (acceptable) {\n const ops = acceptable.split(',');\n for (let i = 0; i < ops.length; ++i) {\n const [type, priority] = ops[i].trim().split(';q=');\n if ((type === '*' || type === 'br')\n && (!priority || parseFloat(priority) > 0)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Given an array of extra script strings / objects, it returns an object with\n * arrays of scripts to inject in different HTML template locations. During\n * the script groupping it also filters out any empty scripts.\n * @param {({\n * code: string;\n * location: string;\n * }|string)[]} [scripts=[]]\n * @return {{\n * BODY_OPEN: string[];\n * DEFAULT: string[];\n * HEAD_OPEN: string[];\n * }}\n */\nfunction groupExtraScripts(scripts = []) {\n const res = {\n [SCRIPT_LOCATIONS.BODY_OPEN]: '',\n [SCRIPT_LOCATIONS.DEFAULT]: '',\n [SCRIPT_LOCATIONS.HEAD_OPEN]: '',\n };\n for (let i = 0; i < scripts.length; ++i) {\n const script = scripts[i];\n if (isString(script)) {\n if (script) res[SCRIPT_LOCATIONS.DEFAULT] += script;\n } else if (script.code) {\n if (res[script.location] !== undefined) {\n res[script.location] += script.code;\n } else throw Error(`Invalid location \"${script.location}\"`);\n }\n }\n return res;\n}\n\n/**\n * Creates a new default (Winston) logger.\n * @param {object} [options={}]\n * @param {string} [options.defaultLogLevel='info']\n * @return {object}\n */\nexport function newDefaultLogger({\n defaultLogLevel = 'info',\n} = {}) {\n const { format, transports } = winston;\n return winston.createLogger({\n level: defaultLogLevel,\n format: format.combine(\n format.splat(),\n format.timestamp(),\n format.colorize(),\n format.printf(\n ({\n level,\n message,\n timestamp,\n stack,\n ...rest\n }) => {\n let res = `${level}\\t(at ${timestamp}):\\t${message}`;\n if (Object.keys(rest).length) {\n res += `\\n${JSON.stringify(rest, null, 2)}`;\n }\n if (stack) res += `\\n${stack}`;\n return res;\n },\n ),\n ),\n transports: [new transports.Console()],\n });\n}\n\n/**\n * Creates the middleware.\n * @param {object} webpackConfig\n * @param {object} options Additional options:\n * @param {Component} [options.Application] The root ReactJS component of\n * the app to use for the server-side rendering. When not provided\n * the server-side rendering is disabled.\n * @param {object} [options.buildInfo] \"Build info\" object to use. If provided,\n * it will be used, instead of trying to load from the filesystem the one\n * generated by the Webpack build. It is intended for test environments,\n * where passing this stuff via file system is no bueno.\n * @param {boolean} [options.favicon] `true` will include favicon\n * link into the rendered HTML templates.\n * @param {boolean} [options.noCsp] `true` means that no\n * Content-Security-Policy (CSP) is used by server, thus the renderer\n * may cut a few corners.\n * @param {number} [options.maxSsrRounds=10] Maximum number of SSR rounds.\n * @param {number} [options.ssrTimeout=1000] SSR timeout in milliseconds,\n * defaults to 1 second.\n * @param {number} [options.staticCacheSize=1.e7] The maximum\n * static cache size in bytes. Defaults to ~10 MB.\n * @param {function} [options.staticCacheController] When given, it activates,\n * and controls the static caching of generated HTML markup. When this function\n * is provided, on each incoming request it is triggered with the request\n * passed in as the argument. To attempt to serve the response from the cache\n * it should return the object with the following fields:\n * - `key: string` &ndash; the cache key for the response;\n * - `maxage?: number` &ndash; the maximum age of cached result in ms.\n * If undefined - infinite age is assumed.\n * @return {function} Created middleware.\n */\nexport default function factory(webpackConfig, options) {\n const ops = defaults(clone(options), {\n beforeRender: () => Promise.resolve({}),\n maxSsrRounds: 10,\n ssrTimeout: 1000,\n staticCacheSize: 1.e7,\n });\n\n // Note: in normal use the default logger is created and set in the root\n // server function, and this initialization is for testing uses, where\n // renderer is imported directly.\n if (ops.logger === undefined) {\n ops.logger = newDefaultLogger({\n defaultLogLevel: ops.defaultLoggerLogLevel,\n });\n }\n\n const buildInfo = ops.buildInfo || getBuildInfo(webpackConfig.context);\n global.TRU_BUILD_INFO = buildInfo;\n\n // publicPath from webpack.output has a trailing slash at the end.\n const { publicPath, path: outputPath } = webpackConfig.output;\n\n const manifestLink = fs.existsSync(`${outputPath}/manifest.json`)\n ? `<link rel=\"manifest\" href=\"${publicPath}manifest.json\">` : '';\n\n const cache = ops.staticCacheController\n ? new Cache(ops.staticCacheSize) : null;\n\n const CHUNK_GROUPS = readChunkGroupsJson(outputPath);\n\n return async (req, res, next) => {\n try {\n // Ensures any caches always revalidate HTML markup before reuse.\n res.set('Cache-Control', 'no-cache');\n\n res.cookie('csrfToken', req.csrfToken());\n\n let cacheRef;\n if (cache) {\n cacheRef = ops.staticCacheController(req);\n if (cacheRef) {\n const data = cache.get(cacheRef);\n if (data !== null) {\n const { buffer, status } = data;\n if (ops.noCsp && isBrotliAcceptable(req)) {\n res.set('Content-Type', 'text/html');\n res.set('Content-Encoding', 'br');\n if (status !== 200) res.status(status);\n res.send(buffer);\n } else {\n await new Promise((done, failed) => {\n brotliDecompress(buffer, (error, html) => {\n if (error) failed(error);\n else {\n let h = html.toString();\n if (!ops.noCsp) {\n // TODO: Starting from Node v15 we'll be able to use string's\n // .replaceAll() method instead relying on reg. expression for\n // global matching.\n const regex = new RegExp(buffer.nonce, 'g');\n h = h.replace(regex, req.nonce);\n }\n if (status !== 200) res.status(status);\n res.send(h);\n done();\n }\n });\n });\n }\n return;\n }\n }\n }\n\n const [{\n configToInject,\n extraScripts,\n initialState,\n }, {\n cipher,\n iv,\n }] = await Promise.all([\n ops.beforeRender(req, sanitizedConfig),\n prepareCipher(buildInfo.key),\n ]);\n\n let helmet;\n\n /* Optional server-side rendering. */\n let App = ops.Application;\n const ssrContext = {\n req,\n state: cloneDeep(initialState || {}),\n\n // Array of chunk names encountered during the rendering.\n chunks: [],\n };\n let stream;\n if (App) {\n const ssrStart = Date.now();\n\n const renderPass = async () => {\n ssrContext.chunks = [];\n return new Promise((resolve, reject) => {\n const pipeableStream = renderToPipeableStream(\n <GlobalStateProvider\n initialState={ssrContext.state}\n ssrContext={ssrContext}\n >\n <StaticRouter location={req.url}>\n <App />\n </StaticRouter>\n </GlobalStateProvider>,\n {\n onAllReady: () => resolve(pipeableStream),\n onError: reject,\n },\n );\n });\n };\n\n let ssrRound = 0;\n let bailed = false;\n for (; ssrRound < ops.maxSsrRounds; ++ssrRound) {\n stream = await renderPass(); // eslint-disable-line no-await-in-loop\n\n if (!ssrContext.dirty) break;\n\n /* eslint-disable no-await-in-loop */\n const timeout = ops.ssrTimeout + ssrStart - Date.now();\n bailed = timeout <= 0 || !await Promise.race([\n Promise.allSettled(ssrContext.pending),\n timer(timeout).then(() => false),\n ]);\n if (bailed) break;\n /* eslint-enable no-await-in-loop */\n }\n\n let logMsg;\n if (ssrContext.dirty) {\n // NOTE: In the case of incomplete SSR one more round is necessary\n // to ensure the correct hydration when some pending promises have\n // resolved and placed their data into the initial global state.\n stream = await renderPass();\n\n logMsg = bailed ? `SSR timed out after ${ops.ssrTimeout} second(s)`\n : `SSR bailed out after ${ops.maxSsrRounds} round(s)`;\n } else logMsg = `SSR completed in ${ssrRound + 1} round(s)`;\n\n ops.logger.log(ssrContext.dirty ? 'warn' : 'info', logMsg);\n\n App = '';\n stream.pipe(new Writable({\n write: (chunk, _, done) => {\n App += chunk.toString();\n done();\n },\n }));\n\n /* This takes care about server-side rendering of page title and meta tags\n * (still demands injection into HTML template, which happens below). */\n helmet = Helmet.renderStatic();\n }\n\n let chunkGroups;\n const webpackStats = get(res.locals, 'webpack.devMiddleware.stats');\n if (webpackStats) {\n chunkGroups = mapValues(\n webpackStats.toJson({\n all: false,\n chunkGroups: true,\n }).namedChunkGroups,\n (item) => item.assets.map(({ name }) => name),\n );\n } else if (CHUNK_GROUPS) chunkGroups = CHUNK_GROUPS;\n else chunkGroups = {};\n\n /* Encrypts data to be injected into HTML.\n * Keep in mind, that this encryption is no way secure: as the JS bundle\n * contains decryption key and is able to decode it at the client side.\n * Hovewer, for a number of reasons, encryption of injected data is still\n * better than injection of a plain text. */\n delete ssrContext.state.dr_pogodin_react_utils___split_components;\n\n const payload = serializeJs({\n CHUNK_GROUPS: chunkGroups,\n CONFIG: configToInject || sanitizedConfig,\n ISTATE: ssrContext.state,\n }, {\n ignoreFunction: true,\n unsafe: true,\n });\n cipher.update(forge.util.createBuffer(payload, 'utf8'));\n cipher.finish();\n const INJ = forge.util.encode64(`${iv}${cipher.output.data}`);\n\n const chunkSet = new Set();\n\n // TODO: \"main\" chunk has to be added explicitly,\n // because unlike all other chunks they are not managed by <CodeSplit>\n // component, thus they are not added to the ssrContext.chunks\n // automatically. Actually, names of these entry chunks should be\n // read from Wepback config, as the end user may customize them,\n // remove or add other entry points, but it requires additional\n // efforts to figure out how to automatically order them right,\n // thus for now this handles the default config.\n [\n 'main',\n ...ssrContext.chunks,\n ].forEach((chunk) => {\n const assets = chunkGroups[chunk];\n if (assets) assets.forEach((asset) => chunkSet.add(asset));\n });\n\n let styleChunkString = '';\n let scriptChunkString = '';\n chunkSet.forEach((chunk) => {\n if (chunk.endsWith('.css')) {\n styleChunkString += `<link href=\"${publicPath}${chunk}\" rel=\"stylesheet\">`;\n } else if (\n chunk.endsWith('.js')\n // In dev mode HMR adds JS updates into asset arrays,\n // and they (updates) should be ignored.\n && !chunk.endsWith('.hot-update.js')\n ) {\n scriptChunkString += `<script src=\"${publicPath}${chunk}\" type=\"application/javascript\"></script>`;\n }\n });\n\n const grouppedExtraScripts = groupExtraScripts(extraScripts);\n\n const faviconLink = ops.favicon ? (\n '<link rel=\"shortcut icon\" href=\"/favicon.ico\">'\n ) : '';\n\n const html = `<!DOCTYPE html>\n <html lang=\"en\">\n <head>\n ${grouppedExtraScripts[SCRIPT_LOCATIONS.HEAD_OPEN]}\n ${helmet ? helmet.title.toString() : ''}\n ${helmet ? helmet.meta.toString() : ''}\n <meta name=\"theme-color\" content=\"#FFFFFF\">\n ${manifestLink}\n ${styleChunkString}\n ${faviconLink}\n <meta charset=\"utf-8\">\n <meta\n content=\"width=device-width,initial-scale=1.0\"\n name=\"viewport\"\n >\n </head>\n <body>\n ${grouppedExtraScripts[SCRIPT_LOCATIONS.BODY_OPEN]}\n <div id=\"react-view\">${App || ''}</div>\n <script\n id=\"inj\"\n type=\"application/javascript\"\n ${ops.noCsp ? '' : `nonce=\"${req.nonce}\"`}\n >\n window.INJ=\"${INJ}\"\n </script>\n ${scriptChunkString}\n ${grouppedExtraScripts[SCRIPT_LOCATIONS.DEFAULT]}\n </body>\n </html>`;\n\n const status = ssrContext.status || 200;\n if (status !== 200) res.status(status);\n\n if (cacheRef && status < 500) {\n // Note: waiting for the caching to complete is not strictly necessary,\n // but it greately simplifies testing, and error reporting.\n await new Promise((done, failed) => {\n brotliCompress(html, (error, buffer) => {\n if (error) failed(error);\n else {\n buffer.nonce = req.nonce; // eslint-disable-line no-param-reassign\n cache.add({ buffer, status }, cacheRef.key);\n done();\n }\n });\n });\n }\n\n // Note: as caching code above may throw in some cases, sending response\n // before it completes will likely hide the error, making it difficult\n // to debug. Thus, at least for now, lets send response after it.\n res.send(html);\n } catch (error) {\n next(error);\n }\n };\n}\n"],"mappings":"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"}