Skip to content

Commit

Permalink
feat: transparent class wrapping, fixes #304
Browse files Browse the repository at this point in the history
  • Loading branch information
theKashey committed May 31, 2019
1 parent d74c7d9 commit 9fe4cad
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 44 deletions.
92 changes: 50 additions & 42 deletions src/reactHotLoader.js
Expand Up @@ -117,53 +117,61 @@ const reactHotLoader = {
configuration.showReactDomPatchNotification = false;
// console.warn('react-🔥-loader activated.');
}
/* eslint-enable */
if (!React.createElement.isPatchedByReactHotLoader) {
const originalCreateElement = React.createElement;
// Trick React into rendering a proxy so that
// its state is preserved when the class changes.
// This will update the proxy if it's for a known type.
React.createElement = (type, ...args) => originalCreateElement(resolveType(type), ...args);
React.createElement.isPatchedByReactHotLoader = true;
if (ReactDOM && ReactDOM.setHotTypeResolver) {
console.log('Types 2');
configuration.intergratedResolver = true;
ReactDOM.setHotTypeResolver(resolveType);
}

if (!React.cloneElement.isPatchedByReactHotLoader) {
const originalCloneElement = React.cloneElement;

React.cloneElement = (element, ...args) => {
const newType = element.type && resolveType(element.type);
if (newType && newType !== element.type) {
return originalCloneElement(
{
...element,
type: newType,
},
...args,
);
}
return originalCloneElement(element, ...args);
};
if (!configuration.intergratedResolver) {
/* eslint-enable */
if (!React.createElement.isPatchedByReactHotLoader) {
const originalCreateElement = React.createElement;
// Trick React into rendering a proxy so that
// its state is preserved when the class changes.
// This will update the proxy if it's for a known type.
React.createElement = (type, ...args) => originalCreateElement(resolveType(type), ...args);
React.createElement.isPatchedByReactHotLoader = true;
}

React.cloneElement.isPatchedByReactHotLoader = true;
}
if (!React.cloneElement.isPatchedByReactHotLoader) {
const originalCloneElement = React.cloneElement;

React.cloneElement = (element, ...args) => {
const newType = element.type && resolveType(element.type);
if (newType && newType !== element.type) {
return originalCloneElement(
{
...element,
type: newType,
},
...args,
);
}
return originalCloneElement(element, ...args);
};

if (!React.createFactory.isPatchedByReactHotLoader) {
// Patch React.createFactory to use patched createElement
// because the original implementation uses the internal,
// unpatched ReactElement.createElement
React.createFactory = type => {
const factory = React.createElement.bind(null, type);
factory.type = type;
return factory;
};
React.createFactory.isPatchedByReactHotLoader = true;
}
React.cloneElement.isPatchedByReactHotLoader = true;
}

if (!React.createFactory.isPatchedByReactHotLoader) {
// Patch React.createFactory to use patched createElement
// because the original implementation uses the internal,
// unpatched ReactElement.createElement
React.createFactory = type => {
const factory = React.createElement.bind(null, type);
factory.type = type;
return factory;
};
React.createFactory.isPatchedByReactHotLoader = true;
}

if (!React.Children.only.isPatchedByReactHotLoader) {
const originalChildrenOnly = React.Children.only;
// Use the same trick as React.createElement
React.Children.only = children => originalChildrenOnly({ ...children, type: resolveType(children.type) });
React.Children.only.isPatchedByReactHotLoader = true;
if (!React.Children.only.isPatchedByReactHotLoader) {
const originalChildrenOnly = React.Children.only;
// Use the same trick as React.createElement
React.Children.only = children => originalChildrenOnly({ ...children, type: resolveType(children.type) });
React.Children.only.isPatchedByReactHotLoader = true;
}
}

if (React.useEffect && !React.useState.isPatchedByReactHotLoader) {
Expand Down
4 changes: 3 additions & 1 deletion src/reconciler/componentComparator.js
Expand Up @@ -5,6 +5,7 @@ import { areSwappable } from './utils';
import { PROXY_KEY, UNWRAP_PROXY } from '../proxy';
import { resolveType } from './resolver';
import logger from '../logger';
import configuration from '../configuration';

const getInnerComponentType = component => {
const unwrapper = component[UNWRAP_PROXY];
Expand Down Expand Up @@ -89,8 +90,9 @@ const compareComponents = (oldType, newType, setNewType, baseType) => {
const knownPairs = new WeakMap();
const emptyMap = new WeakMap();

export const hotComponentCompare = (oldType, newType, setNewType, baseType) => {
export const hotComponentCompare = (oldType, preNewType, setNewType, baseType) => {
const hotActive = hotComparisonOpen();
const newType = configuration.intergratedResolver ? resolveType(preNewType) : preNewType;
let result = oldType === newType;

if (
Expand Down
18 changes: 17 additions & 1 deletion src/webpack/patch.js
Expand Up @@ -34,6 +34,16 @@ const additional = {
'if (current!== null&&current.type===element.type)',
'if (current!== null&&hotCompareElements(current.type,element.type,hotUpdateChild(current)))',
],

'16.8-type': [
'function createFiberFromTypeAndProps(type, // React$ElementType\nkey, pendingProps, owner, mode, expirationTime) {',
'function createFiberFromTypeAndProps(type, // React$ElementType\nkey, pendingProps, owner, mode, expirationTime) {type = hotResolveType(type);',
],

'16.8-type-compact': [
'function createFiberFromTypeAndProps(type,// React$ElementType\nkey,pendingProps,owner,mode,expirationTime){',
'function createFiberFromTypeAndProps(type,// React$ElementType\nkey,pendingProps,owner,mode,expirationTime){type = hotResolveType(type);',
]
};

const ReactHotLoaderInjection = `
Expand All @@ -45,6 +55,9 @@ var hotUpdateChild = function (child) {
}
}
};
var hotResolveType = function (type) {
return type;
};
var hotCompareElements = function (oldType, newType) {
return oldType === newType
};
Expand Down Expand Up @@ -79,6 +92,9 @@ var ReactDOM = {
setHotElementComparator: function (newComparator) {
hotCompareElements = newComparator
},
setHotTypeResolver: function (newResolver) {
hotResolveType = newResolver;
},
`;

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

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

function additionalTransform(source) {
for (const key in additional) {
Expand Down

0 comments on commit 9fe4cad

Please sign in to comment.