Skip to content

Commit 2fafd44

Browse files
committed
fix: update react-fresh babel plugin
1 parent 1b4d861 commit 2fafd44

File tree

5 files changed

+93
-2425
lines changed

5 files changed

+93
-2425
lines changed

Diff for: examples/styled-components/src/Spring.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { animated, useSpring } from 'react-spring';
2+
import React, { useCallback, useState } from 'react';
3+
4+
export function SpringTest() {
5+
const [thingDone, toggleThingDone] = useState(false);
6+
const doTheThing = useCallback(() => toggleThingDone(!thingDone), [thingDone]);
7+
8+
const fader = useSpring({ opacity: thingDone ? 1 : 0 });
9+
10+
return (
11+
<React.Fragment>
12+
<animated.h1 style={fader}>You did the thing!</animated.h1>
13+
<button type="button" onClick={doTheThing}>
14+
{thingDone ? 'Undo The Thing' : 'Do The Thing'}
15+
</button>
16+
</React.Fragment>
17+
);
18+
}

Diff for: src/babel.dev.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,13 @@ module.exports = composePlugins([
257257
// removing everything we dont want right now
258258

259259
// registration
260-
delete p.visitor.Program;
260+
// delete p.visitor.Program;
261+
// delete p.visitor.Program.exit;
261262

262263
// registrations
263-
delete p.visitor.FunctionDeclaration.enter;
264-
delete p.visitor.FunctionDeclaration.leave;
265-
delete p.visitor.VariableDeclaration;
264+
// delete p.visitor.FunctionDeclaration.enter;
265+
// delete p.visitor.FunctionDeclaration.leave;
266+
// delete p.visitor.VariableDeclaration;
266267

267268
return p;
268269
},

Diff for: src/fresh/babel.js

+68-52
Original file line numberDiff line numberDiff line change
@@ -165,25 +165,6 @@ export default function(babel) {
165165
return false;
166166
}
167167

168-
let hookCalls = new WeakMap();
169-
170-
function recordHookCall(functionNode, hookCallPath, hookName) {
171-
if (!hookCalls.has(functionNode)) {
172-
hookCalls.set(functionNode, []);
173-
}
174-
let hookCallsForFn = hookCalls.get(functionNode);
175-
let key = '';
176-
if (hookCallPath.parent.type === 'VariableDeclarator') {
177-
// TODO: if there is no LHS, consider some other heuristic.
178-
key = hookCallPath.parentPath.get('id').getSource();
179-
}
180-
hookCallsForFn.push({
181-
name: hookName,
182-
callee: hookCallPath.node.callee,
183-
key,
184-
});
185-
}
186-
187168
function isBuiltinHook(hookName) {
188169
switch (hookName) {
189170
case 'useState':
@@ -236,9 +217,64 @@ export default function(babel) {
236217

237218
let seenForRegistration = new WeakSet();
238219
let seenForSignature = new WeakSet();
239-
let seenForHookCalls = new WeakSet();
240220
let seenForOutro = new WeakSet();
241221

222+
let hookCalls = new WeakMap();
223+
const HookCallsVisitor = {
224+
CallExpression(path) {
225+
const node = path.node;
226+
const callee = node.callee;
227+
228+
// Note: this visitor MUST NOT mutate the tree in any way.
229+
// It runs early in a separate traversal and should be very fast.
230+
231+
let name = null;
232+
switch (callee.type) {
233+
case 'Identifier':
234+
name = callee.name;
235+
break;
236+
case 'MemberExpression':
237+
name = callee.property.name;
238+
break;
239+
}
240+
if (name === null || !/^use[A-Z]/.test(name)) {
241+
return;
242+
}
243+
const fnScope = path.scope.getFunctionParent();
244+
if (fnScope === null) {
245+
return;
246+
}
247+
248+
// This is a Hook call. Record it.
249+
const fnNode = fnScope.block;
250+
if (!hookCalls.has(fnNode)) {
251+
hookCalls.set(fnNode, []);
252+
}
253+
let hookCallsForFn = hookCalls.get(fnNode);
254+
let key = '';
255+
if (path.parent.type === 'VariableDeclarator') {
256+
// TODO: if there is no LHS, consider some other heuristic.
257+
key = path.parentPath.get('id').getSource();
258+
}
259+
260+
// Some built-in Hooks reset on edits to arguments.
261+
const args = path.get('arguments');
262+
if (name === 'useState' && args.length > 0) {
263+
// useState second argument is initial state.
264+
key += '(' + args[0].getSource() + ')';
265+
} else if (name === 'useReducer' && args.length > 1) {
266+
// useReducer second argument is initial state.
267+
key += '(' + args[1].getSource() + ')';
268+
}
269+
270+
hookCallsForFn.push({
271+
callee: path.node.callee,
272+
name,
273+
key,
274+
});
275+
},
276+
};
277+
242278
return {
243279
visitor: {
244280
ExportDefaultDeclaration(path) {
@@ -289,6 +325,7 @@ export default function(babel) {
289325
},
290326
FunctionDeclaration: {
291327
enter(path) {
328+
return;
292329
const node = path.node;
293330
let programPath;
294331
let insertAfterPath;
@@ -342,6 +379,7 @@ export default function(babel) {
342379
);
343380
},
344381
exit(path) {
382+
//return;
345383
const node = path.node;
346384
const id = node.id;
347385
if (id === null) {
@@ -358,7 +396,7 @@ export default function(babel) {
358396
return;
359397
}
360398
seenForSignature.add(node);
361-
// Don't muatte the tree above this point.
399+
362400

363401
// Unlike with __register__, this needs to work for nested
364402
// declarations too. So we need to search for a path where
@@ -438,6 +476,7 @@ export default function(babel) {
438476
},
439477
},
440478
VariableDeclaration(path) {
479+
return;
441480
const node = path.node;
442481
let programPath;
443482
let insertAfterPath;
@@ -510,39 +549,16 @@ export default function(babel) {
510549
},
511550
);
512551
},
513-
CallExpression(path) {
514-
const node = path.node;
515-
const callee = node.callee;
516-
517-
let name = null;
518-
switch (callee.type) {
519-
case 'Identifier':
520-
name = callee.name;
521-
break;
522-
case 'MemberExpression':
523-
name = callee.property.name;
524-
break;
525-
}
526-
if (name === null || !/^use[A-Z]/.test(name)) {
527-
return;
528-
}
529-
530-
// Make sure we're not recording the same calls twice.
531-
// This can happen if another Babel plugin replaces parents.
532-
if (seenForHookCalls.has(node)) {
533-
return;
534-
}
535-
seenForHookCalls.add(node);
536-
// Don't mutate the tree above this point.
537-
538-
const fn = path.scope.getFunctionParent();
539-
if (fn === null) {
540-
return;
541-
}
542-
recordHookCall(fn.block, path, name);
543-
},
544552
Program: {
553+
enter(path) {
554+
// This is a separate early visitor because we need to collect Hook calls
555+
// and "const [foo, setFoo] = ..." signatures before the destructuring
556+
// transform mangles them. This extra traversal is not ideal for perf,
557+
// but it's the best we can do until we stop transpiling destructuring.
558+
path.traverse(HookCallsVisitor);
559+
},
545560
exit(path) {
561+
return;
546562
const registrations = registrationsByProgramPath.get(path);
547563
if (registrations === undefined) {
548564
return;

Diff for: test/__babel_fixtures__/hooks.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, {useState} from 'react';
2+
import {useExternalHook} from 'external-hook'
23

34
const NoHooks = () => <div>no hooks</div>;
45

@@ -32,6 +33,7 @@ const useForwardRefFunctionHook = React.forwardRef(function () {
3233
const useCustomHook = () => {
3334
useState(42);
3435
useEffectHook();
36+
useExternalHook();
3537
};
3638

3739
function useFunc () {

0 commit comments

Comments
 (0)