useCacheToken.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = useCacheToken;
  7. exports.getComputedToken = void 0;
  8. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  9. var _hash = _interopRequireDefault(require("@emotion/hash"));
  10. var _StyleContext = require("../StyleContext");
  11. var _useGlobalCache = _interopRequireDefault(require("./useGlobalCache"));
  12. var _util = require("../util");
  13. var _vue = require("vue");
  14. const EMPTY_OVERRIDE = {};
  15. const isProduction = process.env.NODE_ENV === 'production';
  16. // nuxt generate when NODE_ENV is prerender
  17. const isPrerender = process.env.NODE_ENV === 'prerender';
  18. // Generate different prefix to make user selector break in production env.
  19. // This helps developer not to do style override directly on the hash id.
  20. const hashPrefix = !isProduction && !isPrerender ? 'css-dev-only-do-not-override' : 'css';
  21. const tokenKeys = new Map();
  22. function recordCleanToken(tokenKey) {
  23. tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1);
  24. }
  25. function removeStyleTags(key, instanceId) {
  26. if (typeof document !== 'undefined') {
  27. const styles = document.querySelectorAll(`style[${_StyleContext.ATTR_TOKEN}="${key}"]`);
  28. styles.forEach(style => {
  29. var _a;
  30. if (style[_StyleContext.CSS_IN_JS_INSTANCE] === instanceId) {
  31. (_a = style.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(style);
  32. }
  33. });
  34. }
  35. }
  36. const TOKEN_THRESHOLD = 0;
  37. // Remove will check current keys first
  38. function cleanTokenStyle(tokenKey, instanceId) {
  39. tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1);
  40. const tokenKeyList = Array.from(tokenKeys.keys());
  41. const cleanableKeyList = tokenKeyList.filter(key => {
  42. const count = tokenKeys.get(key) || 0;
  43. return count <= 0;
  44. });
  45. // Should keep tokens under threshold for not to insert style too often
  46. if (tokenKeyList.length - cleanableKeyList.length > TOKEN_THRESHOLD) {
  47. cleanableKeyList.forEach(key => {
  48. removeStyleTags(key, instanceId);
  49. tokenKeys.delete(key);
  50. });
  51. }
  52. }
  53. const getComputedToken = (originToken, overrideToken, theme, format) => {
  54. const derivativeToken = theme.getDerivativeToken(originToken);
  55. // Merge with override
  56. let mergedDerivativeToken = (0, _extends2.default)((0, _extends2.default)({}, derivativeToken), overrideToken);
  57. // Format if needed
  58. if (format) {
  59. mergedDerivativeToken = format(mergedDerivativeToken);
  60. }
  61. return mergedDerivativeToken;
  62. };
  63. /**
  64. * Cache theme derivative token as global shared one
  65. * @param theme Theme entity
  66. * @param tokens List of tokens, used for cache. Please do not dynamic generate object directly
  67. * @param option Additional config
  68. * @returns Call Theme.getDerivativeToken(tokenObject) to get token
  69. */
  70. exports.getComputedToken = getComputedToken;
  71. function useCacheToken(theme, tokens) {
  72. let option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : (0, _vue.ref)({});
  73. const style = (0, _StyleContext.useStyleInject)();
  74. // Basic - We do basic cache here
  75. const mergedToken = (0, _vue.computed)(() => (0, _extends2.default)({}, ...tokens.value));
  76. const tokenStr = (0, _vue.computed)(() => (0, _util.flattenToken)(mergedToken.value));
  77. const overrideTokenStr = (0, _vue.computed)(() => (0, _util.flattenToken)(option.value.override || EMPTY_OVERRIDE));
  78. const cachedToken = (0, _useGlobalCache.default)('token', (0, _vue.computed)(() => [option.value.salt || '', theme.value.id, tokenStr.value, overrideTokenStr.value]), () => {
  79. const {
  80. salt = '',
  81. override = EMPTY_OVERRIDE,
  82. formatToken,
  83. getComputedToken: compute
  84. } = option.value;
  85. const mergedDerivativeToken = compute ? compute(mergedToken.value, override, theme.value) : getComputedToken(mergedToken.value, override, theme.value, formatToken);
  86. // Optimize for `useStyleRegister` performance
  87. const tokenKey = (0, _util.token2key)(mergedDerivativeToken, salt);
  88. mergedDerivativeToken._tokenKey = tokenKey;
  89. recordCleanToken(tokenKey);
  90. const hashId = `${hashPrefix}-${(0, _hash.default)(tokenKey)}`;
  91. mergedDerivativeToken._hashId = hashId; // Not used
  92. return [mergedDerivativeToken, hashId];
  93. }, cache => {
  94. var _a;
  95. // Remove token will remove all related style
  96. cleanTokenStyle(cache[0]._tokenKey, (_a = style.value) === null || _a === void 0 ? void 0 : _a.cache.instanceId);
  97. });
  98. return cachedToken;
  99. }