@vitejs/plugin-react-swc 3.10.2 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,450 +1,670 @@
1
+ /* global window */
2
+ /* eslint-disable eqeqeq, prefer-const, @typescript-eslint/no-empty-function */
3
+
1
4
  /*! Copyright (c) Meta Platforms, Inc. and affiliates. **/
2
- const REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref");
3
- const REACT_MEMO_TYPE = Symbol.for("react.memo");
4
- let allFamiliesByID = /* @__PURE__ */ new Map();
5
- let allFamiliesByType = /* @__PURE__ */ new WeakMap();
6
- let allSignaturesByType = /* @__PURE__ */ new WeakMap();
7
- const updatedFamiliesByType = /* @__PURE__ */ new WeakMap();
8
- let pendingUpdates = [];
9
- const helpersByRendererID = /* @__PURE__ */ new Map();
10
- const helpersByRoot = /* @__PURE__ */ new Map();
11
- const mountedRoots = /* @__PURE__ */ new Set();
12
- const failedRoots = /* @__PURE__ */ new Set();
13
- let rootElements = /* @__PURE__ */ new WeakMap();
14
- let isPerformingRefresh = false;
5
+ /**
6
+ * This is simplified pure-js version of https://github.com/facebook/react/blob/main/packages/react-refresh/src/ReactFreshRuntime.js
7
+ * without IE11 compatibility and verbose isDev checks.
8
+ * Some utils are appended at the bottom for HMR integration.
9
+ */
10
+
11
+ const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref')
12
+ const REACT_MEMO_TYPE = Symbol.for('react.memo')
13
+
14
+ // We never remove these associations.
15
+ // It's OK to reference families, but use WeakMap/Set for types.
16
+ let allFamiliesByID = new Map()
17
+ let allFamiliesByType = new WeakMap()
18
+ let allSignaturesByType = new WeakMap()
19
+
20
+ // This WeakMap is read by React, so we only put families
21
+ // that have actually been edited here. This keeps checks fast.
22
+ const updatedFamiliesByType = new WeakMap()
23
+
24
+ // This is cleared on every performReactRefresh() call.
25
+ // It is an array of [Family, NextType] tuples.
26
+ let pendingUpdates = []
27
+
28
+ // This is injected by the renderer via DevTools global hook.
29
+ const helpersByRendererID = new Map()
30
+
31
+ const helpersByRoot = new Map()
32
+
33
+ // We keep track of mounted roots so we can schedule updates.
34
+ const mountedRoots = new Set()
35
+ // If a root captures an error, we remember it so we can retry on edit.
36
+ const failedRoots = new Set()
37
+
38
+ // We also remember the last element for every root.
39
+ // It needs to be weak because we do this even for roots that failed to mount.
40
+ // If there is no WeakMap, we won't attempt to do retrying.
41
+ let rootElements = new WeakMap()
42
+ let isPerformingRefresh = false
43
+
15
44
  function computeFullKey(signature) {
16
45
  if (signature.fullKey !== null) {
17
- return signature.fullKey;
46
+ return signature.fullKey
18
47
  }
19
- let fullKey = signature.ownKey;
20
- let hooks2;
48
+
49
+ let fullKey = signature.ownKey
50
+ let hooks
21
51
  try {
22
- hooks2 = signature.getCustomHooks();
52
+ hooks = signature.getCustomHooks()
23
53
  } catch (err) {
24
- signature.forceReset = true;
25
- signature.fullKey = fullKey;
26
- return fullKey;
27
- }
28
- for (let i = 0; i < hooks2.length; i++) {
29
- const hook = hooks2[i];
30
- if (typeof hook !== "function") {
31
- signature.forceReset = true;
32
- signature.fullKey = fullKey;
33
- return fullKey;
54
+ // This can happen in an edge case, e.g. if expression like Foo.useSomething
55
+ // depends on Foo which is lazily initialized during rendering.
56
+ // In that case just assume we'll have to remount.
57
+ signature.forceReset = true
58
+ signature.fullKey = fullKey
59
+ return fullKey
60
+ }
61
+
62
+ for (let i = 0; i < hooks.length; i++) {
63
+ const hook = hooks[i]
64
+ if (typeof hook !== 'function') {
65
+ // Something's wrong. Assume we need to remount.
66
+ signature.forceReset = true
67
+ signature.fullKey = fullKey
68
+ return fullKey
34
69
  }
35
- const nestedHookSignature = allSignaturesByType.get(hook);
36
- if (nestedHookSignature === void 0) {
37
- continue;
70
+ const nestedHookSignature = allSignaturesByType.get(hook)
71
+ if (nestedHookSignature === undefined) {
72
+ // No signature means Hook wasn't in the source code, e.g. in a library.
73
+ // We'll skip it because we can assume it won't change during this session.
74
+ continue
38
75
  }
39
- const nestedHookKey = computeFullKey(nestedHookSignature);
76
+ const nestedHookKey = computeFullKey(nestedHookSignature)
40
77
  if (nestedHookSignature.forceReset) {
41
- signature.forceReset = true;
78
+ signature.forceReset = true
42
79
  }
43
- fullKey += "\n---\n" + nestedHookKey;
80
+ fullKey += '\n---\n' + nestedHookKey
44
81
  }
45
- signature.fullKey = fullKey;
46
- return fullKey;
82
+
83
+ signature.fullKey = fullKey
84
+ return fullKey
47
85
  }
86
+
48
87
  function haveEqualSignatures(prevType, nextType) {
49
- const prevSignature = allSignaturesByType.get(prevType);
50
- const nextSignature = allSignaturesByType.get(nextType);
51
- if (prevSignature === void 0 && nextSignature === void 0) {
52
- return true;
88
+ const prevSignature = allSignaturesByType.get(prevType)
89
+ const nextSignature = allSignaturesByType.get(nextType)
90
+
91
+ if (prevSignature === undefined && nextSignature === undefined) {
92
+ return true
53
93
  }
54
- if (prevSignature === void 0 || nextSignature === void 0) {
55
- return false;
94
+ if (prevSignature === undefined || nextSignature === undefined) {
95
+ return false
56
96
  }
57
97
  if (computeFullKey(prevSignature) !== computeFullKey(nextSignature)) {
58
- return false;
98
+ return false
59
99
  }
60
100
  if (nextSignature.forceReset) {
61
- return false;
101
+ return false
62
102
  }
63
- return true;
103
+
104
+ return true
64
105
  }
106
+
65
107
  function isReactClass(type) {
66
- return type.prototype && type.prototype.isReactComponent;
108
+ return type.prototype && type.prototype.isReactComponent
67
109
  }
110
+
68
111
  function canPreserveStateBetween(prevType, nextType) {
69
112
  if (isReactClass(prevType) || isReactClass(nextType)) {
70
- return false;
113
+ return false
71
114
  }
72
115
  if (haveEqualSignatures(prevType, nextType)) {
73
- return true;
116
+ return true
74
117
  }
75
- return false;
118
+ return false
76
119
  }
120
+
77
121
  function resolveFamily(type) {
78
- return updatedFamiliesByType.get(type);
122
+ // Only check updated types to keep lookups fast.
123
+ return updatedFamiliesByType.get(type)
79
124
  }
125
+
126
+ // This is a safety mechanism to protect against rogue getters and Proxies.
80
127
  function getProperty(object, property) {
81
128
  try {
82
- return object[property];
129
+ return object[property]
83
130
  } catch (err) {
84
- return void 0;
131
+ // Intentionally ignore.
132
+ return undefined
85
133
  }
86
134
  }
135
+
87
136
  function performReactRefresh() {
88
137
  if (pendingUpdates.length === 0) {
89
- return null;
138
+ return null
90
139
  }
91
140
  if (isPerformingRefresh) {
92
- return null;
141
+ return null
93
142
  }
94
- isPerformingRefresh = true;
143
+
144
+ isPerformingRefresh = true
95
145
  try {
96
- const staleFamilies = /* @__PURE__ */ new Set();
97
- const updatedFamilies = /* @__PURE__ */ new Set();
98
- const updates = pendingUpdates;
99
- pendingUpdates = [];
146
+ const staleFamilies = new Set()
147
+ const updatedFamilies = new Set()
148
+
149
+ const updates = pendingUpdates
150
+ pendingUpdates = []
100
151
  updates.forEach(([family, nextType]) => {
101
- const prevType = family.current;
102
- updatedFamiliesByType.set(prevType, family);
103
- updatedFamiliesByType.set(nextType, family);
104
- family.current = nextType;
152
+ // Now that we got a real edit, we can create associations
153
+ // that will be read by the React reconciler.
154
+ const prevType = family.current
155
+ updatedFamiliesByType.set(prevType, family)
156
+ updatedFamiliesByType.set(nextType, family)
157
+ family.current = nextType
158
+
159
+ // Determine whether this should be a re-render or a re-mount.
105
160
  if (canPreserveStateBetween(prevType, nextType)) {
106
- updatedFamilies.add(family);
161
+ updatedFamilies.add(family)
107
162
  } else {
108
- staleFamilies.add(family);
163
+ staleFamilies.add(family)
109
164
  }
110
- });
165
+ })
166
+
167
+ // TODO: rename these fields to something more meaningful.
111
168
  const update = {
112
- updatedFamilies,
113
- // Families that will re-render preserving state
114
- staleFamilies
115
- // Families that will be remounted
116
- };
169
+ updatedFamilies, // Families that will re-render preserving state
170
+ staleFamilies, // Families that will be remounted
171
+ }
172
+
117
173
  helpersByRendererID.forEach((helpers) => {
118
- helpers.setRefreshHandler(resolveFamily);
119
- });
120
- let didError = false;
121
- let firstError = null;
122
- const failedRootsSnapshot = new Set(failedRoots);
123
- const mountedRootsSnapshot = new Set(mountedRoots);
124
- const helpersByRootSnapshot = new Map(helpersByRoot);
174
+ // Even if there are no roots, set the handler on first update.
175
+ // This ensures that if *new* roots are mounted, they'll use the resolve handler.
176
+ helpers.setRefreshHandler(resolveFamily)
177
+ })
178
+
179
+ let didError = false
180
+ let firstError = null
181
+
182
+ // We snapshot maps and sets that are mutated during commits.
183
+ // If we don't do this, there is a risk they will be mutated while
184
+ // we iterate over them. For example, trying to recover a failed root
185
+ // may cause another root to be added to the failed list -- an infinite loop.
186
+ const failedRootsSnapshot = new Set(failedRoots)
187
+ const mountedRootsSnapshot = new Set(mountedRoots)
188
+ const helpersByRootSnapshot = new Map(helpersByRoot)
189
+
125
190
  failedRootsSnapshot.forEach((root) => {
126
- const helpers = helpersByRootSnapshot.get(root);
127
- if (helpers === void 0) {
191
+ const helpers = helpersByRootSnapshot.get(root)
192
+ if (helpers === undefined) {
128
193
  throw new Error(
129
- "Could not find helpers for a root. This is a bug in React Refresh."
130
- );
194
+ 'Could not find helpers for a root. This is a bug in React Refresh.',
195
+ )
131
196
  }
132
197
  if (!failedRoots.has(root)) {
198
+ // No longer failed.
133
199
  }
134
200
  if (rootElements === null) {
135
- return;
201
+ return
136
202
  }
137
203
  if (!rootElements.has(root)) {
138
- return;
204
+ return
139
205
  }
140
- const element = rootElements.get(root);
206
+ const element = rootElements.get(root)
141
207
  try {
142
- helpers.scheduleRoot(root, element);
208
+ helpers.scheduleRoot(root, element)
143
209
  } catch (err) {
144
210
  if (!didError) {
145
- didError = true;
146
- firstError = err;
211
+ didError = true
212
+ firstError = err
147
213
  }
214
+ // Keep trying other roots.
148
215
  }
149
- });
216
+ })
150
217
  mountedRootsSnapshot.forEach((root) => {
151
- const helpers = helpersByRootSnapshot.get(root);
152
- if (helpers === void 0) {
218
+ const helpers = helpersByRootSnapshot.get(root)
219
+ if (helpers === undefined) {
153
220
  throw new Error(
154
- "Could not find helpers for a root. This is a bug in React Refresh."
155
- );
221
+ 'Could not find helpers for a root. This is a bug in React Refresh.',
222
+ )
156
223
  }
157
224
  if (!mountedRoots.has(root)) {
225
+ // No longer mounted.
158
226
  }
159
227
  try {
160
- helpers.scheduleRefresh(root, update);
228
+ helpers.scheduleRefresh(root, update)
161
229
  } catch (err) {
162
230
  if (!didError) {
163
- didError = true;
164
- firstError = err;
231
+ didError = true
232
+ firstError = err
165
233
  }
234
+ // Keep trying other roots.
166
235
  }
167
- });
236
+ })
168
237
  if (didError) {
169
- throw firstError;
238
+ throw firstError
170
239
  }
171
- return update;
240
+ return update
172
241
  } finally {
173
- isPerformingRefresh = false;
242
+ isPerformingRefresh = false
174
243
  }
175
244
  }
245
+
176
246
  function register(type, id) {
177
247
  if (type === null) {
178
- return;
248
+ return
179
249
  }
180
- if (typeof type !== "function" && typeof type !== "object") {
181
- return;
250
+ if (typeof type !== 'function' && typeof type !== 'object') {
251
+ return
182
252
  }
253
+
254
+ // This can happen in an edge case, e.g. if we register
255
+ // return value of a HOC but it returns a cached component.
256
+ // Ignore anything but the first registration for each type.
183
257
  if (allFamiliesByType.has(type)) {
184
- return;
258
+ return
185
259
  }
186
- let family = allFamiliesByID.get(id);
187
- if (family === void 0) {
188
- family = { current: type };
189
- allFamiliesByID.set(id, family);
260
+ // Create family or remember to update it.
261
+ // None of this bookkeeping affects reconciliation
262
+ // until the first performReactRefresh() call above.
263
+ let family = allFamiliesByID.get(id)
264
+ if (family === undefined) {
265
+ family = { current: type }
266
+ allFamiliesByID.set(id, family)
190
267
  } else {
191
- pendingUpdates.push([family, type]);
268
+ pendingUpdates.push([family, type])
192
269
  }
193
- allFamiliesByType.set(type, family);
194
- if (typeof type === "object" && type !== null) {
195
- switch (getProperty(type, "$$typeof")) {
270
+ allFamiliesByType.set(type, family)
271
+
272
+ // Visit inner types because we might not have registered them.
273
+ if (typeof type === 'object' && type !== null) {
274
+ switch (getProperty(type, '$$typeof')) {
196
275
  case REACT_FORWARD_REF_TYPE:
197
- register(type.render, id + "$render");
198
- break;
276
+ register(type.render, id + '$render')
277
+ break
199
278
  case REACT_MEMO_TYPE:
200
- register(type.type, id + "$type");
201
- break;
279
+ register(type.type, id + '$type')
280
+ break
202
281
  }
203
282
  }
204
283
  }
284
+
205
285
  function setSignature(type, key, forceReset, getCustomHooks) {
206
286
  if (!allSignaturesByType.has(type)) {
207
287
  allSignaturesByType.set(type, {
208
288
  forceReset,
209
289
  ownKey: key,
210
290
  fullKey: null,
211
- getCustomHooks: getCustomHooks || (() => [])
212
- });
291
+ getCustomHooks: getCustomHooks || (() => []),
292
+ })
213
293
  }
214
- if (typeof type === "object" && type !== null) {
215
- switch (getProperty(type, "$$typeof")) {
294
+ // Visit inner types because we might not have signed them.
295
+ if (typeof type === 'object' && type !== null) {
296
+ switch (getProperty(type, '$$typeof')) {
216
297
  case REACT_FORWARD_REF_TYPE:
217
- setSignature(type.render, key, forceReset, getCustomHooks);
218
- break;
298
+ setSignature(type.render, key, forceReset, getCustomHooks)
299
+ break
219
300
  case REACT_MEMO_TYPE:
220
- setSignature(type.type, key, forceReset, getCustomHooks);
221
- break;
301
+ setSignature(type.type, key, forceReset, getCustomHooks)
302
+ break
222
303
  }
223
304
  }
224
305
  }
306
+
307
+ // This is lazily called during first render for a type.
308
+ // It captures Hook list at that time so inline requires don't break comparisons.
225
309
  function collectCustomHooksForSignature(type) {
226
- const signature = allSignaturesByType.get(type);
227
- if (signature !== void 0) {
228
- computeFullKey(signature);
310
+ const signature = allSignaturesByType.get(type)
311
+ if (signature !== undefined) {
312
+ computeFullKey(signature)
229
313
  }
230
314
  }
231
- function injectIntoGlobalHook(globalObject) {
232
- let hook = globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__;
233
- if (hook === void 0) {
234
- let nextID = 0;
315
+
316
+ export function injectIntoGlobalHook(globalObject) {
317
+ // For React Native, the global hook will be set up by require('react-devtools-core').
318
+ // That code will run before us. So we need to monkeypatch functions on existing hook.
319
+
320
+ // For React Web, the global hook will be set up by the extension.
321
+ // This will also run before us.
322
+ let hook = globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__
323
+ if (hook === undefined) {
324
+ // However, if there is no DevTools extension, we'll need to set up the global hook ourselves.
325
+ // Note that in this case it's important that renderer code runs *after* this method call.
326
+ // Otherwise, the renderer will think that there is no global hook, and won't do the injection.
327
+ let nextID = 0
235
328
  globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = {
236
- renderers: /* @__PURE__ */ new Map(),
329
+ renderers: new Map(),
237
330
  supportsFiber: true,
238
331
  inject: (injected) => nextID++,
239
- onScheduleFiberRoot: (id, root, children) => {
240
- },
241
- onCommitFiberRoot: (id, root, maybePriorityLevel, didError) => {
242
- },
243
- onCommitFiberUnmount() {
244
- }
245
- };
332
+ onScheduleFiberRoot: (id, root, children) => {},
333
+ onCommitFiberRoot: (id, root, maybePriorityLevel, didError) => {},
334
+ onCommitFiberUnmount() {},
335
+ }
246
336
  }
337
+
247
338
  if (hook.isDisabled) {
248
- console["warn"](
249
- "Something has shimmed the React DevTools global hook (__REACT_DEVTOOLS_GLOBAL_HOOK__). Fast Refresh is not compatible with this shim and will be disabled."
250
- );
251
- return;
252
- }
253
- const oldInject = hook.inject;
254
- hook.inject = function(injected) {
255
- const id = oldInject.apply(this, arguments);
256
- if (typeof injected.scheduleRefresh === "function" && typeof injected.setRefreshHandler === "function") {
257
- helpersByRendererID.set(id, injected);
339
+ // This isn't a real property on the hook, but it can be set to opt out
340
+ // of DevTools integration and associated warnings and logs.
341
+ // Using console['warn'] to evade Babel and ESLint
342
+ console['warn'](
343
+ 'Something has shimmed the React DevTools global hook (__REACT_DEVTOOLS_GLOBAL_HOOK__). ' +
344
+ 'Fast Refresh is not compatible with this shim and will be disabled.',
345
+ )
346
+ return
347
+ }
348
+
349
+ // Here, we just want to get a reference to scheduleRefresh.
350
+ const oldInject = hook.inject
351
+ hook.inject = function (injected) {
352
+ const id = oldInject.apply(this, arguments)
353
+ if (
354
+ typeof injected.scheduleRefresh === 'function' &&
355
+ typeof injected.setRefreshHandler === 'function'
356
+ ) {
357
+ // This version supports React Refresh.
358
+ helpersByRendererID.set(id, injected)
258
359
  }
259
- return id;
260
- };
360
+ return id
361
+ }
362
+
363
+ // Do the same for any already injected roots.
364
+ // This is useful if ReactDOM has already been initialized.
365
+ // https://github.com/facebook/react/issues/17626
261
366
  hook.renderers.forEach((injected, id) => {
262
- if (typeof injected.scheduleRefresh === "function" && typeof injected.setRefreshHandler === "function") {
263
- helpersByRendererID.set(id, injected);
367
+ if (
368
+ typeof injected.scheduleRefresh === 'function' &&
369
+ typeof injected.setRefreshHandler === 'function'
370
+ ) {
371
+ // This version supports React Refresh.
372
+ helpersByRendererID.set(id, injected)
264
373
  }
265
- });
266
- const oldOnCommitFiberRoot = hook.onCommitFiberRoot;
267
- const oldOnScheduleFiberRoot = hook.onScheduleFiberRoot || (() => {
268
- });
269
- hook.onScheduleFiberRoot = function(id, root, children) {
374
+ })
375
+
376
+ // We also want to track currently mounted roots.
377
+ const oldOnCommitFiberRoot = hook.onCommitFiberRoot
378
+ const oldOnScheduleFiberRoot = hook.onScheduleFiberRoot || (() => {})
379
+ hook.onScheduleFiberRoot = function (id, root, children) {
270
380
  if (!isPerformingRefresh) {
271
- failedRoots.delete(root);
381
+ // If it was intentionally scheduled, don't attempt to restore.
382
+ // This includes intentionally scheduled unmounts.
383
+ failedRoots.delete(root)
272
384
  if (rootElements !== null) {
273
- rootElements.set(root, children);
385
+ rootElements.set(root, children)
274
386
  }
275
387
  }
276
- return oldOnScheduleFiberRoot.apply(this, arguments);
277
- };
278
- hook.onCommitFiberRoot = function(id, root, maybePriorityLevel, didError) {
279
- const helpers = helpersByRendererID.get(id);
280
- if (helpers !== void 0) {
281
- helpersByRoot.set(root, helpers);
282
- const current = root.current;
283
- const alternate = current.alternate;
388
+ return oldOnScheduleFiberRoot.apply(this, arguments)
389
+ }
390
+ hook.onCommitFiberRoot = function (id, root, maybePriorityLevel, didError) {
391
+ const helpers = helpersByRendererID.get(id)
392
+ if (helpers !== undefined) {
393
+ helpersByRoot.set(root, helpers)
394
+
395
+ const current = root.current
396
+ const alternate = current.alternate
397
+
398
+ // We need to determine whether this root has just (un)mounted.
399
+ // This logic is copy-pasted from similar logic in the DevTools backend.
400
+ // If this breaks with some refactoring, you'll want to update DevTools too.
401
+
284
402
  if (alternate !== null) {
285
- const wasMounted = alternate.memoizedState != null && alternate.memoizedState.element != null && mountedRoots.has(root);
286
- const isMounted = current.memoizedState != null && current.memoizedState.element != null;
403
+ const wasMounted =
404
+ alternate.memoizedState != null &&
405
+ alternate.memoizedState.element != null &&
406
+ mountedRoots.has(root)
407
+
408
+ const isMounted =
409
+ current.memoizedState != null && current.memoizedState.element != null
410
+
287
411
  if (!wasMounted && isMounted) {
288
- mountedRoots.add(root);
289
- failedRoots.delete(root);
412
+ // Mount a new root.
413
+ mountedRoots.add(root)
414
+ failedRoots.delete(root)
290
415
  } else if (wasMounted && isMounted) {
416
+ // Update an existing root.
417
+ // This doesn't affect our mounted root Set.
291
418
  } else if (wasMounted && !isMounted) {
292
- mountedRoots.delete(root);
419
+ // Unmount an existing root.
420
+ mountedRoots.delete(root)
293
421
  if (didError) {
294
- failedRoots.add(root);
422
+ // We'll remount it on future edits.
423
+ failedRoots.add(root)
295
424
  } else {
296
- helpersByRoot.delete(root);
425
+ helpersByRoot.delete(root)
297
426
  }
298
427
  } else if (!wasMounted && !isMounted) {
299
428
  if (didError) {
300
- failedRoots.add(root);
429
+ // We'll remount it on future edits.
430
+ failedRoots.add(root)
301
431
  }
302
432
  }
303
433
  } else {
304
- mountedRoots.add(root);
434
+ // Mount a new root.
435
+ mountedRoots.add(root)
305
436
  }
306
437
  }
307
- return oldOnCommitFiberRoot.apply(this, arguments);
308
- };
438
+
439
+ // Always call the decorated DevTools hook.
440
+ return oldOnCommitFiberRoot.apply(this, arguments)
441
+ }
309
442
  }
310
- function createSignatureFunctionForTransform() {
311
- let savedType;
312
- let hasCustomHooks;
313
- let didCollectHooks = false;
314
- return function(type, key, forceReset, getCustomHooks) {
315
- if (typeof key === "string") {
443
+
444
+ // This is a wrapper over more primitive functions for setting signature.
445
+ // Signatures let us decide whether the Hook order has changed on refresh.
446
+ //
447
+ // This function is intended to be used as a transform target, e.g.:
448
+ // var _s = createSignatureFunctionForTransform()
449
+ //
450
+ // function Hello() {
451
+ // const [foo, setFoo] = useState(0);
452
+ // const value = useCustomHook();
453
+ // _s(); /* Call without arguments triggers collecting the custom Hook list.
454
+ // * This doesn't happen during the module evaluation because we
455
+ // * don't want to change the module order with inline requires.
456
+ // * Next calls are noops. */
457
+ // return <h1>Hi</h1>;
458
+ // }
459
+ //
460
+ // /* Call with arguments attaches the signature to the type: */
461
+ // _s(
462
+ // Hello,
463
+ // 'useState{[foo, setFoo]}(0)',
464
+ // () => [useCustomHook], /* Lazy to avoid triggering inline requires */
465
+ // );
466
+ export function createSignatureFunctionForTransform() {
467
+ let savedType
468
+ let hasCustomHooks
469
+ let didCollectHooks = false
470
+ return function (type, key, forceReset, getCustomHooks) {
471
+ if (typeof key === 'string') {
472
+ // We're in the initial phase that associates signatures
473
+ // with the functions. Note this may be called multiple times
474
+ // in HOC chains like _s(hoc1(_s(hoc2(_s(actualFunction))))).
316
475
  if (!savedType) {
317
- savedType = type;
318
- hasCustomHooks = typeof getCustomHooks === "function";
476
+ // We're in the innermost call, so this is the actual type.
477
+ // $FlowFixMe[escaped-generic] discovered when updating Flow
478
+ savedType = type
479
+ hasCustomHooks = typeof getCustomHooks === 'function'
319
480
  }
320
- if (type != null && (typeof type === "function" || typeof type === "object")) {
321
- setSignature(type, key, forceReset, getCustomHooks);
481
+ // Set the signature for all types (even wrappers!) in case
482
+ // they have no signatures of their own. This is to prevent
483
+ // problems like https://github.com/facebook/react/issues/20417.
484
+ if (
485
+ type != null &&
486
+ (typeof type === 'function' || typeof type === 'object')
487
+ ) {
488
+ setSignature(type, key, forceReset, getCustomHooks)
322
489
  }
323
- return type;
490
+ return type
324
491
  } else {
492
+ // We're in the _s() call without arguments, which means
493
+ // this is the time to collect custom Hook signatures.
494
+ // Only do this once. This path is hot and runs *inside* every render!
325
495
  if (!didCollectHooks && hasCustomHooks) {
326
- didCollectHooks = true;
327
- collectCustomHooksForSignature(savedType);
496
+ didCollectHooks = true
497
+ collectCustomHooksForSignature(savedType)
328
498
  }
329
499
  }
330
- };
500
+ }
331
501
  }
502
+
332
503
  function isLikelyComponentType(type) {
333
504
  switch (typeof type) {
334
- case "function": {
505
+ case 'function': {
506
+ // First, deal with classes.
335
507
  if (type.prototype != null) {
336
508
  if (type.prototype.isReactComponent) {
337
- return true;
509
+ // React class.
510
+ return true
338
511
  }
339
- const ownNames = Object.getOwnPropertyNames(type.prototype);
340
- if (ownNames.length > 1 || ownNames[0] !== "constructor") {
341
- return false;
512
+ const ownNames = Object.getOwnPropertyNames(type.prototype)
513
+ if (ownNames.length > 1 || ownNames[0] !== 'constructor') {
514
+ // This looks like a class.
515
+ return false
342
516
  }
517
+
343
518
  if (type.prototype.__proto__ !== Object.prototype) {
344
- return false;
519
+ // It has a superclass.
520
+ return false
345
521
  }
522
+ // Pass through.
523
+ // This looks like a regular function with empty prototype.
346
524
  }
347
- const name = type.name || type.displayName;
348
- return typeof name === "string" && /^[A-Z]/.test(name);
525
+ // For plain functions and arrows, use name as a heuristic.
526
+ const name = type.name || type.displayName
527
+ return typeof name === 'string' && /^[A-Z]/.test(name)
349
528
  }
350
- case "object": {
529
+ case 'object': {
351
530
  if (type != null) {
352
- switch (getProperty(type, "$$typeof")) {
531
+ switch (getProperty(type, '$$typeof')) {
353
532
  case REACT_FORWARD_REF_TYPE:
354
533
  case REACT_MEMO_TYPE:
355
- return true;
534
+ // Definitely React components.
535
+ return true
356
536
  default:
357
- return false;
537
+ return false
358
538
  }
359
539
  }
360
- return false;
540
+ return false
361
541
  }
362
542
  default: {
363
- return false;
543
+ return false
364
544
  }
365
545
  }
366
546
  }
367
- function getRefreshReg(filename) {
368
- return (type, id) => register(type, filename + " " + id);
547
+
548
+ function isCompoundComponent(type) {
549
+ if (!isPlainObject(type)) return false
550
+ for (const key in type) {
551
+ if (!isLikelyComponentType(type[key])) return false
552
+ }
553
+ return true
369
554
  }
370
- function registerExportsForReactRefresh(filename, moduleExports) {
555
+
556
+ function isPlainObject(obj) {
557
+ return (
558
+ Object.prototype.toString.call(obj) === '[object Object]' &&
559
+ (obj.constructor === Object || obj.constructor === undefined)
560
+ )
561
+ }
562
+
563
+ /**
564
+ * Plugin utils
565
+ */
566
+
567
+ export function getRefreshReg(filename) {
568
+ return (type, id) => register(type, filename + ' ' + id)
569
+ }
570
+
571
+ // Taken from https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/lib/runtime/RefreshUtils.js#L141
572
+ // This allows to resister components not detected by SWC like styled component
573
+ export function registerExportsForReactRefresh(filename, moduleExports) {
371
574
  for (const key in moduleExports) {
372
- if (key === "__esModule") continue;
373
- const exportValue = moduleExports[key];
575
+ if (key === '__esModule') continue
576
+ const exportValue = moduleExports[key]
374
577
  if (isLikelyComponentType(exportValue)) {
375
- register(exportValue, filename + " export " + key);
578
+ // 'export' is required to avoid key collision when renamed exports that
579
+ // shadow a local component name: https://github.com/vitejs/vite-plugin-react/issues/116
580
+ // The register function has an identity check to not register twice the same component,
581
+ // so this is safe to not used the same key here.
582
+ register(exportValue, filename + ' export ' + key)
583
+ } else if (isCompoundComponent(exportValue)) {
584
+ for (const subKey in exportValue) {
585
+ register(
586
+ exportValue[subKey],
587
+ filename + ' export ' + key + '-' + subKey,
588
+ )
589
+ }
376
590
  }
377
591
  }
378
592
  }
593
+
379
594
  function debounce(fn, delay) {
380
- let handle;
595
+ let handle
381
596
  return () => {
382
- clearTimeout(handle);
383
- handle = setTimeout(fn, delay);
384
- };
597
+ clearTimeout(handle)
598
+ handle = setTimeout(fn, delay)
599
+ }
385
600
  }
386
- const hooks = [];
601
+
602
+ const hooks = []
387
603
  window.__registerBeforePerformReactRefresh = (cb) => {
388
- hooks.push(cb);
389
- };
604
+ hooks.push(cb)
605
+ }
390
606
  const enqueueUpdate = debounce(async () => {
391
- if (hooks.length) await Promise.all(hooks.map((cb) => cb()));
392
- performReactRefresh();
393
- }, 16);
394
- function validateRefreshBoundaryAndEnqueueUpdate(id, prevExports, nextExports) {
395
- var _a, _b;
396
- const ignoredExports = (_b = (_a = window.__getReactRefreshIgnoredExports) == null ? void 0 : _a.call(window, { id })) != null ? _b : [];
397
- if (predicateOnExport(
398
- ignoredExports,
399
- prevExports,
400
- (key) => key in nextExports
401
- ) !== true) {
402
- return "Could not Fast Refresh (export removed)";
607
+ if (hooks.length) await Promise.all(hooks.map((cb) => cb()))
608
+ performReactRefresh()
609
+ }, 16)
610
+
611
+ export function validateRefreshBoundaryAndEnqueueUpdate(
612
+ id,
613
+ prevExports,
614
+ nextExports,
615
+ ) {
616
+ const ignoredExports = window.__getReactRefreshIgnoredExports?.({ id }) ?? []
617
+ if (
618
+ predicateOnExport(
619
+ ignoredExports,
620
+ prevExports,
621
+ (key) => key in nextExports,
622
+ ) !== true
623
+ ) {
624
+ return 'Could not Fast Refresh (export removed)'
403
625
  }
404
- if (predicateOnExport(
405
- ignoredExports,
406
- nextExports,
407
- (key) => key in prevExports
408
- ) !== true) {
409
- return "Could not Fast Refresh (new export)";
626
+ if (
627
+ predicateOnExport(
628
+ ignoredExports,
629
+ nextExports,
630
+ (key) => key in prevExports,
631
+ ) !== true
632
+ ) {
633
+ return 'Could not Fast Refresh (new export)'
410
634
  }
411
- let hasExports = false;
635
+
636
+ let hasExports = false
412
637
  const allExportsAreComponentsOrUnchanged = predicateOnExport(
413
638
  ignoredExports,
414
639
  nextExports,
415
640
  (key, value) => {
416
- hasExports = true;
417
- if (isLikelyComponentType(value)) return true;
418
- return prevExports[key] === nextExports[key];
419
- }
420
- );
641
+ hasExports = true
642
+ if (isLikelyComponentType(value)) return true
643
+ if (isCompoundComponent(value)) return true
644
+ return prevExports[key] === nextExports[key]
645
+ },
646
+ )
421
647
  if (hasExports && allExportsAreComponentsOrUnchanged === true) {
422
- enqueueUpdate();
648
+ enqueueUpdate()
423
649
  } else {
424
- return `Could not Fast Refresh ("${allExportsAreComponentsOrUnchanged}" export is incompatible). Learn more at __README_URL__#consistent-components-exports`;
650
+ return `Could not Fast Refresh ("${allExportsAreComponentsOrUnchanged}" export is incompatible). Learn more at __README_URL__#consistent-components-exports`
425
651
  }
426
652
  }
653
+
427
654
  function predicateOnExport(ignoredExports, moduleExports, predicate) {
428
655
  for (const key in moduleExports) {
429
- if (key === "__esModule") continue;
430
- if (ignoredExports.includes(key)) continue;
431
- const desc = Object.getOwnPropertyDescriptor(moduleExports, key);
432
- if (desc && desc.get) return key;
433
- if (!predicate(key, moduleExports[key])) return key;
656
+ if (key === '__esModule') continue
657
+ if (ignoredExports.includes(key)) continue
658
+ const desc = Object.getOwnPropertyDescriptor(moduleExports, key)
659
+ if (desc && desc.get) return key
660
+ if (!predicate(key, moduleExports[key])) return key
434
661
  }
435
- return true;
662
+ return true
436
663
  }
437
- const __hmr_import = (module) => import(
438
- /* @vite-ignore */
439
- module
440
- );
441
- var refresh_runtime_default = { injectIntoGlobalHook };
442
- export {
443
- __hmr_import,
444
- createSignatureFunctionForTransform,
445
- refresh_runtime_default as default,
446
- getRefreshReg,
447
- injectIntoGlobalHook,
448
- registerExportsForReactRefresh,
449
- validateRefreshBoundaryAndEnqueueUpdate
450
- };
664
+
665
+ // Hides vite-ignored dynamic import so that Vite can skip analysis if no other
666
+ // dynamic import is present (https://github.com/vitejs/vite/pull/12732)
667
+ export const __hmr_import = (module) => import(/* @vite-ignore */ module)
668
+
669
+ // For backwards compatibility with @vitejs/plugin-react.
670
+ export default { injectIntoGlobalHook }