react-refresh-runtime.development.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /** @license React vundefined
  2. * react-refresh-runtime.development.js
  3. *
  4. * Copyright (c) Facebook, Inc. and its affiliates.
  5. *
  6. * This source code is licensed under the MIT license found in the
  7. * LICENSE file in the root directory of this source tree.
  8. */
  9. 'use strict';
  10. if (process.env.NODE_ENV !== "production") {
  11. (function() {
  12. 'use strict';
  13. // The Symbol used to tag the ReactElement-like types. If there is no native Symbol
  14. // nor polyfill, then a plain number is used for performance.
  15. var hasSymbol = typeof Symbol === 'function' && Symbol.for;
  16. // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary
  17. // (unstable) APIs that have been removed. Can we remove the symbols?
  18. var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
  19. var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
  20. var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; // We never remove these associations.
  21. // It's OK to reference families, but use WeakMap/Set for types.
  22. var allFamiliesByID = new Map();
  23. var allFamiliesByType = new PossiblyWeakMap();
  24. var allSignaturesByType = new PossiblyWeakMap(); // This WeakMap is read by React, so we only put families
  25. // that have actually been edited here. This keeps checks fast.
  26. // $FlowIssue
  27. var updatedFamiliesByType = new PossiblyWeakMap(); // This is cleared on every performReactRefresh() call.
  28. // It is an array of [Family, NextType] tuples.
  29. var pendingUpdates = []; // This is injected by the renderer via DevTools global hook.
  30. var helpersByRendererID = new Map();
  31. var helpersByRoot = new Map(); // We keep track of mounted roots so we can schedule updates.
  32. var mountedRoots = new Set(); // If a root captures an error, we add its element to this Map so we can retry on edit.
  33. var failedRoots = new Map();
  34. var didSomeRootFailOnMount = false;
  35. function computeFullKey(signature) {
  36. if (signature.fullKey !== null) {
  37. return signature.fullKey;
  38. }
  39. var fullKey = signature.ownKey;
  40. var hooks;
  41. try {
  42. hooks = signature.getCustomHooks();
  43. } catch (err) {
  44. // This can happen in an edge case, e.g. if expression like Foo.useSomething
  45. // depends on Foo which is lazily initialized during rendering.
  46. // In that case just assume we'll have to remount.
  47. signature.forceReset = true;
  48. signature.fullKey = fullKey;
  49. return fullKey;
  50. }
  51. for (var i = 0; i < hooks.length; i++) {
  52. var hook = hooks[i];
  53. if (typeof hook !== 'function') {
  54. // Something's wrong. Assume we need to remount.
  55. signature.forceReset = true;
  56. signature.fullKey = fullKey;
  57. return fullKey;
  58. }
  59. var nestedHookSignature = allSignaturesByType.get(hook);
  60. if (nestedHookSignature === undefined) {
  61. // No signature means Hook wasn't in the source code, e.g. in a library.
  62. // We'll skip it because we can assume it won't change during this session.
  63. continue;
  64. }
  65. var nestedHookKey = computeFullKey(nestedHookSignature);
  66. if (nestedHookSignature.forceReset) {
  67. signature.forceReset = true;
  68. }
  69. fullKey += '\n---\n' + nestedHookKey;
  70. }
  71. signature.fullKey = fullKey;
  72. return fullKey;
  73. }
  74. function haveEqualSignatures(prevType, nextType) {
  75. var prevSignature = allSignaturesByType.get(prevType);
  76. var nextSignature = allSignaturesByType.get(nextType);
  77. if (prevSignature === undefined && nextSignature === undefined) {
  78. return true;
  79. }
  80. if (prevSignature === undefined || nextSignature === undefined) {
  81. return false;
  82. }
  83. if (computeFullKey(prevSignature) !== computeFullKey(nextSignature)) {
  84. return false;
  85. }
  86. if (nextSignature.forceReset) {
  87. return false;
  88. }
  89. return true;
  90. }
  91. function isReactClass(type) {
  92. return type.prototype && type.prototype.isReactComponent;
  93. }
  94. function canPreserveStateBetween(prevType, nextType) {
  95. if (isReactClass(prevType) || isReactClass(nextType)) {
  96. return false;
  97. }
  98. if (haveEqualSignatures(prevType, nextType)) {
  99. return true;
  100. }
  101. return false;
  102. }
  103. function resolveFamily(type) {
  104. // Only check updated types to keep lookups fast.
  105. return updatedFamiliesByType.get(type);
  106. }
  107. function performReactRefresh() {
  108. {
  109. if (pendingUpdates.length === 0) {
  110. return null;
  111. }
  112. var staleFamilies = new Set();
  113. var updatedFamilies = new Set();
  114. var updates = pendingUpdates;
  115. pendingUpdates = [];
  116. updates.forEach(function (_ref) {
  117. var family = _ref[0],
  118. nextType = _ref[1];
  119. // Now that we got a real edit, we can create associations
  120. // that will be read by the React reconciler.
  121. var prevType = family.current;
  122. updatedFamiliesByType.set(prevType, family);
  123. updatedFamiliesByType.set(nextType, family);
  124. family.current = nextType; // Determine whether this should be a re-render or a re-mount.
  125. if (canPreserveStateBetween(prevType, nextType)) {
  126. updatedFamilies.add(family);
  127. } else {
  128. staleFamilies.add(family);
  129. }
  130. }); // TODO: rename these fields to something more meaningful.
  131. var update = {
  132. updatedFamilies: updatedFamilies,
  133. // Families that will re-render preserving state
  134. staleFamilies: staleFamilies // Families that will be remounted
  135. };
  136. helpersByRendererID.forEach(function (helpers) {
  137. // Even if there are no roots, set the handler on first update.
  138. // This ensures that if *new* roots are mounted, they'll use the resolve handler.
  139. helpers.setRefreshHandler(resolveFamily);
  140. });
  141. var didError = false;
  142. var firstError = null;
  143. failedRoots.forEach(function (element, root) {
  144. var helpers = helpersByRoot.get(root);
  145. if (helpers === undefined) {
  146. throw new Error('Could not find helpers for a root. This is a bug in React Refresh.');
  147. }
  148. try {
  149. helpers.scheduleRoot(root, element);
  150. } catch (err) {
  151. if (!didError) {
  152. didError = true;
  153. firstError = err;
  154. } // Keep trying other roots.
  155. }
  156. });
  157. mountedRoots.forEach(function (root) {
  158. var helpers = helpersByRoot.get(root);
  159. if (helpers === undefined) {
  160. throw new Error('Could not find helpers for a root. This is a bug in React Refresh.');
  161. }
  162. try {
  163. helpers.scheduleRefresh(root, update);
  164. } catch (err) {
  165. if (!didError) {
  166. didError = true;
  167. firstError = err;
  168. } // Keep trying other roots.
  169. }
  170. });
  171. if (didError) {
  172. throw firstError;
  173. }
  174. return update;
  175. }
  176. }
  177. function register(type, id) {
  178. {
  179. if (type === null) {
  180. return;
  181. }
  182. if (typeof type !== 'function' && typeof type !== 'object') {
  183. return;
  184. } // This can happen in an edge case, e.g. if we register
  185. // return value of a HOC but it returns a cached component.
  186. // Ignore anything but the first registration for each type.
  187. if (allFamiliesByType.has(type)) {
  188. return;
  189. } // Create family or remember to update it.
  190. // None of this bookkeeping affects reconciliation
  191. // until the first performReactRefresh() call above.
  192. var family = allFamiliesByID.get(id);
  193. if (family === undefined) {
  194. family = {
  195. current: type
  196. };
  197. allFamiliesByID.set(id, family);
  198. } else {
  199. pendingUpdates.push([family, type]);
  200. }
  201. allFamiliesByType.set(type, family); // Visit inner types because we might not have registered them.
  202. if (typeof type === 'object' && type !== null) {
  203. switch (type.$$typeof) {
  204. case REACT_FORWARD_REF_TYPE:
  205. register(type.render, id + '$render');
  206. break;
  207. case REACT_MEMO_TYPE:
  208. register(type.type, id + '$type');
  209. break;
  210. }
  211. }
  212. }
  213. }
  214. function setSignature(type, key) {
  215. var forceReset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  216. var getCustomHooks = arguments.length > 3 ? arguments[3] : undefined;
  217. {
  218. allSignaturesByType.set(type, {
  219. forceReset: forceReset,
  220. ownKey: key,
  221. fullKey: null,
  222. getCustomHooks: getCustomHooks || function () {
  223. return [];
  224. }
  225. });
  226. }
  227. } // This is lazily called during first render for a type.
  228. // It captures Hook list at that time so inline requires don't break comparisons.
  229. function collectCustomHooksForSignature(type) {
  230. {
  231. var signature = allSignaturesByType.get(type);
  232. if (signature !== undefined) {
  233. computeFullKey(signature);
  234. }
  235. }
  236. }
  237. function getFamilyByID(id) {
  238. {
  239. return allFamiliesByID.get(id);
  240. }
  241. }
  242. function getFamilyByType(type) {
  243. {
  244. return allFamiliesByType.get(type);
  245. }
  246. }
  247. function findAffectedHostInstances(families) {
  248. {
  249. var affectedInstances = new Set();
  250. mountedRoots.forEach(function (root) {
  251. var helpers = helpersByRoot.get(root);
  252. if (helpers === undefined) {
  253. throw new Error('Could not find helpers for a root. This is a bug in React Refresh.');
  254. }
  255. var instancesForRoot = helpers.findHostInstancesForRefresh(root, families);
  256. instancesForRoot.forEach(function (inst) {
  257. affectedInstances.add(inst);
  258. });
  259. });
  260. return affectedInstances;
  261. }
  262. }
  263. function injectIntoGlobalHook(globalObject) {
  264. {
  265. // For React Native, the global hook will be set up by require('react-devtools-core').
  266. // That code will run before us. So we need to monkeypatch functions on existing hook.
  267. // For React Web, the global hook will be set up by the extension.
  268. // This will also run before us.
  269. var hook = globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__;
  270. if (hook === undefined) {
  271. // However, if there is no DevTools extension, we'll need to set up the global hook ourselves.
  272. // Note that in this case it's important that renderer code runs *after* this method call.
  273. // Otherwise, the renderer will think that there is no global hook, and won't do the injection.
  274. var nextID = 0;
  275. globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = {
  276. supportsFiber: true,
  277. inject: function (injected) {
  278. return nextID++;
  279. },
  280. onCommitFiberRoot: function (id, root, maybePriorityLevel, didError) {},
  281. onCommitFiberUnmount: function () {}
  282. };
  283. } // Here, we just want to get a reference to scheduleRefresh.
  284. var oldInject = hook.inject;
  285. hook.inject = function (injected) {
  286. var id = oldInject.apply(this, arguments);
  287. if (typeof injected.scheduleRefresh === 'function' && typeof injected.setRefreshHandler === 'function') {
  288. // This version supports React Refresh.
  289. helpersByRendererID.set(id, injected);
  290. }
  291. return id;
  292. }; // We also want to track currently mounted roots.
  293. var oldOnCommitFiberRoot = hook.onCommitFiberRoot;
  294. hook.onCommitFiberRoot = function (id, root, maybePriorityLevel, didError) {
  295. var helpers = helpersByRendererID.get(id);
  296. if (helpers === undefined) {
  297. return;
  298. }
  299. helpersByRoot.set(root, helpers);
  300. var current = root.current;
  301. var alternate = current.alternate; // We need to determine whether this root has just (un)mounted.
  302. // This logic is copy-pasted from similar logic in the DevTools backend.
  303. // If this breaks with some refactoring, you'll want to update DevTools too.
  304. if (alternate !== null) {
  305. var wasMounted = alternate.memoizedState != null && alternate.memoizedState.element != null;
  306. var isMounted = current.memoizedState != null && current.memoizedState.element != null;
  307. if (!wasMounted && isMounted) {
  308. // Mount a new root.
  309. mountedRoots.add(root);
  310. failedRoots.delete(root);
  311. } else if (wasMounted && isMounted) {// Update an existing root.
  312. // This doesn't affect our mounted root Set.
  313. } else if (wasMounted && !isMounted) {
  314. // Unmount an existing root.
  315. mountedRoots.delete(root);
  316. if (didError) {
  317. // We'll remount it on future edits.
  318. // Remember what was rendered so we can restore it.
  319. failedRoots.set(root, alternate.memoizedState.element);
  320. } else {
  321. helpersByRoot.delete(root);
  322. }
  323. } else if (!wasMounted && !isMounted) {
  324. if (didError && !failedRoots.has(root)) {
  325. // The root had an error during the initial mount.
  326. // We can't read its last element from the memoized state
  327. // because there was no previously committed alternate.
  328. // Ideally, it would be nice if we had a way to extract
  329. // the last attempted rendered element, but accessing the update queue
  330. // would tie this package too closely to the reconciler version.
  331. // So instead, we just set a flag.
  332. // TODO: Maybe we could fix this as the same time as when we fix
  333. // DevTools to not depend on `alternate.memoizedState.element`.
  334. didSomeRootFailOnMount = true;
  335. }
  336. }
  337. } else {
  338. // Mount a new root.
  339. mountedRoots.add(root);
  340. }
  341. return oldOnCommitFiberRoot.apply(this, arguments);
  342. };
  343. }
  344. }
  345. function hasUnrecoverableErrors() {
  346. return didSomeRootFailOnMount;
  347. } // Exposed for testing.
  348. function _getMountedRootCount() {
  349. {
  350. return mountedRoots.size;
  351. }
  352. } // This is a wrapper over more primitive functions for setting signature.
  353. // Signatures let us decide whether the Hook order has changed on refresh.
  354. //
  355. // This function is intended to be used as a transform target, e.g.:
  356. // var _s = createSignatureFunctionForTransform()
  357. //
  358. // function Hello() {
  359. // const [foo, setFoo] = useState(0);
  360. // const value = useCustomHook();
  361. // _s(); /* Second call triggers collecting the custom Hook list.
  362. // * This doesn't happen during the module evaluation because we
  363. // * don't want to change the module order with inline requires.
  364. // * Next calls are noops. */
  365. // return <h1>Hi</h1>;
  366. // }
  367. //
  368. // /* First call specifies the signature: */
  369. // _s(
  370. // Hello,
  371. // 'useState{[foo, setFoo]}(0)',
  372. // () => [useCustomHook], /* Lazy to avoid triggering inline requires */
  373. // );
  374. function createSignatureFunctionForTransform() {
  375. {
  376. // We'll fill in the signature in two steps.
  377. // First, we'll know the signature itself. This happens outside the component.
  378. // Then, we'll know the references to custom Hooks. This happens inside the component.
  379. // After that, the returned function will be a fast path no-op.
  380. var status = 'needsSignature';
  381. var savedType;
  382. var hasCustomHooks;
  383. return function (type, key, forceReset, getCustomHooks) {
  384. switch (status) {
  385. case 'needsSignature':
  386. if (type !== undefined) {
  387. // If we received an argument, this is the initial registration call.
  388. savedType = type;
  389. hasCustomHooks = typeof getCustomHooks === 'function';
  390. setSignature(type, key, forceReset, getCustomHooks); // The next call we expect is from inside a function, to fill in the custom Hooks.
  391. status = 'needsCustomHooks';
  392. }
  393. break;
  394. case 'needsCustomHooks':
  395. if (hasCustomHooks) {
  396. collectCustomHooksForSignature(savedType);
  397. }
  398. status = 'resolved';
  399. break;
  400. case 'resolved':
  401. // Do nothing. Fast path for all future renders.
  402. break;
  403. }
  404. return type;
  405. };
  406. }
  407. }
  408. function isLikelyComponentType(type) {
  409. {
  410. switch (typeof type) {
  411. case 'function':
  412. {
  413. // First, deal with classes.
  414. if (type.prototype != null) {
  415. if (type.prototype.isReactComponent) {
  416. // React class.
  417. return true;
  418. }
  419. var ownNames = Object.getOwnPropertyNames(type.prototype);
  420. if (ownNames.length > 1 || ownNames[0] !== 'constructor') {
  421. // This looks like a class.
  422. return false;
  423. } // eslint-disable-next-line no-proto
  424. if (type.prototype.__proto__ !== Object.prototype) {
  425. // It has a superclass.
  426. return false;
  427. } // Pass through.
  428. // This looks like a regular function with empty prototype.
  429. } // For plain functions and arrows, use name as a heuristic.
  430. var name = type.name || type.displayName;
  431. return typeof name === 'string' && /^[A-Z]/.test(name);
  432. }
  433. case 'object':
  434. {
  435. if (type != null) {
  436. switch (type.$$typeof) {
  437. case REACT_FORWARD_REF_TYPE:
  438. case REACT_MEMO_TYPE:
  439. // Definitely React components.
  440. return true;
  441. default:
  442. return false;
  443. }
  444. }
  445. return false;
  446. }
  447. default:
  448. {
  449. return false;
  450. }
  451. }
  452. }
  453. }
  454. var ReactFreshRuntime = Object.freeze({
  455. performReactRefresh: performReactRefresh,
  456. register: register,
  457. setSignature: setSignature,
  458. collectCustomHooksForSignature: collectCustomHooksForSignature,
  459. getFamilyByID: getFamilyByID,
  460. getFamilyByType: getFamilyByType,
  461. findAffectedHostInstances: findAffectedHostInstances,
  462. injectIntoGlobalHook: injectIntoGlobalHook,
  463. hasUnrecoverableErrors: hasUnrecoverableErrors,
  464. _getMountedRootCount: _getMountedRootCount,
  465. createSignatureFunctionForTransform: createSignatureFunctionForTransform,
  466. isLikelyComponentType: isLikelyComponentType
  467. });
  468. // This is hacky but makes it work with both Rollup and Jest.
  469. var runtime = ReactFreshRuntime.default || ReactFreshRuntime;
  470. module.exports = runtime;
  471. })();
  472. }