- Notifications
You must be signed in to change notification settings - Fork 750
add auto hot reload support #1065
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
Changes from 17 commits
ee3557f 7cb3d15 acdee60 6543967 bfe0549 ad27aee 304fa1e 210f835 6537709 5c4cf92 4a71138 bff3b07 dbc43fd 01eb0f0 1741e73 02f7217 087211e 6963eaf fffc5e8 a53b327 5d06769 File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -6,6 +6,9 @@ var detectEvents = require("./src/events/detect") | |
| var constructorFromGlobal = require("./src/getConstructor/fromGlobal") | ||
| var constructorFromRequireContextWithGlobalFallback = require("./src/getConstructor/fromRequireContextWithGlobalFallback") | ||
| | ||
| var renderWithReactDOM = require("./src/renderComponent/withReactDOM") | ||
| var renderWithHotReload = require("./src/renderComponent/withHotReload") | ||
| Comment on lines +9 to +10 Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in the add render component extension point PR, the folder structure and import pattern is taking reference from getConstructor for consistency. Please let me know if there is a better way | ||
| | ||
| var ReactRailsUJS = { | ||
| // This attribute holds the name of component which should be mounted | ||
| // example: `data-react-class="MyApp.Items.EditForm"` | ||
| | @@ -80,6 +83,18 @@ var ReactRailsUJS = { | |
| return ReactDOMServer[renderFunction](element) | ||
| }, | ||
| | ||
| // Render `component` using the specified `renderFunction` from `react-dom`. | ||
| // Override this function to render components in a custom way. | ||
| // function signature: ("hydrate" | "render", component, node, props) | ||
| renderComponent: renderWithReactDOM, | ||
| | ||
| // Enables hot reload for component rendering. | ||
| // | ||
| // See the HMR section in README to ensure required steps are completed. | ||
| useHotReload: function(requireContext) { | ||
| this.renderComponent = renderWithHotReload(requireContext) | ||
| }, | ||
| Comment on lines +96 to +101 Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me know if this comment could be more helpful, i.e. should the steps to setup be inlined here? Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In addition, there is an opportunity to "stack" instead of "replace". See the example and discussion at #1064. The proposed approach here mirrors | ||
| | ||
| // Within `searchSelector`, find nodes which should have React components | ||
| // inside them, and mount them with their props. | ||
| mountComponents: function(searchSelector) { | ||
| | @@ -112,9 +127,9 @@ var ReactRailsUJS = { | |
| } | ||
| | ||
| if (hydrate && typeof ReactDOM.hydrate === "function") { | ||
| component = ReactDOM.hydrate(component, node); | ||
| renderComponent("hydrate", component, node, props); | ||
| } else { | ||
| component = ReactDOM.render(component, node); | ||
| renderComponent("render", component, node, props); | ||
| } | ||
| } | ||
| } | ||
| | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| var ReactDOM = require("react-dom") | ||
| var reactHotLoader = require("react-hot-loader") | ||
| var AppContainer = reactHotLoader.AppContainer; | ||
| | ||
| // Render React component with hot reload. | ||
| // | ||
| // See the HMR section in README to ensure required steps are completed. | ||
| Comment on lines +7 to +9 Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for this one. Let me know if this comment could be more helpful, i.e. should the steps to setup be inlined here? | ||
| module.exports = function(webpackRequireContext) { | ||
| return function(renderFunctionName, component, node, props) { | ||
| var className = node.getAttribute(ReactRailsUJS.CLASS_NAME_ATTR); | ||
| var filename = getFileNameFromClassName(className); | ||
| var path = webpackRequireContext.resolve("./" + filename); | ||
| var cache = require.cache; | ||
| var module = cache[path]; | ||
| var moduleParent = module && cache[module.parents[0]]; | ||
| if (!moduleParent || !moduleParent.hot) { | ||
| console.warn(`Cannot hot reload for ${path}. Ensure webpack-dev-server is started with --hot and WEBPACKER_DEV_SERVER_HMR=true`); | ||
| return; | ||
| } | ||
| moduleParent.hot.accept(path, () => reRenderAllNodes(className, renderFunctionName)); | ||
| | ||
| ReactDOM[renderFunctionName](React.createElement(AppContainer, null, component), node); | ||
| }; | ||
| } | ||
| | ||
| function getFileNameFromClassName(className) { | ||
| var parts = className.split("."); | ||
| var filename = parts.shift(); | ||
| | ||
| return filename; | ||
| } | ||
| | ||
| function reRenderAllNodes(className, renderFunctionName) { | ||
| var nodes = findAllReactNodes(className); | ||
| for (var i = 0; i < nodes.length; ++i) { | ||
| var node = nodes[i]; | ||
| var propsJson = node.getAttribute(ujs.PROPS_ATTR); | ||
| var props = propsJson && JSON.parse(propsJson); | ||
| var FreshComponent = React.createElement(FreshConstructor, props); | ||
| ReactDOM[renderFunctionName](React.createElement(AppContainer, null, FreshComponent), node); | ||
| } | ||
| } | ||
| | ||
| function findAllReactNodes(className) { | ||
| var selector = '[' + ReactRailsUJS.CLASS_NAME_ATTR + '="' + className + '"]'; | ||
| if (ReactRailsUJS.jQuery) { | ||
| return ReactRailsUJS.jQuery(selector, document); | ||
| } else { | ||
| return parent.querySelectorAll(selector); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| var ReactDOM = require("react-dom") | ||
| | ||
| // Render React component via ReactDOM, for example: | ||
| // | ||
| // - `renderComponent("hydrate", component, node, props)` -> `ReactDOM.hydrate(component, node);` | ||
| // - `renderComponent("render", component, node, props)` -> `ReactDOM.render(component, node);` | ||
| // | ||
| module.exports = function(renderFunctionName, component, node) { | ||
| ReactDOM[renderFunctionName](component, node); | ||
| }; |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me know if the steps in readme is concise and simple to follow. Happy to pull into a separate file if requested