@atlaskit/media-file-preview 0.11.7 → 0.11.8

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @atlaskit/media-file-preview
2
2
 
3
+ ## 0.11.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [`eec573b4a7a6a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/eec573b4a7a6a) -
8
+ Added srcset for Media to remove dual fetching and implememted invisible image along blob
9
+ converison during SSR phase prior to hydration to avoid VC offenses
10
+ - Updated dependencies
11
+
3
12
  ## 0.11.7
4
13
 
5
14
  ### Patch Changes
@@ -37,17 +37,27 @@ var extendAndCachePreview = function extendAndCachePreview(id, mode, preview, me
37
37
  dataURI: dataURI
38
38
  });
39
39
  };
40
+ var getDataUri = function getDataUri(mediaClient, id, params, mediaBlobUrlAttrs) {
41
+ var rawDataURI = mediaClient.getImageUrlSync(id, params);
42
+ return mediaBlobUrlAttrs ? (0, _mediaClient.addFileAttrsToUrl)(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
43
+ };
40
44
  var getSSRPreview = exports.getSSRPreview = function getSSRPreview(ssr, mediaClient, id, params, mediaBlobUrlAttrs) {
41
- var dataURI;
42
45
  try {
43
- var rawDataURI = mediaClient.getImageUrlSync(id, params);
44
- // We want to embed some meta context into dataURI for Copy/Paste to work.
45
- dataURI = mediaBlobUrlAttrs ? (0, _mediaClient.addFileAttrsToUrl)(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
46
+ var dataURI = getDataUri(mediaClient, id, params, mediaBlobUrlAttrs);
47
+ var srcSet = "".concat(dataURI, " 1x");
48
+ if (params.width) {
49
+ var doubleDataURI = getDataUri(mediaClient, id, _objectSpread(_objectSpread({}, params), {}, {
50
+ width: params.width * 2
51
+ }), mediaBlobUrlAttrs);
52
+ // We want to embed some meta context into dataURI for Copy/Paste to work.
53
+ srcSet += ", ".concat(doubleDataURI, " 2x");
54
+ }
46
55
  var source = ssr === 'client' ? 'ssr-client' : 'ssr-server';
47
56
  return {
48
57
  dataURI: dataURI,
49
58
  source: source,
50
- orientation: 1
59
+ orientation: 1,
60
+ srcSet: srcSet
51
61
  };
52
62
  } catch (e) {
53
63
  var reason = ssr === 'server' ? 'ssr-server-uri' : 'ssr-client-uri';
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
@@ -7,7 +8,10 @@ exports.getKey = exports.generateScriptProps = exports.GLOBAL_MEDIA_NAMESPACE =
7
8
  exports.getMediaCardSSR = getMediaCardSSR;
8
9
  exports.getMediaGlobalScope = getMediaGlobalScope;
9
10
  exports.storeDataURI = void 0;
11
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
12
  var _printScript = require("./printScript");
13
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
14
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
11
15
  // ----- WARNING -----
12
16
  // This is a very sensitive fraction of code.
13
17
  // Any changes to this file must be tested directly in product before merging.
@@ -44,23 +48,70 @@ var getKey = exports.getKey = function getKey(_ref) {
44
48
  occurrenceKey = _ref.occurrenceKey;
45
49
  return "".concat(id).concat(dashed(collectionName)).concat(dashed(occurrenceKey));
46
50
  };
47
- var storeDataURI = exports.storeDataURI = function storeDataURI(key, dataURI, dimensions, error) {
48
- var globalScope = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : window;
51
+ var storeDataURI = exports.storeDataURI = function storeDataURI(key, paramDataURI, paramSrcSet, dimensions, error) {
52
+ var globalScope = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : window;
53
+ var featureFlags = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
49
54
  var mediaCardSsr = getMediaCardSSR(globalScope);
50
- mediaCardSsr[key] = {
51
- dataURI: dataURI,
52
- dimensions: dimensions,
53
- error: error
54
- };
55
+ if (featureFlags['media-perf-uplift-mutation-fix']) {
56
+ var _prevData$dimensions, _script;
57
+ var prevData = mediaCardSsr[key];
58
+ var isPreviousImageLarger = prevData && ((_prevData$dimensions = prevData.dimensions) === null || _prevData$dimensions === void 0 ? void 0 : _prevData$dimensions.width) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && prevData.dimensions.width > dimensions.width;
59
+ var srcSet = isPreviousImageLarger ? prevData === null || prevData === void 0 ? void 0 : prevData.srcSet : paramSrcSet;
60
+ var dataURI = isPreviousImageLarger ? prevData === null || prevData === void 0 ? void 0 : prevData.dataURI : paramDataURI;
61
+ var img = (_script = script) === null || _script === void 0 || (_script = _script.parentElement) === null || _script === void 0 ? void 0 : _script.querySelector('img');
62
+ if (img && dataURI) {
63
+ img.src = dataURI;
64
+ }
65
+ if (img && srcSet) {
66
+ img.srcset = srcSet;
67
+ }
68
+
69
+ // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
70
+ img === null || img === void 0 || img.addEventListener('load', function () {
71
+ if (img.currentSrc.startsWith('blob:')) {
72
+ return;
73
+ }
74
+ fetch(img.currentSrc).then(function (res) {
75
+ return res.blob();
76
+ }).then(function (blob) {
77
+ return URL.createObjectURL(blob);
78
+ }).then(function (blobUrl) {
79
+ img.src = blobUrl;
80
+ img.srcset = '';
81
+ mediaCardSsr[key] = _objectSpread(_objectSpread({}, mediaCardSsr[key]), {}, {
82
+ dataURI: blobUrl,
83
+ srcSet: ''
84
+ });
85
+ }).catch(function (err) {
86
+ mediaCardSsr[key] = _objectSpread(_objectSpread({}, mediaCardSsr[key]), {}, {
87
+ error: err
88
+ });
89
+ });
90
+ });
91
+ mediaCardSsr[key] = isPreviousImageLarger ? prevData : {
92
+ dataURI: dataURI,
93
+ dimensions: dimensions,
94
+ error: error,
95
+ srcSet: srcSet
96
+ };
97
+ } else {
98
+ mediaCardSsr[key] = {
99
+ dataURI: paramDataURI,
100
+ dimensions: dimensions,
101
+ error: error
102
+ };
103
+ }
55
104
  };
56
- var generateScript = function generateScript(identifier, dataURI, dimensions, error) {
57
- var functionCall = (0, _printScript.printFunctionCall)(storeDataURI, getKey(identifier), dataURI, dimensions, error);
105
+ var generateScript = function generateScript(identifier, dataURI, srcSet, dimensions, error) {
106
+ var featureFlags = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
107
+ var functionCall = (0, _printScript.printFunctionCall)(storeDataURI, getKey(identifier), dataURI, srcSet, dimensions, error, featureFlags);
58
108
  return (0, _printScript.printScript)([getMediaCardSSR.toString(), getMediaGlobalScope.toString(), functionCall]);
59
109
  };
60
- var generateScriptProps = exports.generateScriptProps = function generateScriptProps(identifier, dataURI, dimensions, error) {
110
+ var generateScriptProps = exports.generateScriptProps = function generateScriptProps(identifier, dataURI, srcSet, dimensions, error) {
111
+ var featureFlags = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
61
112
  return {
62
113
  dangerouslySetInnerHTML: {
63
- __html: generateScript(identifier, dataURI, dimensions, error)
114
+ __html: generateScript(identifier, dataURI, srcSet, dimensions, error, featureFlags)
64
115
  }
65
116
  };
66
117
  };
@@ -31,6 +31,7 @@ var printFunctionCall = exports.printFunctionCall = function printFunctionCall(f
31
31
  // Removing the script tag after execution to prevent hydration
32
32
  // mismatch issues after SSR. We don't want to render different
33
33
  // HTML on the client and server https://react.dev/reference/react-dom/client/hydrateRoot
34
+ // Note: document.currentScript gets incorrectly transpiled to globalThis.currentScript so we need to use it here to avoid transpilation
34
35
  var printScript = exports.printScript = function printScript(statements) {
35
- return "(function(){\n \t\t\t ".concat(statements.join(';'), "\n \t\t\tdocument.currentScript.remove();\n\t\t})();\n\t\t");
36
+ return "(function(){\n\t\t\t let script = document.currentScript;\n \t\t\t ".concat(statements.join(';'), "\n\t\t\t document.currentScript.remove();\n\t\t})();\n\t\t");
36
37
  };
@@ -20,6 +20,16 @@ var _globalScope = require("./globalScope");
20
20
  var _helpers = require("./helpers");
21
21
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
22
22
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
23
+ // invisible gif for SSR preview to show the underlying spinner until the src is replaced by
24
+ // the actual image src in the inline script
25
+ var DEFAULT_SSR_PREVIEW = {
26
+ dataURI: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
27
+ dimensions: {
28
+ width: 100,
29
+ height: 100
30
+ },
31
+ source: 'ssr-server'
32
+ };
23
33
  var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
24
34
  var _ref$resizeMode = _ref.resizeMode,
25
35
  resizeMode = _ref$resizeMode === void 0 ? 'crop' : _ref$resizeMode,
@@ -110,11 +120,13 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
110
120
  }
111
121
  } else {
112
122
  var _dimensions = ssrData.dimensions,
113
- dataURI = ssrData.dataURI;
123
+ dataURI = ssrData.dataURI,
124
+ srcSet = ssrData.srcSet;
114
125
  return {
115
126
  dataURI: dataURI,
116
127
  dimensions: _dimensions,
117
- source: 'ssr-data'
128
+ source: 'ssr-data',
129
+ srcSet: srcSet
118
130
  };
119
131
  }
120
132
  }
@@ -235,6 +247,10 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
235
247
  else if (!error && !nonCriticalError && (!preview || (0, _helpers.isBigger)(preview.dimensions, requestDimensions) ||
236
248
  // We always refetch SSR preview to be able to browser-cache a version without the token in the query parameters
237
249
  (0, _getPreview.isSSRPreview)(preview)) && !skipRemote && upfrontPreviewStatus === 'resolved' && isBackendPreviewReady) {
250
+ // If the preview is SSR and it's a blob URL, we can skip the refetch
251
+ if (preview && (0, _getPreview.isSSRPreview)(preview) && preview.dataURI.startsWith('blob:') && (0, _platformFeatureFlags.fg)('media-perf-uplift-mutation-fix')) {
252
+ return;
253
+ }
238
254
  setIsLoading(true);
239
255
  getAndCacheRemotePreviewRef.current().then(setPreview).catch(function (e) {
240
256
  var wrappedError = (0, _errors.ensureMediaFilePreviewError)('preview-fetch', e);
@@ -320,7 +336,9 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
320
336
  // FOR SSR
321
337
  var getSsrScriptProps = ssr === 'server' ? function () {
322
338
  var _ssrReliabilityRef$cu;
323
- return (0, _globalScope.generateScriptProps)(identifier, preview === null || preview === void 0 ? void 0 : preview.dataURI, requestDimensions, ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined);
339
+ return (0, _globalScope.generateScriptProps)(identifier, preview === null || preview === void 0 ? void 0 : preview.dataURI, preview === null || preview === void 0 ? void 0 : preview.srcSet, requestDimensions, ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined, {
340
+ 'media-perf-uplift-mutation-fix': (0, _platformFeatureFlags.fg)('media-perf-uplift-mutation-fix')
341
+ });
324
342
  } : undefined;
325
343
  var _useCopyIntent = (0, _mediaClientReact.useCopyIntent)(identifier.id, {
326
344
  collectionName: identifier.collectionName
@@ -330,7 +348,7 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
330
348
  // CXP-2723 TODO: should consider simplifying our analytics, and how
331
349
  // we might get rid of ssrReliabiltyRef from our hook
332
350
  return {
333
- preview: preview,
351
+ preview: ssr === 'server' && (0, _platformFeatureFlags.fg)('media-perf-uplift-mutation-fix') ? DEFAULT_SSR_PREVIEW : preview,
334
352
  status: status,
335
353
  error: error,
336
354
  nonCriticalError: nonCriticalError,
@@ -27,17 +27,28 @@ const extendAndCachePreview = (id, mode, preview, mediaBlobUrlAttrs) => {
27
27
  dataURI
28
28
  };
29
29
  };
30
+ const getDataUri = (mediaClient, id, params, mediaBlobUrlAttrs) => {
31
+ const rawDataURI = mediaClient.getImageUrlSync(id, params);
32
+ return mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
33
+ };
30
34
  export const getSSRPreview = (ssr, mediaClient, id, params, mediaBlobUrlAttrs) => {
31
- let dataURI;
32
35
  try {
33
- const rawDataURI = mediaClient.getImageUrlSync(id, params);
34
- // We want to embed some meta context into dataURI for Copy/Paste to work.
35
- dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
36
+ const dataURI = getDataUri(mediaClient, id, params, mediaBlobUrlAttrs);
37
+ let srcSet = `${dataURI} 1x`;
38
+ if (params.width) {
39
+ const doubleDataURI = getDataUri(mediaClient, id, {
40
+ ...params,
41
+ width: params.width * 2
42
+ }, mediaBlobUrlAttrs);
43
+ // We want to embed some meta context into dataURI for Copy/Paste to work.
44
+ srcSet += `, ${doubleDataURI} 2x`;
45
+ }
36
46
  const source = ssr === 'client' ? 'ssr-client' : 'ssr-server';
37
47
  return {
38
48
  dataURI,
39
49
  source,
40
- orientation: 1
50
+ orientation: 1,
51
+ srcSet
41
52
  };
42
53
  } catch (e) {
43
54
  const reason = ssr === 'server' ? 'ssr-server-uri' : 'ssr-client-uri';
@@ -30,20 +30,62 @@ export const getKey = ({
30
30
  collectionName,
31
31
  occurrenceKey
32
32
  }) => `${id}${dashed(collectionName)}${dashed(occurrenceKey)}`;
33
- export const storeDataURI = (key, dataURI, dimensions, error, globalScope = window) => {
33
+ export const storeDataURI = (key, paramDataURI, paramSrcSet, dimensions, error, globalScope = window, featureFlags = {}) => {
34
34
  const mediaCardSsr = getMediaCardSSR(globalScope);
35
- mediaCardSsr[key] = {
36
- dataURI,
37
- dimensions,
38
- error
39
- };
35
+ if (featureFlags['media-perf-uplift-mutation-fix']) {
36
+ var _prevData$dimensions, _script, _script$parentElement;
37
+ const prevData = mediaCardSsr[key];
38
+ const isPreviousImageLarger = prevData && ((_prevData$dimensions = prevData.dimensions) === null || _prevData$dimensions === void 0 ? void 0 : _prevData$dimensions.width) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && prevData.dimensions.width > dimensions.width;
39
+ const srcSet = isPreviousImageLarger ? prevData === null || prevData === void 0 ? void 0 : prevData.srcSet : paramSrcSet;
40
+ const dataURI = isPreviousImageLarger ? prevData === null || prevData === void 0 ? void 0 : prevData.dataURI : paramDataURI;
41
+ const img = (_script = script) === null || _script === void 0 ? void 0 : (_script$parentElement = _script.parentElement) === null || _script$parentElement === void 0 ? void 0 : _script$parentElement.querySelector('img');
42
+ if (img && dataURI) {
43
+ img.src = dataURI;
44
+ }
45
+ if (img && srcSet) {
46
+ img.srcset = srcSet;
47
+ }
48
+
49
+ // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
50
+ img === null || img === void 0 ? void 0 : img.addEventListener('load', () => {
51
+ if (img.currentSrc.startsWith('blob:')) {
52
+ return;
53
+ }
54
+ fetch(img.currentSrc).then(res => res.blob()).then(blob => URL.createObjectURL(blob)).then(blobUrl => {
55
+ img.src = blobUrl;
56
+ img.srcset = '';
57
+ mediaCardSsr[key] = {
58
+ ...mediaCardSsr[key],
59
+ dataURI: blobUrl,
60
+ srcSet: ''
61
+ };
62
+ }).catch(err => {
63
+ mediaCardSsr[key] = {
64
+ ...mediaCardSsr[key],
65
+ error: err
66
+ };
67
+ });
68
+ });
69
+ mediaCardSsr[key] = isPreviousImageLarger ? prevData : {
70
+ dataURI,
71
+ dimensions,
72
+ error,
73
+ srcSet
74
+ };
75
+ } else {
76
+ mediaCardSsr[key] = {
77
+ dataURI: paramDataURI,
78
+ dimensions,
79
+ error
80
+ };
81
+ }
40
82
  };
41
- const generateScript = (identifier, dataURI, dimensions, error) => {
42
- const functionCall = printFunctionCall(storeDataURI, getKey(identifier), dataURI, dimensions, error);
83
+ const generateScript = (identifier, dataURI, srcSet, dimensions, error, featureFlags = {}) => {
84
+ const functionCall = printFunctionCall(storeDataURI, getKey(identifier), dataURI, srcSet, dimensions, error, featureFlags);
43
85
  return printScript([getMediaCardSSR.toString(), getMediaGlobalScope.toString(), functionCall]);
44
86
  };
45
- export const generateScriptProps = (identifier, dataURI, dimensions, error) => ({
87
+ export const generateScriptProps = (identifier, dataURI, srcSet, dimensions, error, featureFlags = {}) => ({
46
88
  dangerouslySetInnerHTML: {
47
- __html: generateScript(identifier, dataURI, dimensions, error)
89
+ __html: generateScript(identifier, dataURI, srcSet, dimensions, error, featureFlags)
48
90
  }
49
91
  });
@@ -14,8 +14,10 @@ export const printFunctionCall = (fn, ...args) => `(${fn.toString()})(${printPar
14
14
  // Removing the script tag after execution to prevent hydration
15
15
  // mismatch issues after SSR. We don't want to render different
16
16
  // HTML on the client and server https://react.dev/reference/react-dom/client/hydrateRoot
17
+ // Note: document.currentScript gets incorrectly transpiled to globalThis.currentScript so we need to use it here to avoid transpilation
17
18
  export const printScript = statements => `(function(){
19
+ let script = document.currentScript;
18
20
  ${statements.join(';')}
19
- document.currentScript.remove();
21
+ document.currentScript.remove();
20
22
  })();
21
23
  `;
@@ -9,6 +9,16 @@ import { ensureMediaFilePreviewError, ImageLoadError, MediaFilePreviewError } fr
9
9
  import { getAndCacheLocalPreview, getAndCacheRemotePreview, getSSRPreview, isLocalPreview, isRemotePreview, isSSRClientPreview, isSSRDataPreview, isSSRPreview, isSupportedLocalPreview, mediaFilePreviewCache } from './getPreview';
10
10
  import { generateScriptProps, getSSRData } from './globalScope';
11
11
  import { createRequestDimensions, isBigger, useCurrentValueRef } from './helpers';
12
+ // invisible gif for SSR preview to show the underlying spinner until the src is replaced by
13
+ // the actual image src in the inline script
14
+ const DEFAULT_SSR_PREVIEW = {
15
+ dataURI: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
16
+ dimensions: {
17
+ width: 100,
18
+ height: 100
19
+ },
20
+ source: 'ssr-server'
21
+ };
12
22
  export const useFilePreview = ({
13
23
  resizeMode = 'crop',
14
24
  identifier,
@@ -83,12 +93,14 @@ export const useFilePreview = ({
83
93
  } else {
84
94
  const {
85
95
  dimensions,
86
- dataURI
96
+ dataURI,
97
+ srcSet
87
98
  } = ssrData;
88
99
  return {
89
100
  dataURI,
90
101
  dimensions,
91
- source: 'ssr-data'
102
+ source: 'ssr-data',
103
+ srcSet
92
104
  };
93
105
  }
94
106
  }
@@ -207,6 +219,10 @@ export const useFilePreview = ({
207
219
  else if (!error && !nonCriticalError && (!preview || isBigger(preview.dimensions, requestDimensions) ||
208
220
  // We always refetch SSR preview to be able to browser-cache a version without the token in the query parameters
209
221
  isSSRPreview(preview)) && !skipRemote && upfrontPreviewStatus === 'resolved' && isBackendPreviewReady) {
222
+ // If the preview is SSR and it's a blob URL, we can skip the refetch
223
+ if (preview && isSSRPreview(preview) && preview.dataURI.startsWith('blob:') && fg('media-perf-uplift-mutation-fix')) {
224
+ return;
225
+ }
210
226
  setIsLoading(true);
211
227
  getAndCacheRemotePreviewRef.current().then(setPreview).catch(e => {
212
228
  const wrappedError = ensureMediaFilePreviewError('preview-fetch', e);
@@ -292,7 +308,9 @@ export const useFilePreview = ({
292
308
  // FOR SSR
293
309
  const getSsrScriptProps = ssr === 'server' ? () => {
294
310
  var _ssrReliabilityRef$cu;
295
- return generateScriptProps(identifier, preview === null || preview === void 0 ? void 0 : preview.dataURI, requestDimensions, ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined);
311
+ return generateScriptProps(identifier, preview === null || preview === void 0 ? void 0 : preview.dataURI, preview === null || preview === void 0 ? void 0 : preview.srcSet, requestDimensions, ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined, {
312
+ 'media-perf-uplift-mutation-fix': fg('media-perf-uplift-mutation-fix')
313
+ });
296
314
  } : undefined;
297
315
  const {
298
316
  copyNodeRef
@@ -303,7 +321,7 @@ export const useFilePreview = ({
303
321
  // CXP-2723 TODO: should consider simplifying our analytics, and how
304
322
  // we might get rid of ssrReliabiltyRef from our hook
305
323
  return {
306
- preview,
324
+ preview: ssr === 'server' && fg('media-perf-uplift-mutation-fix') ? DEFAULT_SSR_PREVIEW : preview,
307
325
  status,
308
326
  error,
309
327
  nonCriticalError,
@@ -30,17 +30,27 @@ var extendAndCachePreview = function extendAndCachePreview(id, mode, preview, me
30
30
  dataURI: dataURI
31
31
  });
32
32
  };
33
+ var getDataUri = function getDataUri(mediaClient, id, params, mediaBlobUrlAttrs) {
34
+ var rawDataURI = mediaClient.getImageUrlSync(id, params);
35
+ return mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
36
+ };
33
37
  export var getSSRPreview = function getSSRPreview(ssr, mediaClient, id, params, mediaBlobUrlAttrs) {
34
- var dataURI;
35
38
  try {
36
- var rawDataURI = mediaClient.getImageUrlSync(id, params);
37
- // We want to embed some meta context into dataURI for Copy/Paste to work.
38
- dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
39
+ var dataURI = getDataUri(mediaClient, id, params, mediaBlobUrlAttrs);
40
+ var srcSet = "".concat(dataURI, " 1x");
41
+ if (params.width) {
42
+ var doubleDataURI = getDataUri(mediaClient, id, _objectSpread(_objectSpread({}, params), {}, {
43
+ width: params.width * 2
44
+ }), mediaBlobUrlAttrs);
45
+ // We want to embed some meta context into dataURI for Copy/Paste to work.
46
+ srcSet += ", ".concat(doubleDataURI, " 2x");
47
+ }
39
48
  var source = ssr === 'client' ? 'ssr-client' : 'ssr-server';
40
49
  return {
41
50
  dataURI: dataURI,
42
51
  source: source,
43
- orientation: 1
52
+ orientation: 1,
53
+ srcSet: srcSet
44
54
  };
45
55
  } catch (e) {
46
56
  var reason = ssr === 'server' ? 'ssr-server-uri' : 'ssr-client-uri';
@@ -1,3 +1,6 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1
4
  import { printFunctionCall, printScript } from './printScript';
2
5
  // ----- WARNING -----
3
6
  // This is a very sensitive fraction of code.
@@ -35,23 +38,70 @@ export var getKey = function getKey(_ref) {
35
38
  occurrenceKey = _ref.occurrenceKey;
36
39
  return "".concat(id).concat(dashed(collectionName)).concat(dashed(occurrenceKey));
37
40
  };
38
- export var storeDataURI = function storeDataURI(key, dataURI, dimensions, error) {
39
- var globalScope = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : window;
41
+ export var storeDataURI = function storeDataURI(key, paramDataURI, paramSrcSet, dimensions, error) {
42
+ var globalScope = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : window;
43
+ var featureFlags = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
40
44
  var mediaCardSsr = getMediaCardSSR(globalScope);
41
- mediaCardSsr[key] = {
42
- dataURI: dataURI,
43
- dimensions: dimensions,
44
- error: error
45
- };
45
+ if (featureFlags['media-perf-uplift-mutation-fix']) {
46
+ var _prevData$dimensions, _script;
47
+ var prevData = mediaCardSsr[key];
48
+ var isPreviousImageLarger = prevData && ((_prevData$dimensions = prevData.dimensions) === null || _prevData$dimensions === void 0 ? void 0 : _prevData$dimensions.width) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && prevData.dimensions.width > dimensions.width;
49
+ var srcSet = isPreviousImageLarger ? prevData === null || prevData === void 0 ? void 0 : prevData.srcSet : paramSrcSet;
50
+ var dataURI = isPreviousImageLarger ? prevData === null || prevData === void 0 ? void 0 : prevData.dataURI : paramDataURI;
51
+ var img = (_script = script) === null || _script === void 0 || (_script = _script.parentElement) === null || _script === void 0 ? void 0 : _script.querySelector('img');
52
+ if (img && dataURI) {
53
+ img.src = dataURI;
54
+ }
55
+ if (img && srcSet) {
56
+ img.srcset = srcSet;
57
+ }
58
+
59
+ // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
60
+ img === null || img === void 0 || img.addEventListener('load', function () {
61
+ if (img.currentSrc.startsWith('blob:')) {
62
+ return;
63
+ }
64
+ fetch(img.currentSrc).then(function (res) {
65
+ return res.blob();
66
+ }).then(function (blob) {
67
+ return URL.createObjectURL(blob);
68
+ }).then(function (blobUrl) {
69
+ img.src = blobUrl;
70
+ img.srcset = '';
71
+ mediaCardSsr[key] = _objectSpread(_objectSpread({}, mediaCardSsr[key]), {}, {
72
+ dataURI: blobUrl,
73
+ srcSet: ''
74
+ });
75
+ }).catch(function (err) {
76
+ mediaCardSsr[key] = _objectSpread(_objectSpread({}, mediaCardSsr[key]), {}, {
77
+ error: err
78
+ });
79
+ });
80
+ });
81
+ mediaCardSsr[key] = isPreviousImageLarger ? prevData : {
82
+ dataURI: dataURI,
83
+ dimensions: dimensions,
84
+ error: error,
85
+ srcSet: srcSet
86
+ };
87
+ } else {
88
+ mediaCardSsr[key] = {
89
+ dataURI: paramDataURI,
90
+ dimensions: dimensions,
91
+ error: error
92
+ };
93
+ }
46
94
  };
47
- var generateScript = function generateScript(identifier, dataURI, dimensions, error) {
48
- var functionCall = printFunctionCall(storeDataURI, getKey(identifier), dataURI, dimensions, error);
95
+ var generateScript = function generateScript(identifier, dataURI, srcSet, dimensions, error) {
96
+ var featureFlags = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
97
+ var functionCall = printFunctionCall(storeDataURI, getKey(identifier), dataURI, srcSet, dimensions, error, featureFlags);
49
98
  return printScript([getMediaCardSSR.toString(), getMediaGlobalScope.toString(), functionCall]);
50
99
  };
51
- export var generateScriptProps = function generateScriptProps(identifier, dataURI, dimensions, error) {
100
+ export var generateScriptProps = function generateScriptProps(identifier, dataURI, srcSet, dimensions, error) {
101
+ var featureFlags = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
52
102
  return {
53
103
  dangerouslySetInnerHTML: {
54
- __html: generateScript(identifier, dataURI, dimensions, error)
104
+ __html: generateScript(identifier, dataURI, srcSet, dimensions, error, featureFlags)
55
105
  }
56
106
  };
57
107
  };
@@ -24,6 +24,7 @@ export var printFunctionCall = function printFunctionCall(fn) {
24
24
  // Removing the script tag after execution to prevent hydration
25
25
  // mismatch issues after SSR. We don't want to render different
26
26
  // HTML on the client and server https://react.dev/reference/react-dom/client/hydrateRoot
27
+ // Note: document.currentScript gets incorrectly transpiled to globalThis.currentScript so we need to use it here to avoid transpilation
27
28
  export var printScript = function printScript(statements) {
28
- return "(function(){\n \t\t\t ".concat(statements.join(';'), "\n \t\t\tdocument.currentScript.remove();\n\t\t})();\n\t\t");
29
+ return "(function(){\n\t\t\t let script = document.currentScript;\n \t\t\t ".concat(statements.join(';'), "\n\t\t\t document.currentScript.remove();\n\t\t})();\n\t\t");
29
30
  };
@@ -13,6 +13,16 @@ import { ensureMediaFilePreviewError, ImageLoadError, MediaFilePreviewError } fr
13
13
  import { getAndCacheLocalPreview, getAndCacheRemotePreview, getSSRPreview, isLocalPreview, isRemotePreview, isSSRClientPreview, isSSRDataPreview, isSSRPreview, isSupportedLocalPreview, mediaFilePreviewCache } from './getPreview';
14
14
  import { generateScriptProps, getSSRData } from './globalScope';
15
15
  import { createRequestDimensions, isBigger, useCurrentValueRef } from './helpers';
16
+ // invisible gif for SSR preview to show the underlying spinner until the src is replaced by
17
+ // the actual image src in the inline script
18
+ var DEFAULT_SSR_PREVIEW = {
19
+ dataURI: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
20
+ dimensions: {
21
+ width: 100,
22
+ height: 100
23
+ },
24
+ source: 'ssr-server'
25
+ };
16
26
  export var useFilePreview = function useFilePreview(_ref) {
17
27
  var _ref$resizeMode = _ref.resizeMode,
18
28
  resizeMode = _ref$resizeMode === void 0 ? 'crop' : _ref$resizeMode,
@@ -103,11 +113,13 @@ export var useFilePreview = function useFilePreview(_ref) {
103
113
  }
104
114
  } else {
105
115
  var _dimensions = ssrData.dimensions,
106
- dataURI = ssrData.dataURI;
116
+ dataURI = ssrData.dataURI,
117
+ srcSet = ssrData.srcSet;
107
118
  return {
108
119
  dataURI: dataURI,
109
120
  dimensions: _dimensions,
110
- source: 'ssr-data'
121
+ source: 'ssr-data',
122
+ srcSet: srcSet
111
123
  };
112
124
  }
113
125
  }
@@ -228,6 +240,10 @@ export var useFilePreview = function useFilePreview(_ref) {
228
240
  else if (!error && !nonCriticalError && (!preview || isBigger(preview.dimensions, requestDimensions) ||
229
241
  // We always refetch SSR preview to be able to browser-cache a version without the token in the query parameters
230
242
  isSSRPreview(preview)) && !skipRemote && upfrontPreviewStatus === 'resolved' && isBackendPreviewReady) {
243
+ // If the preview is SSR and it's a blob URL, we can skip the refetch
244
+ if (preview && isSSRPreview(preview) && preview.dataURI.startsWith('blob:') && fg('media-perf-uplift-mutation-fix')) {
245
+ return;
246
+ }
231
247
  setIsLoading(true);
232
248
  getAndCacheRemotePreviewRef.current().then(setPreview).catch(function (e) {
233
249
  var wrappedError = ensureMediaFilePreviewError('preview-fetch', e);
@@ -313,7 +329,9 @@ export var useFilePreview = function useFilePreview(_ref) {
313
329
  // FOR SSR
314
330
  var getSsrScriptProps = ssr === 'server' ? function () {
315
331
  var _ssrReliabilityRef$cu;
316
- return generateScriptProps(identifier, preview === null || preview === void 0 ? void 0 : preview.dataURI, requestDimensions, ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined);
332
+ return generateScriptProps(identifier, preview === null || preview === void 0 ? void 0 : preview.dataURI, preview === null || preview === void 0 ? void 0 : preview.srcSet, requestDimensions, ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined, {
333
+ 'media-perf-uplift-mutation-fix': fg('media-perf-uplift-mutation-fix')
334
+ });
317
335
  } : undefined;
318
336
  var _useCopyIntent = useCopyIntent(identifier.id, {
319
337
  collectionName: identifier.collectionName
@@ -323,7 +341,7 @@ export var useFilePreview = function useFilePreview(_ref) {
323
341
  // CXP-2723 TODO: should consider simplifying our analytics, and how
324
342
  // we might get rid of ssrReliabiltyRef from our hook
325
343
  return {
326
- preview: preview,
344
+ preview: ssr === 'server' && fg('media-perf-uplift-mutation-fix') ? DEFAULT_SSR_PREVIEW : preview,
327
345
  status: status,
328
346
  error: error,
329
347
  nonCriticalError: nonCriticalError,
@@ -8,8 +8,12 @@ export declare const GLOBAL_MEDIA_NAMESPACE = "__MEDIA_INTERNAL";
8
8
  export type MediaGlobalScope = {
9
9
  [GLOBAL_MEDIA_CARD_SSR]?: MediaCardSsr;
10
10
  };
11
+ type MediaFeatureFlags = {
12
+ 'media-perf-uplift-mutation-fix'?: boolean;
13
+ };
11
14
  export declare function getMediaGlobalScope(globalScope?: any): MediaGlobalScope;
12
15
  export declare function getMediaCardSSR(globalScope?: any): MediaCardSsr;
13
16
  export declare const getKey: ({ id, collectionName, occurrenceKey }: FileIdentifier) => string;
14
- export declare const storeDataURI: (key: string, dataURI?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo, globalScope?: any) => void;
15
- export declare const generateScriptProps: (identifier: FileIdentifier, dataURI?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo) => React.ScriptHTMLAttributes<HTMLScriptElement>;
17
+ export declare const storeDataURI: (key: string, paramDataURI?: string, paramSrcSet?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo, globalScope?: any, featureFlags?: MediaFeatureFlags) => void;
18
+ export declare const generateScriptProps: (identifier: FileIdentifier, dataURI?: string, srcSet?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo, featureFlags?: MediaFeatureFlags) => React.ScriptHTMLAttributes<HTMLScriptElement>;
19
+ export {};
@@ -4,5 +4,6 @@ export type MediaCardSsrData = {
4
4
  dataURI?: string;
5
5
  dimensions?: Partial<NumericalCardDimensions>;
6
6
  error?: MediaFilePreviewErrorInfo;
7
+ srcSet?: string;
7
8
  };
8
9
  export type MediaCardSsr = Record<string, MediaCardSsrData>;
@@ -5,6 +5,7 @@ export type MediaFilePreviewDimensions = {
5
5
  };
6
6
  export interface MediaFilePreview {
7
7
  dataURI: string;
8
+ srcSet?: string;
8
9
  orientation?: number;
9
10
  dimensions?: MediaFilePreviewDimensions;
10
11
  source: MediaFilePreviewSource;
@@ -8,8 +8,12 @@ export declare const GLOBAL_MEDIA_NAMESPACE = "__MEDIA_INTERNAL";
8
8
  export type MediaGlobalScope = {
9
9
  [GLOBAL_MEDIA_CARD_SSR]?: MediaCardSsr;
10
10
  };
11
+ type MediaFeatureFlags = {
12
+ 'media-perf-uplift-mutation-fix'?: boolean;
13
+ };
11
14
  export declare function getMediaGlobalScope(globalScope?: any): MediaGlobalScope;
12
15
  export declare function getMediaCardSSR(globalScope?: any): MediaCardSsr;
13
16
  export declare const getKey: ({ id, collectionName, occurrenceKey }: FileIdentifier) => string;
14
- export declare const storeDataURI: (key: string, dataURI?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo, globalScope?: any) => void;
15
- export declare const generateScriptProps: (identifier: FileIdentifier, dataURI?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo) => React.ScriptHTMLAttributes<HTMLScriptElement>;
17
+ export declare const storeDataURI: (key: string, paramDataURI?: string, paramSrcSet?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo, globalScope?: any, featureFlags?: MediaFeatureFlags) => void;
18
+ export declare const generateScriptProps: (identifier: FileIdentifier, dataURI?: string, srcSet?: string, dimensions?: Partial<NumericalCardDimensions>, error?: MediaFilePreviewErrorInfo, featureFlags?: MediaFeatureFlags) => React.ScriptHTMLAttributes<HTMLScriptElement>;
19
+ export {};
@@ -4,5 +4,6 @@ export type MediaCardSsrData = {
4
4
  dataURI?: string;
5
5
  dimensions?: Partial<NumericalCardDimensions>;
6
6
  error?: MediaFilePreviewErrorInfo;
7
+ srcSet?: string;
7
8
  };
8
9
  export type MediaCardSsr = Record<string, MediaCardSsrData>;
@@ -5,6 +5,7 @@ export type MediaFilePreviewDimensions = {
5
5
  };
6
6
  export interface MediaFilePreview {
7
7
  dataURI: string;
8
+ srcSet?: string;
8
9
  orientation?: number;
9
10
  dimensions?: MediaFilePreviewDimensions;
10
11
  source: MediaFilePreviewSource;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/media-file-preview",
3
- "version": "0.11.7",
3
+ "version": "0.11.8",
4
4
  "description": "A React Hook to fetch and render file previews. It's overloaded with fancy features like SSR, lazy loading, memory cache and local preview.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -30,12 +30,12 @@
30
30
  "sideEffects": false,
31
31
  "atlaskit:src": "src/index.ts",
32
32
  "dependencies": {
33
- "@atlaskit/media-client": "^35.3.0",
33
+ "@atlaskit/media-client": "^35.5.0",
34
34
  "@atlaskit/media-client-react": "^4.1.0",
35
35
  "@atlaskit/media-common": "^12.3.0",
36
- "@atlaskit/media-ui": "^28.6.0",
36
+ "@atlaskit/media-ui": "^28.7.0",
37
37
  "@atlaskit/platform-feature-flags": "^1.1.0",
38
- "@atlaskit/react-ufo": "^4.5.0",
38
+ "@atlaskit/react-ufo": "^4.12.0",
39
39
  "@babel/runtime": "^7.0.0",
40
40
  "eventemitter2": "^4.1.0",
41
41
  "lru_map": "^0.4.1"
@@ -94,6 +94,9 @@
94
94
  "platform-feature-flags": {
95
95
  "platform_close_image_blindspot_2": {
96
96
  "type": "boolean"
97
+ },
98
+ "media-perf-uplift-mutation-fix": {
99
+ "type": "boolean"
97
100
  }
98
101
  }
99
102
  }