@tramvai/module-render 2.70.1 → 2.72.0

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,26 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var fetch = require('node-fetch');
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
10
+
11
+ const thirtySeconds = 1000 * 30;
12
+ const getFileContentLength = async (url) => {
13
+ const info = await fetch__default["default"](url, { method: 'HEAD', timeout: thirtySeconds });
14
+ return info.headers.get('content-length');
15
+ };
16
+ const getFile = async (url) => {
17
+ const fileResponse = await fetch__default["default"](url, { timeout: thirtySeconds });
18
+ if (fileResponse.ok) {
19
+ const file = await fileResponse.text();
20
+ return file;
21
+ }
22
+ return undefined;
23
+ };
24
+
25
+ exports.getFile = getFile;
26
+ exports.getFileContentLength = getFileContentLength;
@@ -0,0 +1,31 @@
1
+ import { resolve } from '@tinkoff/url';
2
+ import startsWith from '@tinkoff/utils/string/startsWith';
3
+ import { ResourceType } from '@tramvai/tokens-render';
4
+
5
+ const URL_OCCURRENCES_RE = /(url\((['"]?))(.*?)(\2\))/gi;
6
+ const isAbsoluteUrl = (resourceUrl) => ['http://', 'https://', '//'].some((prefix) => startsWith(prefix, resourceUrl));
7
+ const toHttpsUrl = (resourceUrl) => {
8
+ if (resourceUrl.indexOf('//localhost') !== -1) {
9
+ return resourceUrl;
10
+ }
11
+ if (startsWith('http://', resourceUrl)) {
12
+ return resourceUrl.replace('http://', 'https://');
13
+ }
14
+ if (startsWith('//', resourceUrl)) {
15
+ return resourceUrl.replace('//', 'https://');
16
+ }
17
+ return resourceUrl;
18
+ };
19
+ const urlReplacerCreator = (resourceUrl) => (str, leftGroup, _, extractedUrl, rightGroup) => {
20
+ return isAbsoluteUrl(extractedUrl)
21
+ ? str
22
+ : `${leftGroup}${resolve(toHttpsUrl(resourceUrl), extractedUrl)}${rightGroup}`;
23
+ };
24
+ const processFile = (resource, file) => {
25
+ if (resource.type === ResourceType.style) {
26
+ return file.replace(URL_OCCURRENCES_RE, urlReplacerCreator(resource.payload));
27
+ }
28
+ return file;
29
+ };
30
+
31
+ export { URL_OCCURRENCES_RE, processFile };
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var url = require('@tinkoff/url');
6
+ var startsWith = require('@tinkoff/utils/string/startsWith');
7
+ var tokensRender = require('@tramvai/tokens-render');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ var startsWith__default = /*#__PURE__*/_interopDefaultLegacy(startsWith);
12
+
13
+ const URL_OCCURRENCES_RE = /(url\((['"]?))(.*?)(\2\))/gi;
14
+ const isAbsoluteUrl = (resourceUrl) => ['http://', 'https://', '//'].some((prefix) => startsWith__default["default"](prefix, resourceUrl));
15
+ const toHttpsUrl = (resourceUrl) => {
16
+ if (resourceUrl.indexOf('//localhost') !== -1) {
17
+ return resourceUrl;
18
+ }
19
+ if (startsWith__default["default"]('http://', resourceUrl)) {
20
+ return resourceUrl.replace('http://', 'https://');
21
+ }
22
+ if (startsWith__default["default"]('//', resourceUrl)) {
23
+ return resourceUrl.replace('//', 'https://');
24
+ }
25
+ return resourceUrl;
26
+ };
27
+ const urlReplacerCreator = (resourceUrl) => (str, leftGroup, _, extractedUrl, rightGroup) => {
28
+ return isAbsoluteUrl(extractedUrl)
29
+ ? str
30
+ : `${leftGroup}${url.resolve(toHttpsUrl(resourceUrl), extractedUrl)}${rightGroup}`;
31
+ };
32
+ const processFile = (resource, file) => {
33
+ if (resource.type === tokensRender.ResourceType.style) {
34
+ return file.replace(URL_OCCURRENCES_RE, urlReplacerCreator(resource.payload));
35
+ }
36
+ return file;
37
+ };
38
+
39
+ exports.URL_OCCURRENCES_RE = URL_OCCURRENCES_RE;
40
+ exports.processFile = processFile;
@@ -0,0 +1,204 @@
1
+ import isUndefined from '@tinkoff/utils/is/undefined';
2
+ import isEmpty from '@tinkoff/utils/is/empty';
3
+ import { ResourceType } from '@tramvai/tokens-render';
4
+ import { isAbsoluteUrl } from '@tinkoff/url';
5
+ import { getFile, getFileContentLength } from './externalFilesHelper.es.js';
6
+ import { processFile } from './fileProcessor.es.js';
7
+
8
+ const INTERNAL_CACHE_SIZE = 50;
9
+ const ASSETS_PREFIX = process.env.NODE_ENV === 'development' &&
10
+ (process.env.ASSETS_PREFIX === 'static' || !process.env.ASSETS_PREFIX)
11
+ ? `http://localhost:${process.env.PORT_STATIC}/dist/`
12
+ : process.env.ASSETS_PREFIX;
13
+ const getInlineType = (type) => {
14
+ switch (type) {
15
+ case ResourceType.style:
16
+ return ResourceType.inlineStyle;
17
+ case ResourceType.script:
18
+ return ResourceType.inlineScript;
19
+ default:
20
+ return type;
21
+ }
22
+ };
23
+ const getResourceUrl = (resource) => {
24
+ if (isEmpty(resource.payload) || !isAbsoluteUrl(resource.payload)) {
25
+ return undefined;
26
+ }
27
+ return resource.payload.startsWith('//')
28
+ ? `https://${resource.payload.substr(2)}`
29
+ : resource.payload;
30
+ };
31
+ class ResourcesInliner {
32
+ constructor({ resourcesRegistryCache, resourceInlineThreshold, logger }) {
33
+ this.internalFilesCache = new Map();
34
+ this.runningRequests = new Set();
35
+ this.scheduleFileLoad = async (resource, resourceInlineThreshold) => {
36
+ const url = getResourceUrl(resource);
37
+ const requestKey = `file${url}`;
38
+ const filesCache = this.getFilesCache(url);
39
+ const result = filesCache.get(url);
40
+ if (result) {
41
+ return result;
42
+ }
43
+ if (!this.runningRequests.has(requestKey)) {
44
+ this.runningRequests.add(url);
45
+ try {
46
+ const file = await getFile(url);
47
+ if (file === undefined) {
48
+ this.resourcesRegistryCache.disabledUrlsCache.set(url, true);
49
+ return;
50
+ }
51
+ const size = file.length;
52
+ if (size < resourceInlineThreshold) {
53
+ filesCache.set(url, processFile(resource, file));
54
+ }
55
+ this.resourcesRegistryCache.sizeCache.set(url, size);
56
+ }
57
+ catch (error) {
58
+ this.log.warn({
59
+ event: 'file-load-failed',
60
+ url,
61
+ error,
62
+ });
63
+ }
64
+ finally {
65
+ this.runningRequests.delete(requestKey);
66
+ }
67
+ }
68
+ };
69
+ this.scheduleFileSizeLoad = async (resource, resourceInlineThreshold) => {
70
+ const url = getResourceUrl(resource);
71
+ const requestKey = `size${url}`;
72
+ const result = this.resourcesRegistryCache.sizeCache.get(url);
73
+ if (result) {
74
+ return result;
75
+ }
76
+ if (!this.runningRequests.has(requestKey)) {
77
+ this.runningRequests.add(requestKey);
78
+ try {
79
+ const contentLength = await getFileContentLength(url);
80
+ const size = isUndefined(contentLength) ? 0 : +contentLength;
81
+ if (size) {
82
+ this.resourcesRegistryCache.sizeCache.set(url, size);
83
+ }
84
+ if (size < resourceInlineThreshold) {
85
+ this.scheduleFileLoad(resource, resourceInlineThreshold);
86
+ }
87
+ }
88
+ catch (error) {
89
+ this.log.warn({
90
+ event: 'file-content-length-load-failed',
91
+ url,
92
+ error,
93
+ });
94
+ }
95
+ finally {
96
+ this.runningRequests.delete(requestKey);
97
+ }
98
+ }
99
+ };
100
+ this.resourcesRegistryCache = resourcesRegistryCache;
101
+ this.resourceInlineThreshold = resourceInlineThreshold;
102
+ this.log = logger('resources-inliner');
103
+ }
104
+ getFilesCache(url) {
105
+ if (url.startsWith(ASSETS_PREFIX)) {
106
+ // internal resources are resources generated by the current app itself
107
+ // these kind of resources are pretty static and won't be changed while app is running
108
+ // so we can cache it with bare Map and do not care about how to cleanup cache from outdated entries
109
+ return this.internalFilesCache;
110
+ }
111
+ return this.resourcesRegistryCache.filesCache;
112
+ }
113
+ // check that resource's preload-link should be added to render
114
+ shouldAddResource(resource) {
115
+ if (resource.type !== ResourceType.preloadLink) {
116
+ // only checking preload-links
117
+ return true;
118
+ }
119
+ const url = getResourceUrl(resource);
120
+ if (isUndefined(url)) {
121
+ // if url is undefined that file is not in cache
122
+ return true;
123
+ }
124
+ // if file is residing in cache that means it will be inlined in page render
125
+ // therefore no need to have preload-link for the inlined resource
126
+ return !this.getFilesCache(url).has(url);
127
+ }
128
+ // method for check is passed resource should be inlined in HTML-page
129
+ shouldInline(resource) {
130
+ var _a;
131
+ if (!(((_a = this.resourceInlineThreshold) === null || _a === void 0 ? void 0 : _a.types) || []).includes(resource.type)) {
132
+ return false;
133
+ }
134
+ const resourceInlineThreshold = this.resourceInlineThreshold.threshold;
135
+ if (isUndefined(resourceInlineThreshold)) {
136
+ return false;
137
+ }
138
+ const url = getResourceUrl(resource);
139
+ if (isUndefined(url) || this.resourcesRegistryCache.disabledUrlsCache.has(url)) {
140
+ return false;
141
+ }
142
+ const filesCache = this.getFilesCache(url);
143
+ if (filesCache.has(url)) {
144
+ return true;
145
+ }
146
+ if (filesCache === this.internalFilesCache &&
147
+ this.internalFilesCache.size >= INTERNAL_CACHE_SIZE) {
148
+ // if we've exceeded limits for the internal resources cache ignore any new entries
149
+ return false;
150
+ }
151
+ if (!this.resourcesRegistryCache.sizeCache.has(url)) {
152
+ this.scheduleFileSizeLoad(resource, resourceInlineThreshold);
153
+ return false;
154
+ }
155
+ const size = this.resourcesRegistryCache.sizeCache.get(url);
156
+ if (size > resourceInlineThreshold) {
157
+ return false;
158
+ }
159
+ this.scheduleFileLoad(resource, resourceInlineThreshold);
160
+ return false;
161
+ }
162
+ inlineResource(resource) {
163
+ const url = getResourceUrl(resource);
164
+ if (isUndefined(url)) {
165
+ // usually, it should not happen but anyway check it for safety
166
+ return [resource];
167
+ }
168
+ const text = this.getFilesCache(url).get(url);
169
+ if (isEmpty(text)) {
170
+ return [resource];
171
+ }
172
+ const result = [];
173
+ if (process.env.NODE_ENV === 'development') {
174
+ // html comment for debugging inlining in dev mode
175
+ result.push({
176
+ slot: resource.slot,
177
+ type: ResourceType.asIs,
178
+ payload: `<!-- Inlined file ${url} -->`,
179
+ });
180
+ }
181
+ result.push({
182
+ ...resource,
183
+ type: getInlineType(resource.type),
184
+ payload: text,
185
+ });
186
+ if (resource.type === ResourceType.style) {
187
+ // If we don't add data-href then extract-css-chunks-webpack-plugin
188
+ // will add link to resources to the html head (https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/blob/master/src/index.js#L346)
189
+ // wherein link in case of css files plugin will look for a link tag, but we add a style tag
190
+ // so we can't use tag from above and have to generate new one
191
+ result.push({
192
+ slot: resource.slot,
193
+ type: ResourceType.style,
194
+ payload: null,
195
+ attrs: {
196
+ 'data-href': resource.payload,
197
+ },
198
+ });
199
+ }
200
+ return result;
201
+ }
202
+ }
203
+
204
+ export { ResourcesInliner };
@@ -0,0 +1,213 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var isUndefined = require('@tinkoff/utils/is/undefined');
6
+ var isEmpty = require('@tinkoff/utils/is/empty');
7
+ var tokensRender = require('@tramvai/tokens-render');
8
+ var url = require('@tinkoff/url');
9
+ var externalFilesHelper = require('./externalFilesHelper.js');
10
+ var fileProcessor = require('./fileProcessor.js');
11
+
12
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
+
14
+ var isUndefined__default = /*#__PURE__*/_interopDefaultLegacy(isUndefined);
15
+ var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
16
+
17
+ const INTERNAL_CACHE_SIZE = 50;
18
+ const ASSETS_PREFIX = process.env.NODE_ENV === 'development' &&
19
+ (process.env.ASSETS_PREFIX === 'static' || !process.env.ASSETS_PREFIX)
20
+ ? `http://localhost:${process.env.PORT_STATIC}/dist/`
21
+ : process.env.ASSETS_PREFIX;
22
+ const getInlineType = (type) => {
23
+ switch (type) {
24
+ case tokensRender.ResourceType.style:
25
+ return tokensRender.ResourceType.inlineStyle;
26
+ case tokensRender.ResourceType.script:
27
+ return tokensRender.ResourceType.inlineScript;
28
+ default:
29
+ return type;
30
+ }
31
+ };
32
+ const getResourceUrl = (resource) => {
33
+ if (isEmpty__default["default"](resource.payload) || !url.isAbsoluteUrl(resource.payload)) {
34
+ return undefined;
35
+ }
36
+ return resource.payload.startsWith('//')
37
+ ? `https://${resource.payload.substr(2)}`
38
+ : resource.payload;
39
+ };
40
+ class ResourcesInliner {
41
+ constructor({ resourcesRegistryCache, resourceInlineThreshold, logger }) {
42
+ this.internalFilesCache = new Map();
43
+ this.runningRequests = new Set();
44
+ this.scheduleFileLoad = async (resource, resourceInlineThreshold) => {
45
+ const url = getResourceUrl(resource);
46
+ const requestKey = `file${url}`;
47
+ const filesCache = this.getFilesCache(url);
48
+ const result = filesCache.get(url);
49
+ if (result) {
50
+ return result;
51
+ }
52
+ if (!this.runningRequests.has(requestKey)) {
53
+ this.runningRequests.add(url);
54
+ try {
55
+ const file = await externalFilesHelper.getFile(url);
56
+ if (file === undefined) {
57
+ this.resourcesRegistryCache.disabledUrlsCache.set(url, true);
58
+ return;
59
+ }
60
+ const size = file.length;
61
+ if (size < resourceInlineThreshold) {
62
+ filesCache.set(url, fileProcessor.processFile(resource, file));
63
+ }
64
+ this.resourcesRegistryCache.sizeCache.set(url, size);
65
+ }
66
+ catch (error) {
67
+ this.log.warn({
68
+ event: 'file-load-failed',
69
+ url,
70
+ error,
71
+ });
72
+ }
73
+ finally {
74
+ this.runningRequests.delete(requestKey);
75
+ }
76
+ }
77
+ };
78
+ this.scheduleFileSizeLoad = async (resource, resourceInlineThreshold) => {
79
+ const url = getResourceUrl(resource);
80
+ const requestKey = `size${url}`;
81
+ const result = this.resourcesRegistryCache.sizeCache.get(url);
82
+ if (result) {
83
+ return result;
84
+ }
85
+ if (!this.runningRequests.has(requestKey)) {
86
+ this.runningRequests.add(requestKey);
87
+ try {
88
+ const contentLength = await externalFilesHelper.getFileContentLength(url);
89
+ const size = isUndefined__default["default"](contentLength) ? 0 : +contentLength;
90
+ if (size) {
91
+ this.resourcesRegistryCache.sizeCache.set(url, size);
92
+ }
93
+ if (size < resourceInlineThreshold) {
94
+ this.scheduleFileLoad(resource, resourceInlineThreshold);
95
+ }
96
+ }
97
+ catch (error) {
98
+ this.log.warn({
99
+ event: 'file-content-length-load-failed',
100
+ url,
101
+ error,
102
+ });
103
+ }
104
+ finally {
105
+ this.runningRequests.delete(requestKey);
106
+ }
107
+ }
108
+ };
109
+ this.resourcesRegistryCache = resourcesRegistryCache;
110
+ this.resourceInlineThreshold = resourceInlineThreshold;
111
+ this.log = logger('resources-inliner');
112
+ }
113
+ getFilesCache(url) {
114
+ if (url.startsWith(ASSETS_PREFIX)) {
115
+ // internal resources are resources generated by the current app itself
116
+ // these kind of resources are pretty static and won't be changed while app is running
117
+ // so we can cache it with bare Map and do not care about how to cleanup cache from outdated entries
118
+ return this.internalFilesCache;
119
+ }
120
+ return this.resourcesRegistryCache.filesCache;
121
+ }
122
+ // check that resource's preload-link should be added to render
123
+ shouldAddResource(resource) {
124
+ if (resource.type !== tokensRender.ResourceType.preloadLink) {
125
+ // only checking preload-links
126
+ return true;
127
+ }
128
+ const url = getResourceUrl(resource);
129
+ if (isUndefined__default["default"](url)) {
130
+ // if url is undefined that file is not in cache
131
+ return true;
132
+ }
133
+ // if file is residing in cache that means it will be inlined in page render
134
+ // therefore no need to have preload-link for the inlined resource
135
+ return !this.getFilesCache(url).has(url);
136
+ }
137
+ // method for check is passed resource should be inlined in HTML-page
138
+ shouldInline(resource) {
139
+ var _a;
140
+ if (!(((_a = this.resourceInlineThreshold) === null || _a === void 0 ? void 0 : _a.types) || []).includes(resource.type)) {
141
+ return false;
142
+ }
143
+ const resourceInlineThreshold = this.resourceInlineThreshold.threshold;
144
+ if (isUndefined__default["default"](resourceInlineThreshold)) {
145
+ return false;
146
+ }
147
+ const url = getResourceUrl(resource);
148
+ if (isUndefined__default["default"](url) || this.resourcesRegistryCache.disabledUrlsCache.has(url)) {
149
+ return false;
150
+ }
151
+ const filesCache = this.getFilesCache(url);
152
+ if (filesCache.has(url)) {
153
+ return true;
154
+ }
155
+ if (filesCache === this.internalFilesCache &&
156
+ this.internalFilesCache.size >= INTERNAL_CACHE_SIZE) {
157
+ // if we've exceeded limits for the internal resources cache ignore any new entries
158
+ return false;
159
+ }
160
+ if (!this.resourcesRegistryCache.sizeCache.has(url)) {
161
+ this.scheduleFileSizeLoad(resource, resourceInlineThreshold);
162
+ return false;
163
+ }
164
+ const size = this.resourcesRegistryCache.sizeCache.get(url);
165
+ if (size > resourceInlineThreshold) {
166
+ return false;
167
+ }
168
+ this.scheduleFileLoad(resource, resourceInlineThreshold);
169
+ return false;
170
+ }
171
+ inlineResource(resource) {
172
+ const url = getResourceUrl(resource);
173
+ if (isUndefined__default["default"](url)) {
174
+ // usually, it should not happen but anyway check it for safety
175
+ return [resource];
176
+ }
177
+ const text = this.getFilesCache(url).get(url);
178
+ if (isEmpty__default["default"](text)) {
179
+ return [resource];
180
+ }
181
+ const result = [];
182
+ if (process.env.NODE_ENV === 'development') {
183
+ // html comment for debugging inlining in dev mode
184
+ result.push({
185
+ slot: resource.slot,
186
+ type: tokensRender.ResourceType.asIs,
187
+ payload: `<!-- Inlined file ${url} -->`,
188
+ });
189
+ }
190
+ result.push({
191
+ ...resource,
192
+ type: getInlineType(resource.type),
193
+ payload: text,
194
+ });
195
+ if (resource.type === tokensRender.ResourceType.style) {
196
+ // If we don't add data-href then extract-css-chunks-webpack-plugin
197
+ // will add link to resources to the html head (https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/blob/master/src/index.js#L346)
198
+ // wherein link in case of css files plugin will look for a link tag, but we add a style tag
199
+ // so we can't use tag from above and have to generate new one
200
+ result.push({
201
+ slot: resource.slot,
202
+ type: tokensRender.ResourceType.style,
203
+ payload: null,
204
+ attrs: {
205
+ 'data-href': resource.payload,
206
+ },
207
+ });
208
+ }
209
+ return result;
210
+ }
211
+ }
212
+
213
+ exports.ResourcesInliner = ResourcesInliner;
@@ -0,0 +1,15 @@
1
+ import { createToken } from '@tinkoff/dippy';
2
+
3
+ /**
4
+ * @description
5
+ * Инлайнер ресурсов - используется на сервере для регистрации файлов, которые должны быть вставлены
6
+ * в итоговую html-страницу в виде ссылки на файл или заинлайнеными полностью
7
+ */
8
+ const RESOURCE_INLINER = createToken('resourceInliner');
9
+ /**
10
+ * @description
11
+ * Кэш загруженных ресурсов.
12
+ */
13
+ const RESOURCES_REGISTRY_CACHE = createToken('resourcesRegistryCache');
14
+
15
+ export { RESOURCES_REGISTRY_CACHE, RESOURCE_INLINER };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var dippy = require('@tinkoff/dippy');
6
+
7
+ /**
8
+ * @description
9
+ * Инлайнер ресурсов - используется на сервере для регистрации файлов, которые должны быть вставлены
10
+ * в итоговую html-страницу в виде ссылки на файл или заинлайнеными полностью
11
+ */
12
+ const RESOURCE_INLINER = dippy.createToken('resourceInliner');
13
+ /**
14
+ * @description
15
+ * Кэш загруженных ресурсов.
16
+ */
17
+ const RESOURCES_REGISTRY_CACHE = dippy.createToken('resourcesRegistryCache');
18
+
19
+ exports.RESOURCES_REGISTRY_CACHE = RESOURCES_REGISTRY_CACHE;
20
+ exports.RESOURCE_INLINER = RESOURCE_INLINER;
@@ -0,0 +1,28 @@
1
+ import toArray from '@tinkoff/utils/array/toArray';
2
+
3
+ class ResourcesRegistry {
4
+ constructor({ resourceInliner }) {
5
+ this.resources = new Set();
6
+ this.resourceInliner = resourceInliner;
7
+ }
8
+ register(resourceOrResources) {
9
+ toArray(resourceOrResources).forEach((resource) => {
10
+ this.resources.add(resource);
11
+ });
12
+ }
13
+ getPageResources() {
14
+ return Array.from(this.resources.values())
15
+ .reduce((acc, resource) => {
16
+ if (this.resourceInliner.shouldInline(resource)) {
17
+ Array.prototype.push.apply(acc, this.resourceInliner.inlineResource(resource));
18
+ }
19
+ else {
20
+ acc.push(resource);
21
+ }
22
+ return acc;
23
+ }, [])
24
+ .filter((resource) => this.resourceInliner.shouldAddResource(resource));
25
+ }
26
+ }
27
+
28
+ export { ResourcesRegistry };
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var toArray = require('@tinkoff/utils/array/toArray');
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var toArray__default = /*#__PURE__*/_interopDefaultLegacy(toArray);
10
+
11
+ class ResourcesRegistry {
12
+ constructor({ resourceInliner }) {
13
+ this.resources = new Set();
14
+ this.resourceInliner = resourceInliner;
15
+ }
16
+ register(resourceOrResources) {
17
+ toArray__default["default"](resourceOrResources).forEach((resource) => {
18
+ this.resources.add(resource);
19
+ });
20
+ }
21
+ getPageResources() {
22
+ return Array.from(this.resources.values())
23
+ .reduce((acc, resource) => {
24
+ if (this.resourceInliner.shouldInline(resource)) {
25
+ Array.prototype.push.apply(acc, this.resourceInliner.inlineResource(resource));
26
+ }
27
+ else {
28
+ acc.push(resource);
29
+ }
30
+ return acc;
31
+ }, [])
32
+ .filter((resource) => this.resourceInliner.shouldAddResource(resource));
33
+ }
34
+ }
35
+
36
+ exports.ResourcesRegistry = ResourcesRegistry;