From 58daa51188323fbcde4f0cfdff52175a75a92edc Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 7 Mar 2020 17:15:21 -1000 Subject: [PATCH] WIP2 --- CHANGELOG.md | 11 ++-- docs/tutorial.md | 61 ++++++++++++++++- .../HelloWorld/components/HelloWorld.jsx | 66 +++++++------------ lib/react_on_rails/helper.rb | 3 + lib/tasks/assets.rake | 3 +- 5 files changed, 95 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75e279ebb2..429dae4155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,21 +17,24 @@ Changes since last non-beta release. *Please add entries here for your pull requests that are not yet released.* ### [11.4.0] - 2020-01-19 #### Changed +- Changes enable hashing of the server bundle so that it's in the manifest. This is important + because the `assets:clean` "enhancement" of rails/webpacker deletes any files that are not + in the `manifest.json`. Thus, it's critical to fingerprint the server bundle and adding it to + the manifest. + - Added configuration option `same_bundle_for_client_and_server` with default `false` because - 1. Production applications would typically have a server bundle that differs from the client bundle 2. This change only affects trying to use HMR with react_on_rails with rails/webpacker. The previous behavior was to always go to the webpack-dev-server for the server bundle if the - webpack-dev-server was running _and_ the server bundle was found in the `manifest.json`. Because - the `assets:clean` enhancement of rails/webpacker deletes any files that are not in the `manifest.json`, - we recommend fingerprinting the server bundle and adding it to the manifest. + webpack-dev-server was running _and_ the server bundle was found in the `manifest.json`. If you are using the **same bundle for client and server rendering**, then set this configuration option to `true`. By [justin808](https://github.com/justin808/1240). #### Improved - Removed unnecessary restriction to keep the server bundle in the same directory with the client bundles. Rails/webpacker 4 has an advanced cleanup that will remove any files in the directory of other webpack files. Removing this restriction allows the server bundle to be created in a sibling directory. Note, the rails/webpacker cleanup will remove any files in child directories. By [justin808](https://github.com/justin808/1240). +- The gem execjs no longer needs to be explicitly included. When Rails is installed without `Sprockets`, `ExecJS` was not required, resulting in the error: `uninitialized constant #::ExecJS` ### [11.3.0] - 2019-05-24 #### Added diff --git a/docs/tutorial.md b/docs/tutorial.md index b850943119..5e7a90efdd 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -111,21 +111,59 @@ First, check that the `hmr` option is `true` in your `config/webpacker.yml` file The basic setup will have HMR working with the default webpacker setup. However, the basic will cause a full page refresh each time you save a file. +To have proper React hot loading: +1. Add the `react-hot-loader` and ` @hot-loader/react-dom` npm packages. + ```sh + yarn add --dev react-hot-loader @hot-loader/react-dom + ``` +2. Add changes like this to your entry points +```diff +// app/javascript/packs/hello_react.jsx +import React from 'react'; ++ import { hot } from 'react-hot-loader/root'; +``` + +```diff +- export default HelloWorld; ++ export default hot(HelloWorld); +``` +3. Adjust your webpack configuration for development so that `sourceMapContents` option for the sass +loader is `false` +```diff +// config/webpack/development.js +process.env.NODE_ENV = process.env.NODE_ENV || 'development' +const environment = require('./environment') +// allows for editing sass/scss files directly in browser ++ if (!module.hot) { ++ environment.loaders.get('sass').use.find(item => item.loader === 'sass-loader').options.sourceMapContents = false ++ } ++ +module.exports = environment.toWebpackConfig() +``` +4. Adjust your `config/webpack/environment.js` for a +```diff +// config/webpack/environment.js +// ... +// Fixes: React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work. +// https://github.com/gaearon/react-hot-loader/issues/1227#issuecomment-482139583 ++ environment.config.merge({ resolve: { alias: { 'react-dom': '@hot-loader/react-dom' } } }); +module.exports = environment; +``` @@ -272,7 +310,9 @@ and you will see your live app and you can share this URL with your friends. Con ## Turning on Server Rendering -You can turn on server rendering by simply changing the `prerender` option to `true`: +You can turn on server rendering by: + +1. Changing the `prerender` option to `true`: ```erb <%= react_component("HelloWorld", props: @hello_world_props, prerender: true) %> @@ -288,6 +328,25 @@ If you want to test this out with HMR, then you also need to add this line to yo More likely, you will create a different build file for server rendering. However, if you want to use the same file from the webpack-dev-server, you'll need to add that line. + + + + +PUT IN THE CHANGES TO ALLOW FOR creating different server and client bundles + + + + + + + + + + + + + + Then push to Heroku: ``` diff --git a/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx b/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx index ccdff8272f..e3a89c67af 100644 --- a/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +++ b/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx @@ -1,45 +1,27 @@ -import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useState} from 'react'; -export default class HelloWorld extends React.Component { - static propTypes = { - name: PropTypes.string.isRequired, // this is passed from the Rails view - }; +const HelloWorld = (props) => { + const [name, setName] = useState(props.name); - /** - * @param props - Comes from your rails view. - */ - constructor(props) { - super(props); + return ( +
+

+ Hello, {name}! +

+
+
+ + setName(e.target.value)} + /> +
+
+ ); +}; - // How to set initial state in ES6 class syntax - // https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class - this.state = { name: this.props.name }; - } - - updateName = (name) => { - this.setState({ name }); - }; - - render() { - return ( -
-

- Hello, {this.state.name}! -

-
-
- - this.updateName(e.target.value)} - /> -
-
- ); - } -} +export default HelloWorld; diff --git a/lib/react_on_rails/helper.rb b/lib/react_on_rails/helper.rb index 6c25e2c145..5b96131129 100644 --- a/lib/react_on_rails/helper.rb +++ b/lib/react_on_rails/helper.rb @@ -10,6 +10,7 @@ require "react_on_rails/utils" require "react_on_rails/json_output" require "active_support/concern" +require "execjs" module ReactOnRails module Helper @@ -258,6 +259,8 @@ def server_render_js(js_expression, options = {}) html = result["html"] console_log_script = result["consoleLogScript"] raw("#{html}#{render_options.replay_console ? console_log_script : ''}") + + # TODO, this error is probably different for mini_racer rescue ExecJS::ProgramError => err raise ReactOnRails::PrerenderError, component_name: "N/A (server_render_js called)", err: err, diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index b61e8d6f8d..8dfb9f4f32 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -38,8 +38,7 @@ if defined?(Sprockets) # Note, it's not possible to refer to ReactOnRails configuration values at this point. Rake::Task["assets:precompile"] .clear_prerequisites - .enhance([:environment, "react_on_rails:assets:compile_environment"]) - .enhance do + .enhance([:environment, "react_on_rails:assets:compile_environment"]) do Rake::Task["react_on_rails:assets:symlink_non_digested_assets"].invoke Rake::Task["react_on_rails:assets:delete_broken_symlinks"].invoke end