@tramvai/module-render 2.70.1 → 2.72.3

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 (58) hide show
  1. package/lib/browser.js +9 -233
  2. package/lib/client/index.browser.js +48 -0
  3. package/lib/client/renderer.browser.js +50 -0
  4. package/lib/react/index.browser.js +11 -0
  5. package/lib/react/index.es.js +11 -0
  6. package/lib/react/index.js +15 -0
  7. package/lib/react/pageErrorBoundary.browser.js +23 -0
  8. package/lib/react/pageErrorBoundary.es.js +23 -0
  9. package/lib/react/pageErrorBoundary.js +27 -0
  10. package/lib/react/root.browser.js +58 -0
  11. package/lib/react/root.es.js +58 -0
  12. package/lib/react/root.js +62 -0
  13. package/lib/resourcesInliner/externalFilesHelper.es.js +17 -0
  14. package/lib/resourcesInliner/externalFilesHelper.js +26 -0
  15. package/lib/resourcesInliner/fileProcessor.es.js +31 -0
  16. package/lib/resourcesInliner/fileProcessor.js +40 -0
  17. package/lib/resourcesInliner/resourcesInliner.es.js +204 -0
  18. package/lib/resourcesInliner/resourcesInliner.js +213 -0
  19. package/lib/resourcesInliner/tokens.es.js +15 -0
  20. package/lib/resourcesInliner/tokens.js +20 -0
  21. package/lib/resourcesRegistry/index.es.js +28 -0
  22. package/lib/resourcesRegistry/index.js +36 -0
  23. package/lib/server/PageBuilder.es.js +93 -0
  24. package/lib/server/PageBuilder.js +102 -0
  25. package/lib/server/ReactRenderServer.es.js +90 -0
  26. package/lib/server/ReactRenderServer.js +98 -0
  27. package/lib/server/blocks/bundleResource/bundleResource.es.js +62 -0
  28. package/lib/server/blocks/bundleResource/bundleResource.js +71 -0
  29. package/lib/server/blocks/polyfill.es.js +35 -0
  30. package/lib/server/blocks/polyfill.js +39 -0
  31. package/lib/{server_inline.inline.es.js → server/blocks/preload/onload.inline.es.js} +1 -1
  32. package/lib/{server_inline.inline.js → server/blocks/preload/onload.inline.js} +2 -0
  33. package/lib/server/blocks/preload/preloadBlock.es.js +21 -0
  34. package/lib/server/blocks/preload/preloadBlock.js +30 -0
  35. package/lib/server/blocks/utils/fetchWebpackStats.es.js +88 -0
  36. package/lib/server/blocks/utils/fetchWebpackStats.js +115 -0
  37. package/lib/server/blocks/utils/flushFiles.es.js +33 -0
  38. package/lib/server/blocks/utils/flushFiles.js +44 -0
  39. package/lib/server/blocks/utils/requireFunc.es.js +5 -0
  40. package/lib/server/blocks/utils/requireFunc.js +9 -0
  41. package/lib/server/constants/performance.es.js +3 -0
  42. package/lib/server/constants/performance.js +7 -0
  43. package/lib/server/htmlPageSchema.es.js +33 -0
  44. package/lib/server/htmlPageSchema.js +37 -0
  45. package/lib/server/utils.es.js +16 -0
  46. package/lib/server/utils.js +20 -0
  47. package/lib/server.es.js +18 -859
  48. package/lib/server.js +33 -909
  49. package/lib/shared/LayoutModule.browser.js +40 -0
  50. package/lib/shared/LayoutModule.es.js +40 -0
  51. package/lib/shared/LayoutModule.js +42 -0
  52. package/lib/shared/pageErrorStore.browser.js +19 -0
  53. package/lib/shared/pageErrorStore.es.js +19 -0
  54. package/lib/shared/pageErrorStore.js +26 -0
  55. package/lib/shared/providers.browser.js +18 -0
  56. package/lib/shared/providers.es.js +18 -0
  57. package/lib/shared/providers.js +22 -0
  58. package/package.json +23 -24
@@ -0,0 +1,88 @@
1
+ import * as path from 'path';
2
+ import fetch from 'node-fetch';
3
+ import { requireFunc } from './requireFunc.es.js';
4
+
5
+ let appConfig;
6
+ try {
7
+ appConfig = require('@tramvai/cli/lib/external/config').appConfig;
8
+ }
9
+ catch (e) { }
10
+ let fetchStats = async () => {
11
+ throw new Error(`Unknown environment`);
12
+ };
13
+ if (process.env.NODE_ENV === 'development') {
14
+ fetchStats = async () => {
15
+ const { modern: configModern, staticHost, staticPort, output } = appConfig;
16
+ const getUrl = (filename) => `http://${staticHost}:${staticPort}/${output.client}/${filename}`;
17
+ const request = await fetch(getUrl(configModern ? 'stats.modern.json' : 'stats.json'));
18
+ const stats = await request.json();
19
+ // static - популярная заглушка в env.development.js файлах, надо игнорировать, как было раньше
20
+ const hasAssetsPrefix = process.env.ASSETS_PREFIX && process.env.ASSETS_PREFIX !== 'static';
21
+ const publicPath = hasAssetsPrefix ? process.env.ASSETS_PREFIX : stats.publicPath;
22
+ return {
23
+ ...stats,
24
+ publicPath,
25
+ };
26
+ };
27
+ }
28
+ if (process.env.NODE_ENV === 'test') {
29
+ fetchStats = () => {
30
+ // mock for unit-testing as there is no real static return something just to make server render work
31
+ return Promise.resolve({ publicPath: 'http://localhost:4000/', assetsByChunkName: {} });
32
+ };
33
+ }
34
+ if (process.env.NODE_ENV === 'production') {
35
+ const SEARCH_PATHS = [process.cwd(), __dirname];
36
+ const webpackStats = (fileName) => {
37
+ let stats;
38
+ for (const dir of SEARCH_PATHS) {
39
+ try {
40
+ const statsPath = path.resolve(dir, fileName);
41
+ stats = requireFunc(statsPath);
42
+ break;
43
+ }
44
+ catch (e) {
45
+ // ignore errors as this function is used to load stats for several optional destinations
46
+ // and these destinations may not have stats file
47
+ }
48
+ }
49
+ if (!stats) {
50
+ return;
51
+ }
52
+ if (!process.env.ASSETS_PREFIX) {
53
+ if (process.env.STATIC_PREFIX) {
54
+ throw new Error('Required env variable "ASSETS_PREFIX" is not set. Instead of using "STATIC_PREFIX" env please define "ASSETS_PREFIX: STATIC_PREFIX + /compiled"');
55
+ }
56
+ throw new Error('Required env variable "ASSETS_PREFIX" is not set');
57
+ }
58
+ return {
59
+ ...stats,
60
+ publicPath: process.env.ASSETS_PREFIX,
61
+ };
62
+ };
63
+ const statsLegacy = webpackStats('stats.json');
64
+ const statsModern = webpackStats('stats.modern.json') || statsLegacy;
65
+ if (!statsLegacy) {
66
+ throw new Error(`Cannot find stats.json.
67
+ It should be placed in one of the next places:
68
+ ${SEARCH_PATHS.join('\n\t')}
69
+ In case it happens on deployment:
70
+ - In case you are using two independent jobs for building app
71
+ - Either do not split build command by two independent jobs and use one common job with "tramvai build" command without --buildType
72
+ - Or copy stats.json (and stats.modern.json if present) file from client build output to server output by yourself in your CI
73
+ - Otherwise report issue to tramvai team
74
+ In case it happens locally:
75
+ - prefer to use command "tramvai start-prod" to test prod-build locally
76
+ - copy stats.json next to built server.js file
77
+ `);
78
+ }
79
+ fetchStats = (modern) => {
80
+ const stats = modern ? statsModern : statsLegacy;
81
+ return Promise.resolve(stats);
82
+ };
83
+ }
84
+ const fetchWebpackStats = async ({ modern, } = {}) => {
85
+ return fetchStats(modern);
86
+ };
87
+
88
+ export { fetchWebpackStats };
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var path = require('path');
6
+ var fetch = require('node-fetch');
7
+ var requireFunc = require('./requireFunc.js');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n["default"] = e;
26
+ return n;
27
+ }
28
+
29
+ var path__namespace = /*#__PURE__*/_interopNamespace(path);
30
+ var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
31
+
32
+ let appConfig;
33
+ try {
34
+ appConfig = require('@tramvai/cli/lib/external/config').appConfig;
35
+ }
36
+ catch (e) { }
37
+ let fetchStats = async () => {
38
+ throw new Error(`Unknown environment`);
39
+ };
40
+ if (process.env.NODE_ENV === 'development') {
41
+ fetchStats = async () => {
42
+ const { modern: configModern, staticHost, staticPort, output } = appConfig;
43
+ const getUrl = (filename) => `http://${staticHost}:${staticPort}/${output.client}/${filename}`;
44
+ const request = await fetch__default["default"](getUrl(configModern ? 'stats.modern.json' : 'stats.json'));
45
+ const stats = await request.json();
46
+ // static - популярная заглушка в env.development.js файлах, надо игнорировать, как было раньше
47
+ const hasAssetsPrefix = process.env.ASSETS_PREFIX && process.env.ASSETS_PREFIX !== 'static';
48
+ const publicPath = hasAssetsPrefix ? process.env.ASSETS_PREFIX : stats.publicPath;
49
+ return {
50
+ ...stats,
51
+ publicPath,
52
+ };
53
+ };
54
+ }
55
+ if (process.env.NODE_ENV === 'test') {
56
+ fetchStats = () => {
57
+ // mock for unit-testing as there is no real static return something just to make server render work
58
+ return Promise.resolve({ publicPath: 'http://localhost:4000/', assetsByChunkName: {} });
59
+ };
60
+ }
61
+ if (process.env.NODE_ENV === 'production') {
62
+ const SEARCH_PATHS = [process.cwd(), __dirname];
63
+ const webpackStats = (fileName) => {
64
+ let stats;
65
+ for (const dir of SEARCH_PATHS) {
66
+ try {
67
+ const statsPath = path__namespace.resolve(dir, fileName);
68
+ stats = requireFunc.requireFunc(statsPath);
69
+ break;
70
+ }
71
+ catch (e) {
72
+ // ignore errors as this function is used to load stats for several optional destinations
73
+ // and these destinations may not have stats file
74
+ }
75
+ }
76
+ if (!stats) {
77
+ return;
78
+ }
79
+ if (!process.env.ASSETS_PREFIX) {
80
+ if (process.env.STATIC_PREFIX) {
81
+ throw new Error('Required env variable "ASSETS_PREFIX" is not set. Instead of using "STATIC_PREFIX" env please define "ASSETS_PREFIX: STATIC_PREFIX + /compiled"');
82
+ }
83
+ throw new Error('Required env variable "ASSETS_PREFIX" is not set');
84
+ }
85
+ return {
86
+ ...stats,
87
+ publicPath: process.env.ASSETS_PREFIX,
88
+ };
89
+ };
90
+ const statsLegacy = webpackStats('stats.json');
91
+ const statsModern = webpackStats('stats.modern.json') || statsLegacy;
92
+ if (!statsLegacy) {
93
+ throw new Error(`Cannot find stats.json.
94
+ It should be placed in one of the next places:
95
+ ${SEARCH_PATHS.join('\n\t')}
96
+ In case it happens on deployment:
97
+ - In case you are using two independent jobs for building app
98
+ - Either do not split build command by two independent jobs and use one common job with "tramvai build" command without --buildType
99
+ - Or copy stats.json (and stats.modern.json if present) file from client build output to server output by yourself in your CI
100
+ - Otherwise report issue to tramvai team
101
+ In case it happens locally:
102
+ - prefer to use command "tramvai start-prod" to test prod-build locally
103
+ - copy stats.json next to built server.js file
104
+ `);
105
+ }
106
+ fetchStats = (modern) => {
107
+ const stats = modern ? statsModern : statsLegacy;
108
+ return Promise.resolve(stats);
109
+ };
110
+ }
111
+ const fetchWebpackStats = async ({ modern, } = {}) => {
112
+ return fetchStats(modern);
113
+ };
114
+
115
+ exports.fetchWebpackStats = fetchWebpackStats;
@@ -0,0 +1,33 @@
1
+ import uniq from '@tinkoff/utils/array/uniq';
2
+ import flatten from '@tinkoff/utils/array/flatten';
3
+
4
+ const isJs = (file) => /\.js$/.test(file) && !/\.hot-update\.js$/.test(file);
5
+ const isCss = (file) => /\.css$/.test(file);
6
+ const getFilesByType = (files) => {
7
+ const scripts = files.filter(isJs);
8
+ const styles = files.filter(isCss);
9
+ return {
10
+ scripts,
11
+ styles,
12
+ };
13
+ };
14
+ const flushFiles = (chunks, webpackStats, { ignoreDependencies = false, } = {}) => {
15
+ // при использовании namedChunkGroups во все entry-файлы как зависимость попадает runtimeChunk
16
+ // что при повторных вызовах flushChunks вызовет дублирование подключения manifest.js
17
+ // из-за чего приложение может запускаться несколько раз
18
+ // без поля namedChunkGroups flushChunks вернет только сами ассеты для чанков, без зависимостей
19
+ const { assetsByChunkName, namedChunkGroups } = webpackStats;
20
+ const resolvedChunks = [];
21
+ for (const chunk of chunks) {
22
+ if (!ignoreDependencies && (namedChunkGroups === null || namedChunkGroups === void 0 ? void 0 : namedChunkGroups[chunk])) {
23
+ resolvedChunks.push(...namedChunkGroups[chunk].chunks);
24
+ }
25
+ else {
26
+ resolvedChunks.push(chunk);
27
+ }
28
+ }
29
+ const files = flatten(uniq(resolvedChunks).map((chunk) => assetsByChunkName[chunk]));
30
+ return getFilesByType(files);
31
+ };
32
+
33
+ export { flushFiles, isCss, isJs };
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var uniq = require('@tinkoff/utils/array/uniq');
6
+ var flatten = require('@tinkoff/utils/array/flatten');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ var uniq__default = /*#__PURE__*/_interopDefaultLegacy(uniq);
11
+ var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
12
+
13
+ const isJs = (file) => /\.js$/.test(file) && !/\.hot-update\.js$/.test(file);
14
+ const isCss = (file) => /\.css$/.test(file);
15
+ const getFilesByType = (files) => {
16
+ const scripts = files.filter(isJs);
17
+ const styles = files.filter(isCss);
18
+ return {
19
+ scripts,
20
+ styles,
21
+ };
22
+ };
23
+ const flushFiles = (chunks, webpackStats, { ignoreDependencies = false, } = {}) => {
24
+ // при использовании namedChunkGroups во все entry-файлы как зависимость попадает runtimeChunk
25
+ // что при повторных вызовах flushChunks вызовет дублирование подключения manifest.js
26
+ // из-за чего приложение может запускаться несколько раз
27
+ // без поля namedChunkGroups flushChunks вернет только сами ассеты для чанков, без зависимостей
28
+ const { assetsByChunkName, namedChunkGroups } = webpackStats;
29
+ const resolvedChunks = [];
30
+ for (const chunk of chunks) {
31
+ if (!ignoreDependencies && (namedChunkGroups === null || namedChunkGroups === void 0 ? void 0 : namedChunkGroups[chunk])) {
32
+ resolvedChunks.push(...namedChunkGroups[chunk].chunks);
33
+ }
34
+ else {
35
+ resolvedChunks.push(chunk);
36
+ }
37
+ }
38
+ const files = flatten__default["default"](uniq__default["default"](resolvedChunks).map((chunk) => assetsByChunkName[chunk]));
39
+ return getFilesByType(files);
40
+ };
41
+
42
+ exports.flushFiles = flushFiles;
43
+ exports.isCss = isCss;
44
+ exports.isJs = isJs;
@@ -0,0 +1,5 @@
1
+ const requireFunc =
2
+ // @ts-ignore
3
+ typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
4
+
5
+ export { requireFunc };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const requireFunc =
6
+ // @ts-ignore
7
+ typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
8
+
9
+ exports.requireFunc = requireFunc;
@@ -0,0 +1,3 @@
1
+ const PRELOAD_JS = '__preloadJS';
2
+
3
+ export { PRELOAD_JS };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const PRELOAD_JS = '__preloadJS';
6
+
7
+ exports.PRELOAD_JS = PRELOAD_JS;
@@ -0,0 +1,33 @@
1
+ import { staticRender, dynamicRender } from '@tinkoff/htmlpagebuilder';
2
+ import { ResourceSlot } from '@tramvai/tokens-render';
3
+ import { formatAttributes } from './utils.es.js';
4
+
5
+ const { REACT_RENDER, HEAD_CORE_SCRIPTS, HEAD_DYNAMIC_SCRIPTS, HEAD_META, HEAD_POLYFILLS, HEAD_CORE_STYLES, HEAD_PERFORMANCE, HEAD_ANALYTICS, BODY_START, BODY_END, HEAD_ICONS, BODY_TAIL_ANALYTICS, BODY_TAIL, } = ResourceSlot;
6
+ const htmlPageSchemaFactory = ({ htmlAttrs, }) => {
7
+ return [
8
+ staticRender('<!DOCTYPE html>'),
9
+ staticRender(`<html ${formatAttributes(htmlAttrs, 'html')}>`),
10
+ staticRender('<head>'),
11
+ staticRender('<meta charset="UTF-8">'),
12
+ dynamicRender(HEAD_META),
13
+ dynamicRender(HEAD_PERFORMANCE),
14
+ dynamicRender(HEAD_CORE_STYLES),
15
+ dynamicRender(HEAD_POLYFILLS),
16
+ dynamicRender(HEAD_DYNAMIC_SCRIPTS),
17
+ dynamicRender(HEAD_CORE_SCRIPTS),
18
+ dynamicRender(HEAD_ANALYTICS),
19
+ dynamicRender(HEAD_ICONS),
20
+ staticRender('</head>'),
21
+ staticRender(`<body ${formatAttributes(htmlAttrs, 'body')}>`),
22
+ dynamicRender(BODY_START),
23
+ // react app
24
+ dynamicRender(REACT_RENDER),
25
+ dynamicRender(BODY_END),
26
+ dynamicRender(BODY_TAIL_ANALYTICS),
27
+ dynamicRender(BODY_TAIL),
28
+ staticRender('</body>'),
29
+ staticRender('</html>'),
30
+ ];
31
+ };
32
+
33
+ export { htmlPageSchemaFactory };
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var htmlpagebuilder = require('@tinkoff/htmlpagebuilder');
6
+ var tokensRender = require('@tramvai/tokens-render');
7
+ var utils = require('./utils.js');
8
+
9
+ const { REACT_RENDER, HEAD_CORE_SCRIPTS, HEAD_DYNAMIC_SCRIPTS, HEAD_META, HEAD_POLYFILLS, HEAD_CORE_STYLES, HEAD_PERFORMANCE, HEAD_ANALYTICS, BODY_START, BODY_END, HEAD_ICONS, BODY_TAIL_ANALYTICS, BODY_TAIL, } = tokensRender.ResourceSlot;
10
+ const htmlPageSchemaFactory = ({ htmlAttrs, }) => {
11
+ return [
12
+ htmlpagebuilder.staticRender('<!DOCTYPE html>'),
13
+ htmlpagebuilder.staticRender(`<html ${utils.formatAttributes(htmlAttrs, 'html')}>`),
14
+ htmlpagebuilder.staticRender('<head>'),
15
+ htmlpagebuilder.staticRender('<meta charset="UTF-8">'),
16
+ htmlpagebuilder.dynamicRender(HEAD_META),
17
+ htmlpagebuilder.dynamicRender(HEAD_PERFORMANCE),
18
+ htmlpagebuilder.dynamicRender(HEAD_CORE_STYLES),
19
+ htmlpagebuilder.dynamicRender(HEAD_POLYFILLS),
20
+ htmlpagebuilder.dynamicRender(HEAD_DYNAMIC_SCRIPTS),
21
+ htmlpagebuilder.dynamicRender(HEAD_CORE_SCRIPTS),
22
+ htmlpagebuilder.dynamicRender(HEAD_ANALYTICS),
23
+ htmlpagebuilder.dynamicRender(HEAD_ICONS),
24
+ htmlpagebuilder.staticRender('</head>'),
25
+ htmlpagebuilder.staticRender(`<body ${utils.formatAttributes(htmlAttrs, 'body')}>`),
26
+ htmlpagebuilder.dynamicRender(BODY_START),
27
+ // react app
28
+ htmlpagebuilder.dynamicRender(REACT_RENDER),
29
+ htmlpagebuilder.dynamicRender(BODY_END),
30
+ htmlpagebuilder.dynamicRender(BODY_TAIL_ANALYTICS),
31
+ htmlpagebuilder.dynamicRender(BODY_TAIL),
32
+ htmlpagebuilder.staticRender('</body>'),
33
+ htmlpagebuilder.staticRender('</html>'),
34
+ ];
35
+ };
36
+
37
+ exports.htmlPageSchemaFactory = htmlPageSchemaFactory;
@@ -0,0 +1,16 @@
1
+ const formatAttributes = (htmlAttrs, target) => {
2
+ if (!htmlAttrs) {
3
+ return '';
4
+ }
5
+ const targetAttrs = htmlAttrs.filter((item) => item.target === target);
6
+ const collectedAttrs = targetAttrs.reduce((acc, item) => ({ ...acc, ...item.attrs }), {});
7
+ const attrsString = Object.keys(collectedAttrs).reduce((acc, name) => {
8
+ if (collectedAttrs[name] === true) {
9
+ return `${acc} ${name}`;
10
+ }
11
+ return `${acc} ${name}="${collectedAttrs[name]}"`;
12
+ }, '');
13
+ return attrsString.trim();
14
+ };
15
+
16
+ export { formatAttributes };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const formatAttributes = (htmlAttrs, target) => {
6
+ if (!htmlAttrs) {
7
+ return '';
8
+ }
9
+ const targetAttrs = htmlAttrs.filter((item) => item.target === target);
10
+ const collectedAttrs = targetAttrs.reduce((acc, item) => ({ ...acc, ...item.attrs }), {});
11
+ const attrsString = Object.keys(collectedAttrs).reduce((acc, name) => {
12
+ if (collectedAttrs[name] === true) {
13
+ return `${acc} ${name}`;
14
+ }
15
+ return `${acc} ${name}="${collectedAttrs[name]}"`;
16
+ }, '');
17
+ return attrsString.trim();
18
+ };
19
+
20
+ exports.formatAttributes = formatAttributes;