Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve hot api for production mode - error reporting and babel … #1260

Merged
merged 1 commit into from Jun 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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