Skip to content

Commit 9fe4cad

Browse files
committed
feat: transparent class wrapping, fixes #304
1 parent d74c7d9 commit 9fe4cad

File tree

3 files changed

+70
-44
lines changed

3 files changed

+70
-44
lines changed

src/reactHotLoader.js

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -117,53 +117,61 @@ const reactHotLoader = {
117117
configuration.showReactDomPatchNotification = false;
118118
// console.warn('react-🔥-loader activated.');
119119
}
120-
/* eslint-enable */
121-
if (!React.createElement.isPatchedByReactHotLoader) {
122-
const originalCreateElement = React.createElement;
123-
// Trick React into rendering a proxy so that
124-
// its state is preserved when the class changes.
125-
// This will update the proxy if it's for a known type.
126-
React.createElement = (type, ...args) => originalCreateElement(resolveType(type), ...args);
127-
React.createElement.isPatchedByReactHotLoader = true;
120+
if (ReactDOM && ReactDOM.setHotTypeResolver) {
121+
console.log('Types 2');
122+
configuration.intergratedResolver = true;
123+
ReactDOM.setHotTypeResolver(resolveType);
128124
}
129125

130-
if (!React.cloneElement.isPatchedByReactHotLoader) {
131-
const originalCloneElement = React.cloneElement;
132-
133-
React.cloneElement = (element, ...args) => {
134-
const newType = element.type && resolveType(element.type);
135-
if (newType && newType !== element.type) {
136-
return originalCloneElement(
137-
{
138-
...element,
139-
type: newType,
140-
},
141-
...args,
142-
);
143-
}
144-
return originalCloneElement(element, ...args);
145-
};
126+
if (!configuration.intergratedResolver) {
127+
/* eslint-enable */
128+
if (!React.createElement.isPatchedByReactHotLoader) {
129+
const originalCreateElement = React.createElement;
130+
// Trick React into rendering a proxy so that
131+
// its state is preserved when the class changes.
132+
// This will update the proxy if it's for a known type.
133+
React.createElement = (type, ...args) => originalCreateElement(resolveType(type), ...args);
134+
React.createElement.isPatchedByReactHotLoader = true;
135+
}
146136

147-
React.cloneElement.isPatchedByReactHotLoader = true;
148-
}
137+
if (!React.cloneElement.isPatchedByReactHotLoader) {
138+
const originalCloneElement = React.cloneElement;
139+
140+
React.cloneElement = (element, ...args) => {
141+
const newType = element.type && resolveType(element.type);
142+
if (newType && newType !== element.type) {
143+
return originalCloneElement(
144+
{
145+
...element,
146+
type: newType,
147+
},
148+
...args,
149+
);
150+
}
151+
return originalCloneElement(element, ...args);
152+
};
149153

150-
if (!React.createFactory.isPatchedByReactHotLoader) {
151-
// Patch React.createFactory to use patched createElement
152-
// because the original implementation uses the internal,
153-
// unpatched ReactElement.createElement
154-
React.createFactory = type => {
155-
const factory = React.createElement.bind(null, type);
156-
factory.type = type;
157-
return factory;
158-
};
159-
React.createFactory.isPatchedByReactHotLoader = true;
160-
}
154+
React.cloneElement.isPatchedByReactHotLoader = true;
155+
}
156+
157+
if (!React.createFactory.isPatchedByReactHotLoader) {
158+
// Patch React.createFactory to use patched createElement
159+
// because the original implementation uses the internal,
160+
// unpatched ReactElement.createElement
161+
React.createFactory = type => {
162+
const factory = React.createElement.bind(null, type);
163+
factory.type = type;
164+
return factory;
165+
};
166+
React.createFactory.isPatchedByReactHotLoader = true;
167+
}
161168

162-
if (!React.Children.only.isPatchedByReactHotLoader) {
163-
const originalChildrenOnly = React.Children.only;
164-
// Use the same trick as React.createElement
165-
React.Children.only = children => originalChildrenOnly({ ...children, type: resolveType(children.type) });
166-
React.Children.only.isPatchedByReactHotLoader = true;
169+
if (!React.Children.only.isPatchedByReactHotLoader) {
170+
const originalChildrenOnly = React.Children.only;
171+
// Use the same trick as React.createElement
172+
React.Children.only = children => originalChildrenOnly({ ...children, type: resolveType(children.type) });
173+
React.Children.only.isPatchedByReactHotLoader = true;
174+
}
167175
}
168176

169177
if (React.useEffect && !React.useState.isPatchedByReactHotLoader) {

src/reconciler/componentComparator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { areSwappable } from './utils';
55
import { PROXY_KEY, UNWRAP_PROXY } from '../proxy';
66
import { resolveType } from './resolver';
77
import logger from '../logger';
8+
import configuration from '../configuration';
89

910
const getInnerComponentType = component => {
1011
const unwrapper = component[UNWRAP_PROXY];
@@ -89,8 +90,9 @@ const compareComponents = (oldType, newType, setNewType, baseType) => {
8990
const knownPairs = new WeakMap();
9091
const emptyMap = new WeakMap();
9192

92-
export const hotComponentCompare = (oldType, newType, setNewType, baseType) => {
93+
export const hotComponentCompare = (oldType, preNewType, setNewType, baseType) => {
9394
const hotActive = hotComparisonOpen();
95+
const newType = configuration.intergratedResolver ? resolveType(preNewType) : preNewType;
9496
let result = oldType === newType;
9597

9698
if (

src/webpack/patch.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ const additional = {
3434
'if (current!== null&&current.type===element.type)',
3535
'if (current!== null&&hotCompareElements(current.type,element.type,hotUpdateChild(current)))',
3636
],
37+
38+
'16.8-type': [
39+
'function createFiberFromTypeAndProps(type, // React$ElementType\nkey, pendingProps, owner, mode, expirationTime) {',
40+
'function createFiberFromTypeAndProps(type, // React$ElementType\nkey, pendingProps, owner, mode, expirationTime) {type = hotResolveType(type);',
41+
],
42+
43+
'16.8-type-compact': [
44+
'function createFiberFromTypeAndProps(type,// React$ElementType\nkey,pendingProps,owner,mode,expirationTime){',
45+
'function createFiberFromTypeAndProps(type,// React$ElementType\nkey,pendingProps,owner,mode,expirationTime){type = hotResolveType(type);',
46+
]
3747
};
3848

3949
const ReactHotLoaderInjection = `
@@ -45,6 +55,9 @@ var hotUpdateChild = function (child) {
4555
}
4656
}
4757
};
58+
var hotResolveType = function (type) {
59+
return type;
60+
};
4861
var hotCompareElements = function (oldType, newType) {
4962
return oldType === newType
5063
};
@@ -79,6 +92,9 @@ var ReactDOM = {
7992
setHotElementComparator: function (newComparator) {
8093
hotCompareElements = newComparator
8194
},
95+
setHotTypeResolver: function (newResolver) {
96+
hotResolveType = newResolver;
97+
},
8298
`;
8399

84100
const defaultEnd = ['var ReactDOM = {', ReactHotLoaderInjection];
@@ -92,7 +108,7 @@ const injectionEnd = {
92108
'16.4-compact': defaultEndCompact,
93109
};
94110

95-
const sign = '/* 🔥 this is hot-loader/react-dom 🔥 */';
111+
const sign = '/* 🔥 this is hot-loader/react-dom 4.8+ 🔥 */';
96112

97113
function additionalTransform(source) {
98114
for (const key in additional) {

0 commit comments

Comments
 (0)