@khanacademy/wonder-blocks-data 8.0.0 → 8.0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @khanacademy/wonder-blocks-data
2
2
 
3
+ ## 8.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 5f4a4297: Make dependency on `flow-enums-runtime` explicit
8
+ - 2b96fd59: Change flow-enums-runtime to be peer dependencies
9
+ - Updated dependencies [5f4a4297]
10
+ - Updated dependencies [2b96fd59]
11
+ - @khanacademy/wonder-blocks-core@4.3.2
12
+
13
+ ## 8.0.2
14
+
15
+ ### Patch Changes
16
+
17
+ - 580141ed: Always initialize SSR-only cache
18
+
19
+ ## 8.0.1
20
+
21
+ ### Patch Changes
22
+
23
+ - e5fa4d9e: Make sure ssr-only cache is initialized when purging caches in test environment
24
+
3
25
  ## 8.0.0
4
26
 
5
27
  ### Major Changes
package/dist/es/index.js CHANGED
@@ -172,11 +172,10 @@ class SsrCache {
172
172
  };
173
173
 
174
174
  this.getEntry = id => {
175
- var _this$_ssrOnlyCache$g, _this$_ssrOnlyCache;
175
+ const ssrEntry = Server.isServerSide() ? this._ssrOnlyCache.get(DefaultScope$2, id) : null;
176
+ const internalEntry = ssrEntry != null ? ssrEntry : this._hydrationCache.get(DefaultScope$2, id);
176
177
 
177
- const internalEntry = (_this$_ssrOnlyCache$g = (_this$_ssrOnlyCache = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache.get(DefaultScope$2, id)) != null ? _this$_ssrOnlyCache$g : this._hydrationCache.get(DefaultScope$2, id);
178
-
179
- if (this._ssrOnlyCache == null && internalEntry != null) {
178
+ if (!Server.isServerSide() && internalEntry != null) {
180
179
  this._hydrationCache.purge(DefaultScope$2, id);
181
180
  }
182
181
 
@@ -184,13 +183,11 @@ class SsrCache {
184
183
  };
185
184
 
186
185
  this.purgeData = predicate => {
187
- var _this$_ssrOnlyCache2;
188
-
189
186
  const realPredicate = predicate ? (_, key, cachedEntry) => predicate(key, cachedEntry) : undefined;
190
187
 
191
188
  this._hydrationCache.purgeAll(realPredicate);
192
189
 
193
- (_this$_ssrOnlyCache2 = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache2.purgeAll(realPredicate);
190
+ this._ssrOnlyCache.purgeAll(realPredicate);
194
191
  };
195
192
 
196
193
  this.cloneHydratableData = () => {
@@ -201,7 +198,7 @@ class SsrCache {
201
198
  return (_cache$DefaultScope = cache[DefaultScope$2]) != null ? _cache$DefaultScope : {};
202
199
  };
203
200
 
204
- this._ssrOnlyCache = Server.isServerSide() ? ssrOnlyCache || new SerializableInMemoryCache() : undefined;
201
+ this._ssrOnlyCache = ssrOnlyCache || new SerializableInMemoryCache();
205
202
  this._hydrationCache = hydrationCache || new SerializableInMemoryCache();
206
203
  }
207
204
 
@@ -212,9 +209,7 @@ class SsrCache {
212
209
  if (hydrate) {
213
210
  this._hydrationCache.set(DefaultScope$2, id, frozenEntry);
214
211
  } else {
215
- var _this$_ssrOnlyCache3;
216
-
217
- (_this$_ssrOnlyCache3 = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache3.set(DefaultScope$2, id, frozenEntry);
212
+ this._ssrOnlyCache.set(DefaultScope$2, id, frozenEntry);
218
213
  }
219
214
  }
220
215
 
package/dist/index.js CHANGED
@@ -165,6 +165,12 @@ module.exports = require("react");
165
165
 
166
166
  /***/ }),
167
167
  /* 2 */
168
+ /***/ (function(module, exports) {
169
+
170
+ module.exports = require("@khanacademy/wonder-blocks-core");
171
+
172
+ /***/ }),
173
+ /* 3 */
168
174
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
169
175
 
170
176
  "use strict";
@@ -187,12 +193,6 @@ const FetchPolicy = __webpack_require__(22).Mirrored(["CacheBeforeNetwork", "Cac
187
193
  * and functions are not allowed.
188
194
  */
189
195
 
190
- /***/ }),
191
- /* 3 */
192
- /***/ (function(module, exports) {
193
-
194
- module.exports = require("@khanacademy/wonder-blocks-core");
195
-
196
196
  /***/ }),
197
197
  /* 4 */
198
198
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
@@ -556,7 +556,7 @@ class RequestTracker {
556
556
 
557
557
  "use strict";
558
558
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return SsrCache; });
559
- /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
559
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
560
560
  /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
561
561
  /* harmony import */ var _serializable_in_memory_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(13);
562
562
 
@@ -608,14 +608,14 @@ class SsrCache {
608
608
  };
609
609
 
610
610
  this.getEntry = id => {
611
- var _this$_ssrOnlyCache$g, _this$_ssrOnlyCache;
612
-
613
611
  // Get the cached entry for this value.
614
- // We first look in the ssr cache and then the hydration cache.
615
- const internalEntry = (_this$_ssrOnlyCache$g = (_this$_ssrOnlyCache = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache.get(DefaultScope, id)) != null ? _this$_ssrOnlyCache$g : this._hydrationCache.get(DefaultScope, id); // If we are not server-side and we hydrated something, let's clear
612
+ // We first look in the ssr cache, if we need to.
613
+ const ssrEntry = _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() ? this._ssrOnlyCache.get(DefaultScope, id) : null; // Now we defer to the SSR value, and fallback to the hydration cache.
614
+
615
+ const internalEntry = ssrEntry != null ? ssrEntry : this._hydrationCache.get(DefaultScope, id); // If we are not server-side and we hydrated something, let's clear
616
616
  // that from the hydration cache to save memory.
617
617
 
618
- if (this._ssrOnlyCache == null && internalEntry != null) {
618
+ if (!_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() && internalEntry != null) {
619
619
  // We now delete this from our hydration cache as we don't need it.
620
620
  // This does mean that if another handler of the same type but
621
621
  // without some sort of linked cache won't get the value, but
@@ -632,8 +632,6 @@ class SsrCache {
632
632
  };
633
633
 
634
634
  this.purgeData = predicate => {
635
- var _this$_ssrOnlyCache2;
636
-
637
635
  const realPredicate = predicate ? // We know what we're putting into the cache so let's assume it
638
636
  // conforms.
639
637
  // $FlowIgnore[incompatible-call]
@@ -641,7 +639,7 @@ class SsrCache {
641
639
 
642
640
  this._hydrationCache.purgeAll(realPredicate);
643
641
 
644
- (_this$_ssrOnlyCache2 = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache2.purgeAll(realPredicate);
642
+ this._ssrOnlyCache.purgeAll(realPredicate);
645
643
  };
646
644
 
647
645
  this.cloneHydratableData = () => {
@@ -658,7 +656,7 @@ class SsrCache {
658
656
  return (_cache$DefaultScope = cache[DefaultScope]) != null ? _cache$DefaultScope : {};
659
657
  };
660
658
 
661
- this._ssrOnlyCache = _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() ? ssrOnlyCache || new _serializable_in_memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* SerializableInMemoryCache */ "a"]() : undefined;
659
+ this._ssrOnlyCache = ssrOnlyCache || new _serializable_in_memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* SerializableInMemoryCache */ "a"]();
662
660
  this._hydrationCache = hydrationCache || new _serializable_in_memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* SerializableInMemoryCache */ "a"]();
663
661
  }
664
662
 
@@ -671,12 +669,10 @@ class SsrCache {
671
669
  if (hydrate) {
672
670
  this._hydrationCache.set(DefaultScope, id, frozenEntry);
673
671
  } else {
674
- var _this$_ssrOnlyCache3;
675
-
676
672
  // Usually, when server-side, this cache will always be present.
677
673
  // We do fake server-side in our doc example though, when it
678
674
  // won't be.
679
- (_this$_ssrOnlyCache3 = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache3.set(DefaultScope, id, frozenEntry);
675
+ this._ssrOnlyCache.set(DefaultScope, id, frozenEntry);
680
676
  }
681
677
  }
682
678
 
@@ -921,7 +917,7 @@ class ScopedInMemoryCache {
921
917
  /* harmony import */ var _use_server_effect_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(16);
922
918
  /* harmony import */ var _use_shared_cache_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
923
919
  /* harmony import */ var _use_cached_effect_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(17);
924
- /* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(2);
920
+ /* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
925
921
 
926
922
 
927
923
 
@@ -1123,7 +1119,7 @@ const purgeHydrationCache = predicate => _ssr_cache_js__WEBPACK_IMPORTED_MODULE_
1123
1119
 
1124
1120
  "use strict";
1125
1121
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useServerEffect; });
1126
- /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
1122
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
1127
1123
  /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
1128
1124
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1);
1129
1125
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
@@ -1188,14 +1184,14 @@ const useServerEffect = (requestId, handler, options = {}) => {
1188
1184
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useCachedEffect; });
1189
1185
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
1190
1186
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
1191
- /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
1187
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
1192
1188
  /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__);
1193
1189
  /* harmony import */ var _util_data_error_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(0);
1194
1190
  /* harmony import */ var _util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
1195
1191
  /* harmony import */ var _util_status_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6);
1196
1192
  /* harmony import */ var _use_shared_cache_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5);
1197
1193
  /* harmony import */ var _use_request_interception_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(19);
1198
- /* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(2);
1194
+ /* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(3);
1199
1195
 
1200
1196
 
1201
1197
 
@@ -1584,125 +1580,9 @@ const mergeGqlContext = (defaultContext, overrides) => {
1584
1580
 
1585
1581
  /***/ }),
1586
1582
  /* 22 */
1587
- /***/ (function(module, exports, __webpack_require__) {
1588
-
1589
- "use strict";
1590
- /**
1591
- * Copyright (c) Facebook, Inc. and its affiliates.
1592
- *
1593
- * This source code is licensed under the MIT license found in the
1594
- * LICENSE file in the root directory of this source tree.
1595
- */
1596
-
1597
-
1598
-
1599
- // Below we want to use `hasOwnProperty` on an object that doesn't have
1600
- // `Object.prototype` in its proto chain, so we must extract it here.
1601
- var hasOwnProperty = Object.prototype.hasOwnProperty;
1602
-
1603
- // Map from an enum object to a reverse map of its values to names
1604
- var reverseMapCache = typeof WeakMap === 'function' ? new WeakMap() : new Map();
1605
-
1606
- // Computes the reverse mapping of the enum object: from value to name.
1607
- // Flow Enum values are unique (enforced by the parser), so this is a
1608
- // one to one mapping.
1609
- function getReverseMap(enumObject) {
1610
- var reverseMap = reverseMapCache.get(enumObject);
1611
- if (reverseMap !== undefined) {
1612
- return reverseMap;
1613
- }
1614
- // We aren't using `Object.values` because that gets enumerable
1615
- // properties, and our properties aren't enumerable.
1616
- var newReverseMap = new Map();
1617
- Object.getOwnPropertyNames(enumObject).forEach(function (name) {
1618
- newReverseMap.set(enumObject[name], name);
1619
- });
1620
- reverseMapCache.set(enumObject, newReverseMap);
1621
- return newReverseMap;
1622
- }
1623
-
1624
- var EnumPrototype = Object.freeze(
1625
- Object.defineProperties(Object.create(null), {
1626
- isValid: {
1627
- value: function (x) {
1628
- return getReverseMap(this).has(x);
1629
- },
1630
- },
1631
- cast: {
1632
- value: function (x) {
1633
- return this.isValid(x) ? x : undefined;
1634
- },
1635
- },
1636
- members: {
1637
- value: function () {
1638
- return getReverseMap(this).keys();
1639
- },
1640
- },
1641
- getName: {
1642
- value: function (value) {
1643
- return getReverseMap(this).get(value);
1644
- }
1645
- }
1646
- })
1647
- );
1648
-
1649
- // `members` is an object mapping name to value.
1650
- function Enum(members) {
1651
- var o = Object.create(EnumPrototype);
1652
- for (var k in members) {
1653
- if (hasOwnProperty.call(members, k)) {
1654
- // Create non-enumerable properties.
1655
- Object.defineProperty(o, k, {value: members[k]});
1656
- }
1657
- }
1658
- return Object.freeze(o);
1659
- }
1660
-
1661
- // Mirrored enum (string enum with no member initializers).
1662
- // Optimized implementation, taking advantage of the fact that
1663
- // keys and values are identical.
1664
- var EnumMirroredPrototype = Object.freeze(
1665
- Object.defineProperties(Object.create(null), {
1666
- isValid: {
1667
- value: function (x) {
1668
- if (typeof x === 'string') {
1669
- return hasOwnProperty.call(this, x);
1670
- }
1671
- return false;
1672
- },
1673
- },
1674
- cast: {
1675
- value: EnumPrototype.cast,
1676
- },
1677
- members: {
1678
- value: function () {
1679
- // We aren't using `Object.values` because that gets enumerable
1680
- // properties, and our properties aren't enumerable.
1681
- return Object.getOwnPropertyNames(this).values();
1682
- },
1683
- },
1684
- getName: {
1685
- value: function (value) {
1686
- return value;
1687
- }
1688
- }
1689
- })
1690
- );
1691
-
1692
- // `members` is an array of names (which, are also the values).
1693
- Enum.Mirrored = function EnumMirrored(members) {
1694
- var o = Object.create(EnumMirroredPrototype);
1695
- for (var i = 0, len = members.length; i < len; ++i) {
1696
- // Value is same as key. Also, non-enumerable.
1697
- Object.defineProperty(o, members[i], {value: members[i]});
1698
- }
1699
- return Object.freeze(o);
1700
- };
1701
-
1702
- Object.freeze(Enum.Mirrored);
1703
-
1704
- module.exports = Object.freeze(Enum);
1583
+ /***/ (function(module, exports) {
1705
1584
 
1585
+ module.exports = require("flow-enums-runtime");
1706
1586
 
1707
1587
  /***/ }),
1708
1588
  /* 23 */
@@ -1712,7 +1592,7 @@ module.exports = Object.freeze(Enum);
1712
1592
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return fetchTrackedRequests; });
1713
1593
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return hasTrackedRequestsToBeFetched; });
1714
1594
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return abortInflightRequests; });
1715
- /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
1595
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
1716
1596
  /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
1717
1597
  /* harmony import */ var _request_tracking_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
1718
1598
  /* harmony import */ var _request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10);
@@ -1812,7 +1692,7 @@ const purgeCaches = () => {
1812
1692
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TrackData; });
1813
1693
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
1814
1694
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
1815
- /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
1695
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
1816
1696
  /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__);
1817
1697
  /* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
1818
1698
 
@@ -2266,7 +2146,7 @@ const getGqlDataFromResponse = async response => {
2266
2146
 
2267
2147
  "use strict";
2268
2148
  __webpack_require__.r(__webpack_exports__);
2269
- /* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
2149
+ /* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
2270
2150
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "FetchPolicy", function() { return _util_types_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
2271
2151
 
2272
2152
  /* harmony import */ var _util_hydration_cache_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(15);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-data",
3
- "version": "8.0.0",
3
+ "version": "8.0.3",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -14,10 +14,11 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@babel/runtime": "^7.16.3",
17
- "@khanacademy/wonder-blocks-core": "^4.3.1"
17
+ "@khanacademy/wonder-blocks-core": "^4.3.2"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@khanacademy/wonder-stuff-core": "^0.1.2",
21
+ "flow-enums-runtime": "^0.0.6",
21
22
  "react": "16.14.0"
22
23
  },
23
24
  "devDependencies": {
@@ -16,6 +16,54 @@ describe("../ssr-cache.js", () => {
16
16
  jest.restoreAllMocks();
17
17
  });
18
18
 
19
+ describe("#constructor", () => {
20
+ it("should default the ssr-only cache to a cache instance", () => {
21
+ // Arrange
22
+
23
+ // Act
24
+ const cache = new SsrCache();
25
+
26
+ // Assert
27
+ expect(cache._ssrOnlyCache).toBeInstanceOf(
28
+ SerializableInMemoryCache,
29
+ );
30
+ });
31
+
32
+ it("should set the hydration cache to the passed instance if there is one", () => {
33
+ // Arrange
34
+ const passedInstance = new SerializableInMemoryCache();
35
+
36
+ // Act
37
+ const cache = new SsrCache(null, passedInstance);
38
+
39
+ // Assert
40
+ expect(cache._ssrOnlyCache).toBe(passedInstance);
41
+ });
42
+
43
+ it("should default the hydration cache to a cache instance", () => {
44
+ // Arrange
45
+
46
+ // Act
47
+ const cache = new SsrCache();
48
+
49
+ // Assert
50
+ expect(cache._hydrationCache).toBeInstanceOf(
51
+ SerializableInMemoryCache,
52
+ );
53
+ });
54
+
55
+ it("should set the hydration cache to the passed instance if there is one", () => {
56
+ // Arrange
57
+ const passedInstance = new SerializableInMemoryCache();
58
+
59
+ // Act
60
+ const cache = new SsrCache(passedInstance);
61
+
62
+ // Assert
63
+ expect(cache._hydrationCache).toBe(passedInstance);
64
+ });
65
+ });
66
+
19
67
  describe("@Default", () => {
20
68
  it("should return an instance of SsrCache", () => {
21
69
  // Arrange
@@ -26,15 +26,13 @@ export class SsrCache {
26
26
  }
27
27
 
28
28
  _hydrationCache: SerializableInMemoryCache;
29
- _ssrOnlyCache: ?SerializableInMemoryCache;
29
+ _ssrOnlyCache: SerializableInMemoryCache;
30
30
 
31
31
  constructor(
32
32
  hydrationCache: ?SerializableInMemoryCache = null,
33
33
  ssrOnlyCache: ?SerializableInMemoryCache = null,
34
34
  ) {
35
- this._ssrOnlyCache = Server.isServerSide()
36
- ? ssrOnlyCache || new SerializableInMemoryCache()
37
- : undefined;
35
+ this._ssrOnlyCache = ssrOnlyCache || new SerializableInMemoryCache();
38
36
  this._hydrationCache =
39
37
  hydrationCache || new SerializableInMemoryCache();
40
38
  }
@@ -54,7 +52,7 @@ export class SsrCache {
54
52
  // Usually, when server-side, this cache will always be present.
55
53
  // We do fake server-side in our doc example though, when it
56
54
  // won't be.
57
- this._ssrOnlyCache?.set(DefaultScope, id, frozenEntry);
55
+ this._ssrOnlyCache.set(DefaultScope, id, frozenEntry);
58
56
  }
59
57
  }
60
58
  return frozenEntry;
@@ -120,14 +118,18 @@ export class SsrCache {
120
118
  ): ?$ReadOnly<CachedResponse<TData>> => {
121
119
  // Get the cached entry for this value.
122
120
 
123
- // We first look in the ssr cache and then the hydration cache.
121
+ // We first look in the ssr cache, if we need to.
122
+ const ssrEntry = Server.isServerSide()
123
+ ? this._ssrOnlyCache.get(DefaultScope, id)
124
+ : null;
125
+
126
+ // Now we defer to the SSR value, and fallback to the hydration cache.
124
127
  const internalEntry =
125
- this._ssrOnlyCache?.get(DefaultScope, id) ??
126
- this._hydrationCache.get(DefaultScope, id);
128
+ ssrEntry ?? this._hydrationCache.get(DefaultScope, id);
127
129
 
128
130
  // If we are not server-side and we hydrated something, let's clear
129
131
  // that from the hydration cache to save memory.
130
- if (this._ssrOnlyCache == null && internalEntry != null) {
132
+ if (!Server.isServerSide() && internalEntry != null) {
131
133
  // We now delete this from our hydration cache as we don't need it.
132
134
  // This does mean that if another handler of the same type but
133
135
  // without some sort of linked cache won't get the value, but
@@ -165,7 +167,7 @@ export class SsrCache {
165
167
 
166
168
  // Apply the predicate to what we have in our caches.
167
169
  this._hydrationCache.purgeAll(realPredicate);
168
- this._ssrOnlyCache?.purgeAll(realPredicate);
170
+ this._ssrOnlyCache.purgeAll(realPredicate);
169
171
  };
170
172
 
171
173
  /**
@@ -1,337 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`wonder-blocks-data example 1 1`] = `
4
- <div
5
- className=""
6
- style={
7
- Object {
8
- "alignItems": "stretch",
9
- "borderStyle": "solid",
10
- "borderWidth": 0,
11
- "boxSizing": "border-box",
12
- "display": "flex",
13
- "flexDirection": "column",
14
- "margin": 0,
15
- "minHeight": 0,
16
- "minWidth": 0,
17
- "padding": 0,
18
- "position": "relative",
19
- "zIndex": 0,
20
- }
21
- }
22
- >
23
- <div
24
- className=""
25
- style={
26
- Object {
27
- "alignItems": "stretch",
28
- "borderStyle": "solid",
29
- "borderWidth": 0,
30
- "boxSizing": "border-box",
31
- "display": "flex",
32
- "flexDirection": "column",
33
- "margin": 0,
34
- "minHeight": 0,
35
- "minWidth": 0,
36
- "padding": 0,
37
- "position": "relative",
38
- "zIndex": 0,
39
- }
40
- }
41
- >
42
- <span
43
- className=""
44
- style={
45
- Object {
46
- "MozOsxFontSmoothing": "grayscale",
47
- "WebkitFontSmoothing": "antialiased",
48
- "display": "block",
49
- "fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
50
- "fontSize": 16,
51
- "fontWeight": 400,
52
- "lineHeight": "22px",
53
- }
54
- }
55
- >
56
- This request will succeed and give us data!
57
- </span>
58
- Loading...
59
- </div>
60
- <div
61
- aria-hidden="true"
62
- className=""
63
- style={
64
- Object {
65
- "MsFlexBasis": 12,
66
- "MsFlexPreferredSize": 12,
67
- "WebkitFlexBasis": 12,
68
- "alignItems": "stretch",
69
- "borderStyle": "solid",
70
- "borderWidth": 0,
71
- "boxSizing": "border-box",
72
- "display": "flex",
73
- "flexBasis": 12,
74
- "flexDirection": "column",
75
- "flexShrink": 0,
76
- "margin": 0,
77
- "minHeight": 0,
78
- "minWidth": 0,
79
- "padding": 0,
80
- "position": "relative",
81
- "width": 12,
82
- "zIndex": 0,
83
- }
84
- }
85
- />
86
- <div
87
- className=""
88
- style={
89
- Object {
90
- "alignItems": "stretch",
91
- "borderStyle": "solid",
92
- "borderWidth": 0,
93
- "boxSizing": "border-box",
94
- "display": "flex",
95
- "flexDirection": "column",
96
- "margin": 0,
97
- "minHeight": 0,
98
- "minWidth": 0,
99
- "padding": 0,
100
- "position": "relative",
101
- "zIndex": 0,
102
- }
103
- }
104
- >
105
- <span
106
- className=""
107
- style={
108
- Object {
109
- "MozOsxFontSmoothing": "grayscale",
110
- "WebkitFontSmoothing": "antialiased",
111
- "display": "block",
112
- "fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
113
- "fontSize": 16,
114
- "fontWeight": 400,
115
- "lineHeight": "22px",
116
- }
117
- }
118
- >
119
- This request will go boom and give us an error!
120
- </span>
121
- Loading...
122
- </div>
123
- </div>
124
- `;
125
-
126
- exports[`wonder-blocks-data example 2 1`] = `
127
- <div
128
- className=""
129
- style={
130
- Object {
131
- "alignItems": "stretch",
132
- "borderStyle": "solid",
133
- "borderWidth": 0,
134
- "boxSizing": "border-box",
135
- "display": "flex",
136
- "flexDirection": "column",
137
- "margin": 0,
138
- "minHeight": 0,
139
- "minWidth": 0,
140
- "padding": 0,
141
- "position": "relative",
142
- "zIndex": 0,
143
- }
144
- }
145
- >
146
- <div
147
- className=""
148
- style={
149
- Object {
150
- "alignItems": "stretch",
151
- "borderStyle": "solid",
152
- "borderWidth": 0,
153
- "boxSizing": "border-box",
154
- "display": "flex",
155
- "flexDirection": "column",
156
- "margin": 0,
157
- "minHeight": 0,
158
- "minWidth": 0,
159
- "padding": 0,
160
- "position": "relative",
161
- "zIndex": 0,
162
- }
163
- }
164
- >
165
- <span
166
- className=""
167
- style={
168
- Object {
169
- "MozOsxFontSmoothing": "grayscale",
170
- "WebkitFontSmoothing": "antialiased",
171
- "display": "block",
172
- "fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
173
- "fontSize": 16,
174
- "fontWeight": 400,
175
- "lineHeight": "22px",
176
- }
177
- }
178
- >
179
- This cache has data!
180
- </span>
181
- <span
182
- className=""
183
- style={
184
- Object {
185
- "MozOsxFontSmoothing": "grayscale",
186
- "WebkitFontSmoothing": "antialiased",
187
- "display": "block",
188
- "fontFamily": "Inconsolata, monospace",
189
- "fontSize": 17,
190
- "fontWeight": 400,
191
- "lineHeight": "22px",
192
- }
193
- }
194
- >
195
- I'm DATA from the hydration cache
196
- </span>
197
- </div>
198
- </div>
199
- `;
200
-
201
- exports[`wonder-blocks-data example 3 1`] = `
202
- <div
203
- className=""
204
- style={
205
- Object {
206
- "alignItems": "stretch",
207
- "borderStyle": "solid",
208
- "borderWidth": 0,
209
- "boxSizing": "border-box",
210
- "display": "flex",
211
- "flexDirection": "column",
212
- "margin": 0,
213
- "minHeight": 0,
214
- "minWidth": 0,
215
- "padding": 0,
216
- "position": "relative",
217
- "zIndex": 0,
218
- }
219
- }
220
- >
221
- <span
222
- className=""
223
- style={
224
- Object {
225
- "MozOsxFontSmoothing": "grayscale",
226
- "WebkitFontSmoothing": "antialiased",
227
- "display": "block",
228
- "fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
229
- "fontSize": 16,
230
- "fontWeight": 400,
231
- "lineHeight": "22px",
232
- }
233
- }
234
- >
235
- This received intercepted data!
236
- </span>
237
- If you see this, the example is broken!
238
- </div>
239
- `;
240
-
241
- exports[`wonder-blocks-data example 4 1`] = `"Sorry, no snapshot for you"`;
242
-
243
- exports[`wonder-blocks-data example 5 1`] = `
244
- <div
245
- className=""
246
- style={
247
- Object {
248
- "alignItems": "stretch",
249
- "borderStyle": "solid",
250
- "borderWidth": 0,
251
- "boxSizing": "border-box",
252
- "display": "flex",
253
- "flexDirection": "column",
254
- "margin": 0,
255
- "minHeight": 0,
256
- "minWidth": 0,
257
- "padding": 0,
258
- "position": "relative",
259
- "zIndex": 0,
260
- }
261
- }
262
- >
263
- <button
264
- aria-disabled={false}
265
- className=""
266
- onBlur={[Function]}
267
- onClick={[Function]}
268
- onDragStart={[Function]}
269
- onFocus={[Function]}
270
- onKeyDown={[Function]}
271
- onKeyUp={[Function]}
272
- onMouseDown={[Function]}
273
- onMouseEnter={[Function]}
274
- onMouseLeave={[Function]}
275
- onMouseUp={[Function]}
276
- onTouchCancel={[Function]}
277
- onTouchEnd={[Function]}
278
- onTouchStart={[Function]}
279
- role="button"
280
- style={
281
- Object {
282
- "::MozFocusInner": Object {
283
- "border": 0,
284
- },
285
- ":focus": Object {
286
- "WebkitTapHighlightColor": "rgba(0,0,0,0)",
287
- },
288
- "alignItems": "center",
289
- "background": "#1865f2",
290
- "border": "none",
291
- "borderRadius": 4,
292
- "boxSizing": "border-box",
293
- "color": "#ffffff",
294
- "cursor": "pointer",
295
- "display": "inline-flex",
296
- "height": 40,
297
- "justifyContent": "center",
298
- "margin": 0,
299
- "outline": "none",
300
- "paddingBottom": 0,
301
- "paddingLeft": 16,
302
- "paddingRight": 16,
303
- "paddingTop": 0,
304
- "position": "relative",
305
- "textDecoration": "none",
306
- "touchAction": "manipulation",
307
- "userSelect": "none",
308
- }
309
- }
310
- tabIndex={0}
311
- type="button"
312
- >
313
- <span
314
- className=""
315
- style={
316
- Object {
317
- "MozOsxFontSmoothing": "grayscale",
318
- "WebkitFontSmoothing": "antialiased",
319
- "alignItems": "center",
320
- "display": "inline-block",
321
- "fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
322
- "fontSize": 16,
323
- "fontWeight": "bold",
324
- "lineHeight": "20px",
325
- "overflow": "hidden",
326
- "pointerEvents": "none",
327
- "textOverflow": "ellipsis",
328
- "whiteSpace": "nowrap",
329
- }
330
- }
331
- >
332
- Enable Server-side Mode
333
- </span>
334
- </button>
335
- Sorry, no snapshot for you
336
- </div>
337
- `;
@@ -1,350 +0,0 @@
1
- // This file is auto-generated by gen-snapshot-tests.js
2
- // Do not edit this file. To make changes to these snapshot tests:
3
- // 1. edit the markdown documentation files in the package,
4
- // packages/wonder-blocks-data
5
- // 2. Run `yarn run gen-snapshot-tests`.
6
- import React from "react";
7
- import renderer from "react-test-renderer";
8
-
9
- // Mock react-dom as jest doesn't like findDOMNode.
10
- jest.mock("react-dom");
11
- import {Body, BodyMonospace} from "@khanacademy/wonder-blocks-typography";
12
- import {View, Server} from "@khanacademy/wonder-blocks-core";
13
- import {
14
- Data,
15
- initializeHydrationCache,
16
- InterceptRequests,
17
- TrackData,
18
- fetchTrackedRequests,
19
- } from "@khanacademy/wonder-blocks-data";
20
- import {Strut} from "@khanacademy/wonder-blocks-layout";
21
- import Color from "@khanacademy/wonder-blocks-color";
22
- import Spacing from "@khanacademy/wonder-blocks-spacing";
23
- import Button from "@khanacademy/wonder-blocks-button";
24
-
25
- describe("wonder-blocks-data", () => {
26
- it("example 1", () => {
27
- const myValidHandler = () =>
28
- new Promise((resolve, reject) =>
29
- setTimeout(() => resolve("I'm DATA from a request"), 3000),
30
- );
31
-
32
- const myInvalidHandler = () =>
33
- new Promise((resolve, reject) =>
34
- setTimeout(() => reject("I'm an ERROR from a request"), 3000),
35
- );
36
-
37
- const example = (
38
- <View>
39
- <View>
40
- <Body>This request will succeed and give us data!</Body>
41
- <Data handler={myValidHandler} requestId="VALID">
42
- {(result) => {
43
- if (result.status === "loading") {
44
- return "Loading...";
45
- }
46
-
47
- return <BodyMonospace>{result.data}</BodyMonospace>;
48
- }}
49
- </Data>
50
- </View>
51
- <Strut size={Spacing.small_12} />
52
- <View>
53
- <Body>This request will go boom and give us an error!</Body>
54
- <Data handler={myInvalidHandler} requestId="INVALID">
55
- {(result) => {
56
- if (result.status === "loading") {
57
- return "Loading...";
58
- }
59
-
60
- return (
61
- <BodyMonospace
62
- style={{
63
- color: Color.red,
64
- }}
65
- >
66
- ERROR: {result.error}
67
- </BodyMonospace>
68
- );
69
- }}
70
- </Data>
71
- </View>
72
- </View>
73
- );
74
- const tree = renderer.create(example).toJSON();
75
- expect(tree).toMatchSnapshot();
76
- });
77
-
78
- it("example 2", () => {
79
- const myHandler = () => {
80
- throw new Error(
81
- "If you're seeing this error, the examples are broken and data isn't in the cache that should be.",
82
- );
83
- };
84
-
85
- initializeHydrationCache({
86
- DATA: {
87
- data: "I'm DATA from the hydration cache",
88
- },
89
- });
90
- const example = (
91
- <View>
92
- <View>
93
- <Body>This cache has data!</Body>
94
- <Data handler={myHandler} requestId="DATA">
95
- {(result) => {
96
- if (result.status !== "success") {
97
- return "If you see this, the example is broken!";
98
- }
99
-
100
- return <BodyMonospace>{result.data}</BodyMonospace>;
101
- }}
102
- </Data>
103
- </View>
104
- </View>
105
- );
106
- const tree = renderer.create(example).toJSON();
107
- expect(tree).toMatchSnapshot();
108
- });
109
-
110
- it("example 3", () => {
111
- const myHandler = () =>
112
- Promise.reject(new Error("You should not see this!"));
113
-
114
- const interceptor = (requestId) =>
115
- requestId === "INTERCEPT_EXAMPLE"
116
- ? Promise.resolve("INTERCEPTED DATA!")
117
- : null;
118
-
119
- const example = (
120
- <InterceptRequests interceptor={interceptor}>
121
- <View>
122
- <Body>This received intercepted data!</Body>
123
- <Data handler={myHandler} requestId="INTERCEPT_EXAMPLE">
124
- {(result) => {
125
- if (result.status !== "success") {
126
- return "If you see this, the example is broken!";
127
- }
128
-
129
- return <BodyMonospace>{result.data}</BodyMonospace>;
130
- }}
131
- </Data>
132
- </View>
133
- </InterceptRequests>
134
- );
135
- const tree = renderer.create(example).toJSON();
136
- expect(tree).toMatchSnapshot();
137
- });
138
-
139
- it("example 4", () => {
140
- class ErrorBoundary extends React.Component {
141
- constructor(props) {
142
- super(props);
143
- this.state = {};
144
- }
145
-
146
- static getDerivedStateFromError(error) {
147
- return {
148
- error: error.message,
149
- };
150
- }
151
-
152
- render() {
153
- if (typeof jest !== "undefined") {
154
- /**
155
- * The snapshot test just sees the error getting thrown, not the
156
- * awesome error boundary, so we have to hack around it to keep
157
- * this live example, but not get test failures.
158
- */
159
- return "Sorry, no snapshot for you";
160
- }
161
-
162
- if (this.state.error) {
163
- return <View>{this.state.error}</View>;
164
- }
165
-
166
- return this.props.children;
167
- }
168
- }
169
-
170
- const example = (
171
- <ErrorBoundary>
172
- <View>
173
- <TrackData>
174
- <Body>
175
- This only renders if we're in server-side mode and
176
- the page hot reloaded
177
- </Body>
178
- </TrackData>
179
- </View>
180
- </ErrorBoundary>
181
- );
182
- const tree = renderer.create(example).toJSON();
183
- expect(tree).toMatchSnapshot();
184
- });
185
-
186
- it("example 5", () => {
187
- const myPretendHandler = () =>
188
- new Promise((resolve, reject) =>
189
- setTimeout(() => resolve("DATA!"), 3000),
190
- );
191
-
192
- class Example extends React.Component {
193
- constructor() {
194
- super();
195
- /**
196
- * For this demonstration, we need to hack the return of isServerSide solely
197
- * for the scope of this component.
198
- */
199
-
200
- this.state = {};
201
- }
202
-
203
- static getDerivedStateFromError(error) {
204
- return {
205
- error,
206
- };
207
- }
208
-
209
- componentDidMount() {
210
- this._mounted = true;
211
- }
212
-
213
- componentWillUnmount() {
214
- this._mounted = false;
215
- }
216
-
217
- setClientMode() {
218
- window.location.reload();
219
- }
220
-
221
- setServerMode() {
222
- Server.setServerSide();
223
- this.setState({
224
- refresh: Date.now(),
225
- error: null,
226
- });
227
- }
228
-
229
- _renderErrorOrContent() {
230
- if (typeof jest !== "undefined") {
231
- /**
232
- * The snapshot test just sees the error getting thrown, not the
233
- * awesome error boundary, so we have to hack around it to keep
234
- * this live example, but not get test failures.
235
- */
236
- return "Sorry, no snapshot for you";
237
- }
238
-
239
- if (this.state.error) {
240
- return (
241
- <React.Fragment>
242
- <Strut size={Spacing.small_12} />
243
- <Body>
244
- We can't show you anything useful in client-side
245
- mode
246
- </Body>
247
- </React.Fragment>
248
- );
249
- }
250
-
251
- const data = this.state.data
252
- ? JSON.stringify(this.state.data, undefined, " ")
253
- : "Data requested...";
254
- return (
255
- <React.Fragment>
256
- <Strut size={Spacing.small_12} />
257
- <TrackData>
258
- <Data
259
- handler={myPretendHandler}
260
- requestId="TRACK_DATA_EXAMPLE"
261
- >
262
- {(result) => (
263
- <View>
264
- <BodyMonospace>{`Loading: ${
265
- result.status === "loading"
266
- }`}</BodyMonospace>
267
- <BodyMonospace>{`Data: ${JSON.stringify(
268
- result.data,
269
- )}`}</BodyMonospace>
270
- </View>
271
- )}
272
- </Data>
273
- </TrackData>
274
- <Strut size={Spacing.small_12} />
275
- <View>
276
- <Body>
277
- The above components requested data, but we're
278
- server-side, so all that happened is we tracked
279
- the request. In this example, we've also called
280
- `fetchTrackedRequests` to fetch that tracked
281
- data.
282
- </Body>
283
- <Strut size={Spacing.small_12} />
284
- <Body>
285
- In about 3 seconds, it will appear below. Notice
286
- that when it does, the above still doesn't
287
- update. That's because during SSR, the data is
288
- not updated in the rendered tree.
289
- </Body>
290
- <Strut size={Spacing.small_12} />
291
- <BodyMonospace>{data}</BodyMonospace>
292
- </View>
293
- </React.Fragment>
294
- );
295
- }
296
-
297
- render() {
298
- try {
299
- return (
300
- <View key={this.state.refresh}>
301
- {Server.isServerSide() ? (
302
- <React.Fragment>
303
- <Button
304
- kind={"secondary"}
305
- onClick={() => this.setClientMode()}
306
- >
307
- Back to Client-side Mode (reloads page)
308
- </Button>
309
- <Strut size={Spacing.small_12} />
310
- <Button
311
- kind={"secondary"}
312
- onClick={() => this.setServerMode()}
313
- >
314
- Re-mount
315
- </Button>
316
- </React.Fragment>
317
- ) : (
318
- <Button
319
- kind={"primary"}
320
- onClick={() => this.setServerMode()}
321
- >
322
- Enable Server-side Mode
323
- </Button>
324
- )}
325
- {this._renderErrorOrContent()}
326
- </View>
327
- );
328
- } finally {
329
- if (!this.state.data && Server.isServerSide()) {
330
- setTimeout(
331
- () =>
332
- fetchTrackedRequests().then((data) => {
333
- if (this._mounted) {
334
- this.setState({
335
- data,
336
- });
337
- }
338
- }),
339
- 0,
340
- );
341
- }
342
- }
343
- }
344
- }
345
-
346
- const example = <Example />;
347
- const tree = renderer.create(example).toJSON();
348
- expect(tree).toMatchSnapshot();
349
- });
350
- });