Skip to content

Commit

Permalink
fix: improve hot api for production mode - error reporting and babel …
Browse files Browse the repository at this point in the history
…plugin
  • Loading branch information
theKashey committed May 31, 2019
1 parent d74c7d9 commit 6b29911
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 29 deletions.
14 changes: 11 additions & 3 deletions examples/styled-components/src/App.js
Expand Up @@ -25,7 +25,7 @@ const indirect = {

const indirectStyled = {
DS: styled.div`
border: px solid #f00;
border: 2px solid #f00;
`,
DE: emoStyled('div')`border: 1px solid #F00`,
};
Expand All @@ -39,10 +39,17 @@ const OtherComponent = () => <span>test</span>;
const Context = React.createContext();

const Hook = () => {
const [state] = React.useState({ x: 4 });
const [state, setState] = React.useState({ x: 2 });
React.useEffect(
() =>
setState(state => ({
x: state.x + 1,
})),
[],
);
return (
<div>
hook state: {state.x}
hook state 1: {state.x}
<Counter />
</div>
);
Expand Down Expand Up @@ -128,6 +135,7 @@ const App = () => <InApp />;

setConfig({
logLevel: 'debug',
hotHooks: true,
});

// return App;
Expand Down
2 changes: 1 addition & 1 deletion examples/styled-components/webpack.config.babel.js
Expand Up @@ -6,7 +6,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/index'],
mode: process.env.NODE_ENV || 'development',
devtool: 'eval-source-map',
devtool: false,
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
Expand Down
3 changes: 2 additions & 1 deletion index.js
Expand Up @@ -8,8 +8,9 @@ if (process.env.NODE_ENV === 'production') {
// this is just server environment
module.exports = require('./dist/react-hot-loader.production.min.js');
} else if (!module.hot) {
console.error('React-Hot-Loader: Hot Module Replacement is not enabled');
module.exports = require('./dist/react-hot-loader.production.min.js');
module.exports.AppContainer.warnAboutHMRDisabled = true;
module.exports.hot.shouldWrapWithAppContainer = true;
} else {
var evalAllowed = false;
try {
Expand Down
34 changes: 18 additions & 16 deletions root.js
@@ -1,28 +1,30 @@
if (module.hot) {
if (process.env.NODE_ENV !== 'production') {
var hot = require('./index').hot;
var cache = require.cache;
if (module.hot) {
var cache = require.cache;

if (!module.parents || module.parents.length === 0) {
throw new Error(
'React-Hot-Loader: `react-hot-loader/root` is not supported on your system. ' +
if (!module.parents || module.parents.length === 0) {
throw new Error(
'React-Hot-Loader: `react-hot-loader/root` is not supported on your system. ' +
'Please use `import {hot} from "react-hot-loader"` instead'
);
}
// access parent
var parent = cache[module.parents[0]];
if (!parent) {
throw new Error(
'React-Hot-Loader: `react-hot-loader/root` is not supported on your system. ' +
);
}
// access parent
var parent = cache[module.parents[0]];
if (!parent) {
throw new Error(
'React-Hot-Loader: `react-hot-loader/root` is not supported on your system. ' +
'Please use `import {hot} from "react-hot-loader"` instead'
);
);
}
// remove self from a cache
delete cache[module.id];
}
// remove self from a cache
delete cache[module.id];
// setup hot for caller
exports.hot = hot(parent);
} else {
// prod mode
exports.hot = function(a) {
exports.hot = function (a) {
return a;
};
}
9 changes: 9 additions & 0 deletions src/AppContainer.prod.js
Expand Up @@ -3,7 +3,16 @@
import React from 'react';

function AppContainer(props) {
if (AppContainer.warnAboutHMRDisabled) {
AppContainer.warnAboutHMRDisabled = true;
console.error(
'React-Hot-Loader: misconfiguration detected, using production version in not production environment.',
);
console.error('React-Hot-Loader: Hot Module Replacement is not enabled.');
}
return React.Children.only(props.children);
}

AppContainer.warnAboutHMRDisabled = false;

export default AppContainer;
21 changes: 19 additions & 2 deletions src/babel.prod.js
@@ -1,12 +1,14 @@
const RHLPackage = 'react-hot-loader';
const RHLRootPackage = 'react-hot-loader/root';
const RHLPackages = [RHLPackage, RHLRootPackage];

function isImportedFromRHL(path, name) {
const binding = path.scope.getBinding(name);
const bindingType = binding && binding.path.node.type;

if (bindingType === 'ImportSpecifier' || bindingType === 'ImportNamespaceSpecifier') {
const bindingParent = binding.path.parent;
return bindingParent.source.value === RHLPackage;
return RHLPackages.includes(bindingParent.source.value);
}

return false;
Expand All @@ -20,7 +22,7 @@ function getRHLContext(file) {
const bodyItem = body[i];
const { source, specifiers } = bodyItem;

if (bodyItem.type !== 'ImportDeclaration' || source.value !== RHLPackage) {
if (bodyItem.type !== 'ImportDeclaration' || !RHLPackages.includes(source.value)) {
continue;
}

Expand Down Expand Up @@ -58,6 +60,7 @@ export default function plugin() {
const specifier = this.rhlContext[i];

if (specifier.kind === 'named') {
// replaces hot(module)(App)
if (
path.node.callee.name === specifier.local &&
// ensure that this is `hot` from RHL
Expand All @@ -69,7 +72,21 @@ export default function plugin() {
path.parentPath.replaceWith(path.parent.arguments[0]);
break;
}

// replaces hot(App)
if (
path.node.callee.name === specifier.local &&
// ensure that this is `hot` from RHL
isImportedFromRHL(path, specifier.local) &&
path.type === 'CallExpression' &&
path.node.arguments[0] &&
path.node.arguments[0].type === 'Identifier'
) {
path.replaceWith(path.node.arguments[0]);
break;
}
} else if (specifier.kind === 'namespace') {
// replaces RHL.hot(module)(App)
if (
path.node.callee.callee &&
path.node.callee.callee.type === 'MemberExpression' &&
Expand Down
18 changes: 17 additions & 1 deletion src/hot.prod.js
@@ -1 +1,17 @@
export default () => Component => Component;
import React from 'react';
import AppContainer from './AppContainer.prod';

const hot = () => {
if (hot.shouldWrapWithAppContainer) {
return Component => props => (
<AppContainer>
<Component {...props} />
</AppContainer>
);
}
return Component => Component;
};

hot.shouldWrapWithAppContainer = false;

export default hot;
4 changes: 3 additions & 1 deletion test/__babel_fixtures__/drop-hot.prod.js
@@ -1,6 +1,7 @@
import React from 'react'
import { hot, foo } from 'react-hot-loader'
import { hot as namedHot, foo as namedFoo } from 'react-hot-loader'
import { hot as rootHot } from 'react-hot-loader/root'
import { hot as namedHot2 } from 'react-hot-loader'
import { hot as notRHLHot } from 'not-react-hot-loader'
import * as RHL from 'react-hot-loader'
Expand All @@ -10,6 +11,7 @@ import * as NOTRHL from 'not-react-hot-loader'
const App = () => <div>Hello World!</div>

const a = hot(module)(App);
const z = rootHot(App);
const b = namedHot(module)(App);
const c = namedHot2(module)(App);
const d = RHL.hot(module)(App);
Expand All @@ -21,4 +23,4 @@ namedFoo(module)(App);
RHL.foo(module)(App);
NOTRHL.hot(module)(App);

export { a, b, c, d, e };
export { a, b, c, d, e, z };
16 changes: 12 additions & 4 deletions test/__snapshots__/babel.test.js.snap
Expand Up @@ -1007,7 +1007,7 @@ exports[`babel Targetting "es2015" tags potential React components drop hot.prod
Object.defineProperty(exports, \\"__esModule\\", {
value: true
});
exports.e = exports.d = exports.c = exports.b = exports.a = undefined;
exports.z = exports.e = exports.d = exports.c = exports.b = exports.a = undefined;
var _react = require('react');
Expand All @@ -1019,6 +1019,8 @@ var RHL = _interopRequireWildcard(_reactHotLoader);
var RHL2 = _interopRequireWildcard(_reactHotLoader);
var _root = require('react-hot-loader/root');
var _notReactHotLoader = require('not-react-hot-loader');
var NOTRHL = _interopRequireWildcard(_notReactHotLoader);
Expand All @@ -1036,6 +1038,7 @@ var App = function App() {
};
var a = App;
var z = App;
var b = App;
var c = App;
var d = App;
Expand All @@ -1051,7 +1054,8 @@ exports.a = a;
exports.b = b;
exports.c = c;
exports.d = d;
exports.e = e;"
exports.e = e;
exports.z = z;"
`;

exports[`babel Targetting "es2015" tags potential React components issue 246.js 1`] = `
Expand Down Expand Up @@ -1883,7 +1887,7 @@ exports[`babel Targetting "modern" tags potential React components drop hot.prod
Object.defineProperty(exports, \\"__esModule\\", {
value: true
});
exports.e = exports.d = exports.c = exports.b = exports.a = undefined;
exports.z = exports.e = exports.d = exports.c = exports.b = exports.a = undefined;
var _react = require('react');
Expand All @@ -1895,6 +1899,8 @@ var RHL = _interopRequireWildcard(_reactHotLoader);
var RHL2 = _interopRequireWildcard(_reactHotLoader);
var _root = require('react-hot-loader/root');
var _notReactHotLoader = require('not-react-hot-loader');
var NOTRHL = _interopRequireWildcard(_notReactHotLoader);
Expand All @@ -1910,6 +1916,7 @@ const App = () => _react2.default.createElement(
);
const a = App;
const z = App;
const b = App;
const c = App;
const d = App;
Expand All @@ -1925,7 +1932,8 @@ exports.a = a;
exports.b = b;
exports.c = c;
exports.d = d;
exports.e = e;"
exports.e = e;
exports.z = z;"
`;
exports[`babel Targetting "modern" tags potential React components issue 246.js 1`] = `
Expand Down

0 comments on commit 6b29911

Please sign in to comment.