diff --git a/.gitignore b/.gitignore index a9a2ff05c..51d63287a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ npm-debug.* spec/dummy/client/npm-debug.log.* /gen-examples + +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index 1043f21ed..59d05acc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ Contributors: please follow the recommendations outlined at [keepachangelog.com] ## [Unreleased] ##### Added - Non-digested version of assets in public folder [#413](https://github.com/shakacode/react_on_rails/pull/413) by [alleycat-at-git] +##### Changed +- Only one webpack config is generated for server and client config. Package.json files were changed to reflect this [#398](https://github.com/shakacode/react_on_rails/pull/398). +- Added npm_build_test_command to allow developers to change what npm command is automatically run from rspec [#398](https://github.com/shakacode/react_on_rails/pull/398). +##### Removed +- Server rendering is no longer an option in the generator and is always accessible [#398](https://github.com/shakacode/react_on_rails/pull/398). +- removed lodash, jquery, and loggerMiddleware from the generated code [#398](https://github.com/shakacode/react_on_rails/pull/398). +- removed webpack watch check for test helper automatic compilation [#398](https://github.com/shakacode/react_on_rails/pull/398). + ##### Changed - Replace URI with Addressable gem. See [#405](https://github.com/shakacode/react_on_rails/pull/405) by [lucke84] diff --git a/README.md b/README.md index d43cad766..872993a56 100644 --- a/README.md +++ b/README.md @@ -161,8 +161,6 @@ In most cases, you should use the `prerender: false` (default behavior) with the Now the server will interpret your JavaScript using [ExecJS](https://github.com/rails/execjs) and pass the resulting HTML to the client. We recommend using [therubyracer](https://github.com/cowboyd/therubyracer) as ExecJS's runtime. The generator will automatically add it to your Gemfile for you. -Note that **server-rendering requires globally exposing your components by setting them to `global`, not `window`** (as is the case with client-rendering). If using the generator, you can pass the `--server-rendering` option to configure your application for server-side rendering. - In the following screenshot you can see the 3 parts of React on Rails rendering: 1. A hidden HTML div that contains the properties of the React component, such as the registered name and any props. A JavaScript function runs after the page loads to convert take this data and build initialize React components. @@ -265,27 +263,30 @@ In this case, a prop and value for `somethingUseful` will go into the railsConte ### Globally Exposing Your React Components Place your JavaScript code inside of the provided `client/app` folder. Use modules just as you would when using webpack alone. The difference here is that instead of mounting React components directly to an element using `React.render`, you **expose your components globally and then mount them with helpers inside of your Rails views**. -+ *Normal Mode (JavaScript is Rendered on client):* - If you are not server rendering, `clientRegistration.jsx` will have + +*Default Mode (works for server and client rendering):* + This is an example of how to expose a component to the `react_component` view helper. ```javascript + // client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx import HelloWorld from '../components/HelloWorld'; import ReactOnRails from 'react-on-rails'; ReactOnRails.register({ HelloWorld }); ``` -+ *Server-Side Rendering:* - - If you are server rendering, `serverRegistration.jsx` will have this. Note, you might be initializing HelloWorld with version specialized for server rendering. +*Separated Server-Side Rendering:* + + You can add a separate webpack configuration file for server rendering that has a separate entry file. ex. 'serverHelloWorldApp.jsx'. Note, you might be initializing HelloWorld with version specialized for server rendering. +  ```javascript import HelloWorld from '../components/HelloWorld'; import ReactOnRails from 'react-on-rails'; ReactOnRails.register({ HelloWorld }); ``` - +  In general, you may want different initialization for your server rendered components. - +  See below section on how to setup redux stores that allow multiple components to talk to the same store. ## ReactOnRails View Helpers API diff --git a/app/helpers/react_on_rails_helper.rb b/app/helpers/react_on_rails_helper.rb index 5c852abd2..3e601255d 100644 --- a/app/helpers/react_on_rails_helper.rb +++ b/app/helpers/react_on_rails_helper.rb @@ -270,7 +270,7 @@ def server_rendered_react_component_html(props, react_component_name, dom_id, # On server `location` option is added (`location = request.fullpath`) # React Router needs this to match the current route - # Make sure that we use up-to-date server-bundle + # Make sure that we use up-to-date webpack-bundle ReactOnRails::ServerRenderingPool.reset_pool_if_server_bundle_was_modified # Since this code is not inserted on a web page, we don't need to escape props diff --git a/docs/additional-reading/heroku-deployment.md b/docs/additional-reading/heroku-deployment.md index b4e312843..46d4b17dc 100644 --- a/docs/additional-reading/heroku-deployment.md +++ b/docs/additional-reading/heroku-deployment.md @@ -84,9 +84,7 @@ namespace :assets do desc "Compile assets with webpack" task :webpack do - sh "cd client && npm run build:client" - # If you are doing server rendering - # sh "cd client && npm run build:server" + sh "cd client && npm run build:production" end task :clobber do diff --git a/docs/additional-reading/node-server-rendering.md b/docs/additional-reading/node-server-rendering.md index 647b0761b..f12c719a7 100644 --- a/docs/additional-reading/node-server-rendering.md +++ b/docs/additional-reading/node-server-rendering.md @@ -3,7 +3,7 @@ ### Warning: this is an experimental feature The default server rendering exploits ExecJS to render react components. -Node server rendering allows you to use separate NodeJS process as a renderer. The process loads server-bundle.js and +Node server rendering allows you to use separate NodeJS process as a renderer. The process loads webpack-bundle.js and then executes javascript to render the component inside its environment. The communication between rails and node occurs via socket (`client/node/node.sock`) diff --git a/docs/additional-reading/rspec-configuration.md b/docs/additional-reading/rspec-configuration.md index 70018c776..de99e0f10 100644 --- a/docs/additional-reading/rspec-configuration.md +++ b/docs/additional-reading/rspec-configuration.md @@ -12,10 +12,10 @@ RSpec.configure do |config| You can pass an RSpec metatag as an optional second parameter to this helper method if you want this helper to run on examples other than where `js: true` (default). The helper will compile webpack files at most once per test run. The helper will not compile the webpack files unless they are out of date (stale). Please take note of the following: -- This utility assumes your build tasks for the static generated files are `npm run build:client` and `npm run build:server` and do not have the `--watch` option enabled. +- This utility uses your `npm_build_test_command' to build the static generated files. This command should not include the `--watch` option. - By default, the webpack processes look for the `app/assets/webpack` folders. If this folder is missing, is empty, or contains files with `mtime`s older than any of the files in your `client` folder, the helper will recompile your assets. You can override this inside of `config/initializers/react_on_rails.rb` by passing a filepath (relative to the root of the app) to the `generated_assets_dir` configuration option. -If you want to speed up the re-compiling process, you can call `npm run build:dev:client` (and `npm run build:dev:server` if doing server rendering) to have webpack run in "watch" mode and recompile these files in the background, which will be much faster when making incremental changes than compiling from scratch. +If you want to speed up the re-compiling process, you can call `npm run build:development` to have webpack run in "watch" mode and recompile these files in the background, which will be much faster when making incremental changes than compiling from scratch. [spec/dummy](../../spec/dummy) contains examples of how to set the proc files for this purpose. diff --git a/docs/additional-reading/webpack.md b/docs/additional-reading/webpack.md index b996ad139..6291427ab 100644 --- a/docs/additional-reading/webpack.md +++ b/docs/additional-reading/webpack.md @@ -12,8 +12,6 @@ You need both include `react-dom/server` and `react` as values for `entry`, like // See use of 'vendor' in the CommonsChunkPlugin inclusion below. vendor: [ 'babel-core/polyfill', - 'jquery', - 'jquery-ujs', 'react', 'react-dom', ], @@ -25,14 +23,6 @@ and you need to expose them: // React is necessary for the client rendering: {test: require.resolve('react'), loader: 'expose?React'}, {test: require.resolve('react-dom'), loader: 'expose?ReactDOM'}, - {test: require.resolve('jquery'), loader: 'expose?jQuery'}, - {test: require.resolve('jquery'), loader: 'expose?$'}, -``` - -`webpack.server.config.js` is similar, but substitute: - -``` - entry: ['./yourCode', 'react-dom/server', 'react'], ``` and use this line rather than `{test: require.resolve('react-dom'), loader: 'expose?ReactDOM'},`: diff --git a/docs/api/ruby-api-hot-reload-view-helpers.md b/docs/api/ruby-api-hot-reload-view-helpers.md index 9f0940530..12f2a8759 100644 --- a/docs/api/ruby-api-hot-reload-view-helpers.md +++ b/docs/api/ruby-api-hot-reload-view-helpers.md @@ -13,8 +13,7 @@ static vs. hot is picked based on whether `ENV["REACT_ON_RAILS_ENV"] == "HOT"` - <%= env_javascript_include_tag(hot: ['http://localhost:3500/vendor-bundle.js', - 'http://localhost:3500/app-bundle.js']) %> + <%= env_javascript_include_tag(hot: ['http://localhost:3500/webpack-bundle.js') %> <%= env_javascript_include_tag(static: 'application_static', diff --git a/docs/basics/generator.md b/docs/basics/generator.md index 80961ae14..97471b7ea 100644 --- a/docs/basics/generator.md +++ b/docs/basics/generator.md @@ -14,7 +14,6 @@ Usage: Options: -R, [--redux], [--no-redux] # Install Redux gems and Redux version of Hello World Example - -S, [--server-rendering], [--no-server-rendering] # Add necessary files and configurations for server-side rendering Runtime options: -f, [--force] # Overwrite files that already exist @@ -33,7 +32,7 @@ The generated client code follows our organization scheme. Each unique set of fu Inside of the generated "HelloWorld" domain you will find the following folders: -+ `startup`: two types of files, one that return a container component and implement any code that differs between client and server code (if using server-rendering), and a `clientRegistration` file that exposes the aforementioned files (as well as a `serverRegistration` file if using server rendering). These registration files are what webpack is using as an entry point. ++ `startup`: This contains the entry point files for webpack. It defaults to a single file that is used for server and client compilation, but if these need to be different, then you can create two webpack configurations with separate endpoints. + `containers`: "smart components" (components that have functionality and logic that is passed to child "dumb components"). + `components`: includes "dumb components", or components that simply render their properties and call functions given to them as properties by a parent component. Ultimately, at least one of these dumb components will have a parent container component. diff --git a/lib/generators/USAGE b/lib/generators/USAGE index 3dcbd689a..c44323a39 100644 --- a/lib/generators/USAGE +++ b/lib/generators/USAGE @@ -1,10 +1,6 @@ Description: -The react_on_rails:install generator combined with the example pull requests of -generator runs will get you up and running efficiently. There's a fair bit of -setup involved when integrating Webpack with Rails. Defaults for options -are such that the default is for the flag to be off. For example, the default for -`-R` is that redux is off, and the default of -b is that skip-bootstrap is off. +The react_on_rails:install generator integrates webpack with rails with ease. You can pass the redux option if you'd like to have redux setup for you automatically. * Redux @@ -12,88 +8,6 @@ are such that the default is for the flag to be off. For example, the default fo to integrate the Redux state container framework. The necessary node modules will be automatically included for you. - The generator uses the organizational `paradigm of "bundles"`. These are like - application domains and are used for grouping your code into webpack bundles - in case you decide to create different bundles for deployment. This is also - useful for separating out logical parts of your application. We recommend that - that each bundle will have it's own Redux store. If you have code that you - want to reuse across bundles, such as middleware or common utilities, place them - under `/client/app/lib`. You can then import them in your client code: - `import MyModule from 'lib/MyModule'`; since we have configured webpack to - automatically resolve the word lib to point to this folder. - -* Using Images and Fonts - - The generator has amended the folders created in `client/assets/` to Rails's - asset path. We recommend that if you have any existing assets that you want - to use with your client code, you should move them to these folders and use - webpack as normal. This allows webpack's development server to have access - to your assets, as it will not be able to see any assets in the default Rails - directories which are above the `/client` directory. - - Alternatively, if you have many existing assets and don't wish to move them, - you could consider creating symlinks from `client/assets` that point to your - Rails assets folders inside of `app/assets/`. The assets there will then be - visible to both Rails and webpack. - -* Bootstrap Integration - - React on Rails ships with Twitter Bootstrap already integrated into the build. - Note that the generator removes require_tree in both the application.js and - application.css.scss files. This is to ensure the correct load order for the - bootstrap integration, and is usually a good idea in general. You will therefore - need to explicitly require your files. - - How the Bootstrap library is loaded depends upon whether one is using the Rails - server or the HMR development server. - - 1. Bootstrap via Rails Server - - The Rails server loads bootstrap-sprockets, provided - by the bootstrap-sass ruby gem (added automatically to your Gemfile by - the generator), via the `app/assets/stylesheets/_bootstrap-custom.scss` - partial. - - This allows for using Bootstrap in your regular Rails stylesheets. If you - wish to customize any of the Bootstrap variables, you can do so via the - `client/assets/stylesheets/_pre-bootstrap.scss` partial. - - 2. Bootstrap via Webpack Dev Server - - The webpack dev server does not go through Rails but instead loads bootstrap - via the `bootstrap-sass-loader` webpack loader. You can configure the loader - via the `client/bootstrap-sass-config.js` file. - - 3. Keeping Custom Bootstrap Configurations Synced - - Because the webpack dev server and Rails each load Bootstrap via a different - file (explained in the two sections immediately above), any changes to - the way components are loaded in one file must also be made to the other - file in order to keep styling consistent between the two. For example, - if an import is excluded in _bootstrap-custom.scss, the same import should - be excluded in `bootstrap-sass-config.js` so that styling in the Rails - server and the webpack dev server will be the same. - - 4. Skip Bootstrap Integration - - Bootstrap integration is enabled by default, but can be disabled by passing - the --skip-bootstrap flag (alias -b). When you don't need Bootstrap in your - existing project, just skip it as needed. - -* JavaScript Linters - - JavaScript linters are enabled by default, but can be disabled by passing the - --skip-js-linters flag (alias j), and those that run in Node have been added to - `client/package.json` under devDependencies. - -* Ruby Linters - - Ruby linters are disabled by default, but can be enabled by passing the - `--ruby-linters` flag when generating. These linters have been added to your - Gemfile in addition to the the appropriate Rake tasks. - - We really love using all the linters! Give them a try. - ******************************************************************************* After running the generator, you will want to: @@ -102,14 +16,7 @@ After running the generator, you will want to: Then you may run - npm run - -And you will see several useful commands: - - express-server - echo 'visit http://localhost:4000' && cd client && npm start - rails-server - echo 'visit http://localhost:3000/hello_world' && foreman start -f Procfile.dev + foreman start -f Procfile.dev More Details: diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb index 4a9d05352..e32ca2c0b 100644 --- a/lib/generators/react_on_rails/base_generator.rb +++ b/lib/generators/react_on_rails/base_generator.rb @@ -4,7 +4,7 @@ module ReactOnRails module Generators - class BaseGenerator < Rails::Generators::Base # rubocop:disable Metrics/ClassLength + class BaseGenerator < Rails::Generators::Base include GeneratorHelper Rails::Generators.hide_namespace(namespace) source_root(File.expand_path("../templates", __FILE__)) @@ -15,12 +15,6 @@ class BaseGenerator < Rails::Generators::Base # rubocop:disable Metrics/ClassLen default: false, desc: "Install Redux gems and Redux version of Hello World Example", aliases: "-R" - # --server-rendering - class_option :server_rendering, - type: :boolean, - default: false, - desc: "Configure for server-side rendering of webpack JavaScript", - aliases: "-S" def add_hello_world_route route "get 'hello_world', to: 'hello_world#index'" @@ -45,14 +39,7 @@ def update_git_ignore def update_application_js data = <<-DATA.strip_heredoc - // DO NOT REQUIRE jQuery or jQuery-ujs in this file! - // DO NOT REQUIRE TREE! - - // CRITICAL that vendor-bundle must be BEFORE bootstrap-sprockets and turbolinks - // since it is exposing jQuery and jQuery-ujs - - //= require vendor-bundle - //= require app-bundle + //= require webpack-bundle DATA @@ -65,13 +52,6 @@ def update_application_js end end - def strip_application_js_of_incompatible_sprockets_statements - application_js = File.join(destination_root, "app/assets/javascripts/application.js") - gsub_file(application_js, "//= require jquery_ujs", "// require jquery_ujs") - gsub_file(application_js, %r{//= require jquery$}, "// require jquery") - gsub_file(application_js, %r{//= require_tree \.$}, "// require_tree .") - end - def strip_application_js_of_double_blank_lines application_js = File.join(destination_root, "app/assets/javascripts/application.js") gsub_file(application_js, /^\n^\n/, "\n") @@ -86,10 +66,7 @@ def copy_base_files base_path = "base/base/" base_files = %w(app/controllers/hello_world_controller.rb client/.babelrc - client/webpack.client.base.config.js - client/webpack.client.rails.config.js - REACT_ON_RAILS.md - client/REACT_ON_RAILS_CLIENT_README.md) + client/webpack.config.js) base_files.each { |file| copy_file(base_path + file, file) } end @@ -104,31 +81,20 @@ def template_base_files end def add_base_gems_to_gemfile - return unless options.server_rendering? append_to_file("Gemfile", "\ngem 'therubyracer', platforms: :ruby\n") end - def template_client_registration_file - filename = "clientRegistration.jsx" - location = "client/app/bundles/HelloWorld/startup" - template("base/base/#{location}/clientRegistration.jsx.tt", "#{location}/#{filename}") - end - - def install_server_rendering_files_if_enabled - return unless options.server_rendering? - base_path = "base/server_rendering/" - %w(client/webpack.server.rails.config.js - client/app/bundles/HelloWorld/startup/serverRegistration.jsx - client/node/package.json + def install_node_files + base_path = "base/base/" + %w(client/node/package.json client/node/server.js).each do |file| copy_file(base_path + file, file) end - - copy_file("base/base/lib/tasks/load_test.rake", "lib/tasks/load_test.rake") end def template_assets_rake_file template("base/base/lib/tasks/assets.rake.tt", "lib/tasks/assets.rake") + copy_file("base/base/lib/tasks/load_test.rake", "lib/tasks/load_test.rake") end ASSETS_RB_APPEND = <<-DATA.strip_heredoc @@ -136,7 +102,7 @@ def template_assets_rake_file # If you do not want to move existing images and fonts from your Rails app # you could also consider creating symlinks there that point to the original # rails directories. In that case, you would not add these paths here. -Rails.application.config.assets.precompile += %w( server-bundle.js ) +Rails.application.config.assets.precompile += %w( webpack-bundle.js ) # Add folder with webpack generated assets to assets.paths Rails.application.config.assets.paths << Rails.root.join("app", "assets", "webpack") diff --git a/lib/generators/react_on_rails/dev_tests_generator.rb b/lib/generators/react_on_rails/dev_tests_generator.rb index 8602620fb..599ea1215 100644 --- a/lib/generators/react_on_rails/dev_tests_generator.rb +++ b/lib/generators/react_on_rails/dev_tests_generator.rb @@ -8,6 +8,12 @@ class DevTestsGenerator < Rails::Generators::Base Rails::Generators.hide_namespace(namespace) source_root(File.expand_path("../templates/dev_tests", __FILE__)) + # --example-server-rendering + class_option :example_server_rendering, + type: :boolean, + default: false, + desc: "Setup prerender true for server rendered examples" + def copy_rspec_files %w(spec/spec_helper.rb spec/rails_helper.rb @@ -40,7 +46,7 @@ def change_webpack_client_base_config_to_include_fallback plugins: [ TEXT sentinel = /^\s\s},\n\s\splugins: \[\n/ - config = File.join(destination_root, "client", "webpack.client.base.config.js") + config = File.join(destination_root, "client", "webpack.config.js") old_contents = File.read(config) new_contents = old_contents.gsub(sentinel, text) File.open(config, "w+") { |f| f.puts new_contents } @@ -53,6 +59,16 @@ def add_test_related_gems_to_gemfile gem("coveralls", require: false) gem("poltergeist") end + + def gsub_prerender_if_server_rendering + return unless options.example_server_rendering + hello_world_index = File.join(destination_root, "app", "views", "hello_world", "index.html.erb") + hello_world_contents = File.read(hello_world_index) + new_hello_world_contents = hello_world_contents.gsub(/prerender: false/, + "prerender: true") + + File.open(hello_world_index, "w+") { |f| f.puts new_hello_world_contents } + end end end end diff --git a/lib/generators/react_on_rails/install_generator.rb b/lib/generators/react_on_rails/install_generator.rb index a3210f0ad..580978715 100644 --- a/lib/generators/react_on_rails/install_generator.rb +++ b/lib/generators/react_on_rails/install_generator.rb @@ -16,12 +16,6 @@ class InstallGenerator < Rails::Generators::Base default: false, desc: "Install Redux gems and Redux version of Hello World Example. Default: false", aliases: "-R" - # --server-rendering - class_option :server_rendering, - type: :boolean, - default: false, - desc: "Add necessary files and configurations for server-side rendering. Default: false", - aliases: "-S" # --ignore-warnings class_option :ignore_warnings, diff --git a/lib/generators/react_on_rails/react_no_redux_generator.rb b/lib/generators/react_on_rails/react_no_redux_generator.rb index e559db20d..ed633f7bf 100644 --- a/lib/generators/react_on_rails/react_no_redux_generator.rb +++ b/lib/generators/react_on_rails/react_no_redux_generator.rb @@ -8,30 +8,16 @@ class ReactNoReduxGenerator < Rails::Generators::Base Rails::Generators.hide_namespace(namespace) source_root(File.expand_path("../templates", __FILE__)) - # --server-rendering - class_option :server_rendering, - type: :boolean, - default: false, - desc: "Configure for server-side rendering of webpack JavaScript", - aliases: "-S" - def copy_base_files base_path = "no_redux/base/" file = "client/app/bundles/HelloWorld/containers/HelloWorld.jsx" copy_file(base_path + file, file) end - def copy_server_rendering_files_if_appropriate - return unless options.server_rendering? - base_path = "no_redux/server_rendering/" - file = "client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx" - copy_file(base_path + file, file) - end - - def template_appropriate_version_of_hello_world_app_client - filename = "HelloWorldAppClient.jsx" + def template_appropriate_version_of_hello_world_app + filename = "HelloWorldApp.jsx" location = "client/app/bundles/HelloWorld/startup" - template("no_redux/base/#{location}/HelloWorldAppClient.jsx.tt", "#{location}/#{filename}") + template("no_redux/base/#{location}/HelloWorldApp.jsx.tt", "#{location}/#{filename}") end end end diff --git a/lib/generators/react_on_rails/react_with_redux_generator.rb b/lib/generators/react_on_rails/react_with_redux_generator.rb index 884335990..f15acc686 100644 --- a/lib/generators/react_on_rails/react_with_redux_generator.rb +++ b/lib/generators/react_on_rails/react_with_redux_generator.rb @@ -6,18 +6,9 @@ class ReactWithReduxGenerator < Rails::Generators::Base Rails::Generators.hide_namespace(namespace) source_root(File.expand_path("../templates", __FILE__)) - # --server-rendering - class_option :server_rendering, - type: :boolean, - default: false, - desc: "Configure for server-side rendering of webpack JavaScript", - aliases: "-S" - def create_redux_directories dirs = %w(actions constants reducers store) dirs.each { |name| empty_directory("client/app/bundles/HelloWorld/#{name}") } - - empty_directory("client/app/lib/middlewares") end def copy_base_redux_files @@ -27,23 +18,15 @@ def copy_base_redux_files client/app/bundles/HelloWorld/constants/helloWorldConstants.jsx client/app/bundles/HelloWorld/reducers/helloWorldReducer.jsx client/app/bundles/HelloWorld/reducers/index.jsx - client/app/bundles/HelloWorld/store/helloWorldStore.jsx - client/app/lib/middlewares/loggerMiddleware.js).each do |file| + client/app/bundles/HelloWorld/store/helloWorldStore.jsx).each do |file| copy_file(base_path + file, file) end end - def copy_server_rendering_redux_files - return unless options.server_rendering? - base_path = "redux/server_rendering/" - file = "client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx" - copy_file(base_path + file, file) - end - - def template_appropriate_version_of_hello_world_app_client - filename = "HelloWorldAppClient.jsx" + def template_appropriate_version_of_hello_world_app + filename = "HelloWorldApp.jsx" location = "client/app/bundles/HelloWorld/startup" - template("redux/base/#{location}/HelloWorldAppClient.jsx.tt", "#{location}/#{filename}") + template("redux/base/#{location}/HelloWorldApp.jsx.tt", "#{location}/#{filename}") end end end diff --git a/lib/generators/react_on_rails/templates/base/base/.DS_Store b/lib/generators/react_on_rails/templates/base/base/.DS_Store new file mode 100644 index 000000000..5008ddfcf Binary files /dev/null and b/lib/generators/react_on_rails/templates/base/base/.DS_Store differ diff --git a/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt b/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt index f9436206c..88d4c4ac5 100644 --- a/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt +++ b/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt @@ -1,6 +1,3 @@ web: rails s -client: sh -c 'rm app/assets/webpack/* || true && cd client && npm run build:dev:client' -<%- if options.server_rendering? %> -server: sh -c 'cd client && npm run build:dev:server' +client: sh -c 'rm app/assets/webpack/* || true && cd client && npm run build:development' node: sh -c 'cd client/node && npm start' -<%- end %> diff --git a/lib/generators/react_on_rails/templates/base/base/REACT_ON_RAILS.md b/lib/generators/react_on_rails/templates/base/base/REACT_ON_RAILS.md deleted file mode 100644 index da6741e7a..000000000 --- a/lib/generators/react_on_rails/templates/base/base/REACT_ON_RAILS.md +++ /dev/null @@ -1,16 +0,0 @@ -The `react_on_rails` gem has been installed. You can view the documentation online at -[React on Rails](https://github.com/shakacode/react_on_rails). - -Also, check out the [example application](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/client/server.js) -for a live example and code. - -The "Hello World" example has been installed. - -+ The view is located at `app/views/hello_world/index.html.erb` -+ The controller is located at `app/controllers/hello_world_controller.rb` - -See [the documentation](https://github.com/shakacode/react_on_rails) for how to build your bundles and -install your packages. Then you can view the example as follows: - -- Rails Server: [localhost:3000/hello_world](http://localhost:3000/hello_world) -- Webpack Development Server with HMR: [localhost:4000/hello_world](http://localhost:4000/hello_world) diff --git a/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt b/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt index 6f0e76018..266bc15d6 100644 --- a/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +++ b/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt @@ -1,4 +1,3 @@ -

<%= options.server_rendering? ? "Server Rendering" : "Client Rendering" %>

-<%%= react_component("HelloWorldApp", - props: @hello_world_props, - prerender: <%= options.server_rendering? %>) %> +

Hello World

+<%%= react_component("HelloWorldApp", props: @hello_world_props, prerender: false) %> + diff --git a/lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md b/lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md deleted file mode 100644 index 7bb961d95..000000000 --- a/lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md +++ /dev/null @@ -1,3 +0,0 @@ -Client folder generated by React on Rails gem. - -See documentation [on github](https://github.com/shakacode/react_on_rails) for details on how it is organized. diff --git a/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorldWidget.jsx.tt b/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorldWidget.jsx.tt index 830844197..8cae5993e 100644 --- a/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorldWidget.jsx.tt +++ b/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorldWidget.jsx.tt @@ -2,7 +2,6 @@ // all your dump component names with Widget. import React, { PropTypes } from 'react'; -import _ from 'lodash'; // Simple example of a React "dumb" component export default class HelloWorldWidget extends React.Component { @@ -13,15 +12,6 @@ export default class HelloWorldWidget extends React.Component { name: PropTypes.string.isRequired, }; - constructor(props, context) { - super(props, context); - - // Uses lodash to bind all methods to the context of the object instance, otherwise - // the methods defined here would not refer to the component's class, not the component - // instance itself. - _.bindAll(this, 'handleChange'); - } - // React will automatically provide us with the event `e` handleChange(e) { const name = e.target.value; @@ -43,7 +33,7 @@ export default class HelloWorldWidget extends React.Component { this.handleChange(e)} /> diff --git a/lib/generators/react_on_rails/templates/base/server_rendering/client/node/package.json b/lib/generators/react_on_rails/templates/base/base/client/node/package.json similarity index 70% rename from lib/generators/react_on_rails/templates/base/server_rendering/client/node/package.json rename to lib/generators/react_on_rails/templates/base/base/client/node/package.json index 3a4478210..f0733585d 100644 --- a/lib/generators/react_on_rails/templates/base/server_rendering/client/node/package.json +++ b/lib/generators/react_on_rails/templates/base/base/client/node/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "start": "node ./server.js -s server-bundle.js" + "start": "node ./server.js -s webpack-bundle.js" }, "dependencies": { } diff --git a/lib/generators/react_on_rails/templates/base/server_rendering/client/node/server.js b/lib/generators/react_on_rails/templates/base/base/client/node/server.js similarity index 97% rename from lib/generators/react_on_rails/templates/base/server_rendering/client/node/server.js rename to lib/generators/react_on_rails/templates/base/base/client/node/server.js index b7b541235..5363abe99 100644 --- a/lib/generators/react_on_rails/templates/base/server_rendering/client/node/server.js +++ b/lib/generators/react_on_rails/templates/base/base/client/node/server.js @@ -2,7 +2,7 @@ var net = require('net'); var fs = require('fs'); var bundlePath = '../../app/assets/webpack/'; -var bundleFileName = 'server-bundle.js'; +var bundleFileName = 'webpack-bundle.js'; var currentArg; diff --git a/lib/generators/react_on_rails/templates/base/base/client/package.json.tt b/lib/generators/react_on_rails/templates/base/base/client/package.json.tt index f1d731867..5b5532a91 100644 --- a/lib/generators/react_on_rails/templates/base/base/client/package.json.tt +++ b/lib/generators/react_on_rails/templates/base/base/client/package.json.tt @@ -7,23 +7,11 @@ "npm": "3.5.0" }, "scripts": { - "build:client": "NODE_ENV=production webpack --config webpack.client.rails.config.js", - <%- if options.server_rendering? -%> - "build:server": "NODE_ENV=production webpack --config webpack.server.rails.config.js", - <%- end -%> - "build:dev:client": "webpack -w --config webpack.client.rails.config.js", - <%- if options.server_rendering? -%> - "build:dev:server": "webpack -w --config webpack.server.rails.config.js", - <%- end -%> - "build:production:client": "NODE_ENV=production webpack --config webpack.client.rails.build.config.js", - <%- if options.server_rendering? -%> - "build:production:server": "NODE_ENV=production webpack --config webpack.server.rails.build.config.js", - <%- end -%> - "test": "echo \"Error: no test specified\" && exit 1" + "build:test": "webpack --config webpack.config.js", + "build:production": "NODE_ENV=production webpack --config webpack.config.js", + "build:development": "webpack -w --config webpack.config.js" }, "dependencies": { - "autoprefixer": "^6.3.5", - "axios": "^0.9.1", "babel": "^6.5.2", "babel-cli": "^6.6.5", "babel-core": "^6.7.4", @@ -33,17 +21,12 @@ "babel-preset-es2015": "^6.6.0", "babel-preset-react": "^6.5.0", "babel-preset-stage-0": "^6.5.0", - "css-loader": "^0.23.1", "es5-shim": "^4.5.7", "expose-loader": "^0.7.1", <%- if options.redux? -%> "immutable": "^3.7.6", <%- end -%> "imports-loader": "^0.6.5", - "jquery": "^2.2.2", - "jquery-ujs": "^1.2.1", - "loader-utils": "^0.2.13", - "lodash": "^4.7.0", <%- if options.redux? -%> "mirror-creator": "1.1.0", <%- end -%> diff --git a/lib/generators/react_on_rails/templates/base/base/client/webpack.client.base.config.js b/lib/generators/react_on_rails/templates/base/base/client/webpack.client.base.config.js deleted file mode 100644 index b96abe10c..000000000 --- a/lib/generators/react_on_rails/templates/base/base/client/webpack.client.base.config.js +++ /dev/null @@ -1,65 +0,0 @@ -// Common client-side webpack configuration used by webpack.hot.config and webpack.rails.config. - -const webpack = require('webpack'); -const path = require('path'); - -const devBuild = process.env.NODE_ENV !== 'production'; -const nodeEnv = devBuild ? 'development' : 'production'; - -module.exports = { - - // the project dir - context: __dirname, - entry: { - - // See use of 'vendor' in the CommonsChunkPlugin inclusion below. - vendor: [ - 'babel-polyfill', - 'jquery', - ], - - // This will contain the app entry points defined by webpack.hot.config and - // webpack.rails.config - app: [ - './app/bundles/HelloWorld/startup/clientRegistration', - ], - }, - resolve: { - extensions: ['', '.js', '.jsx'], - alias: { - lib: path.join(process.cwd(), 'app', 'lib'), - react: path.resolve('./node_modules/react'), - 'react-dom': path.resolve('./node_modules/react-dom'), - }, - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(nodeEnv), - }, - }), - - // https://webpack.github.io/docs/list-of-plugins.html#2-explicit-vendor-chunk - new webpack.optimize.CommonsChunkPlugin({ - - // This name 'vendor' ties into the entry definition - name: 'vendor', - - // We don't want the default vendor.js name - filename: 'vendor-bundle.js', - - // Passing Infinity just creates the commons chunk, but moves no modules into it. - // In other words, we only put what's in the vendor entry definition in vendor-bundle.js - minChunks: Infinity, - }), - ], - module: { - loaders: [ - - // Not all apps require jQuery. Many Rails apps do, such as those using TurboLinks or - // bootstrap js - { test: require.resolve('jquery'), loader: 'expose?jQuery' }, - { test: require.resolve('jquery'), loader: 'expose?$' }, - ], - }, -}; diff --git a/lib/generators/react_on_rails/templates/base/base/client/webpack.client.rails.config.js b/lib/generators/react_on_rails/templates/base/base/client/webpack.client.rails.config.js deleted file mode 100644 index 5e0eb7798..000000000 --- a/lib/generators/react_on_rails/templates/base/base/client/webpack.client.rails.config.js +++ /dev/null @@ -1,53 +0,0 @@ -// Run like this: -// cd client && npm run build:dev:client -// Note that Foreman (Procfile.dev) has also been configured to take care of this. - -// NOTE: All style sheets handled by the asset pipeline in rails - -const webpack = require('webpack'); -const config = require('./webpack.client.base.config'); -const devBuild = process.env.NODE_ENV !== 'production'; - -config.output = { - filename: '[name]-bundle.js', - path: '../app/assets/webpack', -}; - -// You can add entry points specific to rails here -// The es5-shim/sham is for capybara testing -config.entry.vendor.unshift( - 'es5-shim/es5-shim', - 'es5-shim/es5-sham' -); - -// jquery-ujs MUST GO AFTER jquery, so must use 'push' -config.entry.vendor.push('jquery-ujs'); - -// See webpack.common.config for adding modules common to both the webpack dev server and rails -config.module.loaders.push( - { - test: /\.jsx?$/, - loader: 'babel-loader', - exclude: /node_modules/, - }, - { - test: require.resolve('react'), - loader: 'imports?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham', - }, - { - test: require.resolve('jquery-ujs'), - loader: 'imports?jQuery=jquery', - } -); - -module.exports = config; - -if (devBuild) { - console.log('Webpack dev build for Rails'); // eslint-disable-line no-console - module.exports.devtool = 'eval-source-map'; -} else { - config.plugins.push( - new webpack.optimize.DedupePlugin() - ); - console.log('Webpack production build for Rails'); // eslint-disable-line no-console -} diff --git a/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js b/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js new file mode 100644 index 000000000..54d2dd570 --- /dev/null +++ b/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js @@ -0,0 +1,58 @@ +const webpack = require('webpack'); +const path = require('path'); + +const devBuild = process.env.NODE_ENV !== 'production'; +const nodeEnv = devBuild ? 'development' : 'production'; + +config = { + entry: [ + 'es5-shim/es5-shim', + 'es5-shim/es5-sham', + 'babel-polyfill', + './app/bundles/HelloWorld/startup/HelloWorldApp', + ], + + output: { + filename: 'webpack-bundle.js', + path: '../app/assets/webpack', + }, + + resolve: { + extensions: ['', '.js', '.jsx'], + alias: { + react: path.resolve('./node_modules/react'), + 'react-dom': path.resolve('./node_modules/react-dom'), + }, + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(nodeEnv), + }, + }), + ], + module: { + loaders: [ + { + test: require.resolve('react'), + loader: 'imports?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham', + }, + { + test: /\.jsx?$/, loader: 'babel-loader', + exclude: /node_modules/, + }, + ], + }, +}; + +module.exports = config; + +if (devBuild) { + console.log('Webpack dev build for Rails'); // eslint-disable-line no-console + module.exports.devtool = 'eval-source-map'; +} else { + config.plugins.push( + new webpack.optimize.DedupePlugin() + ); + console.log('Webpack production build for Rails'); // eslint-disable-line no-console +} diff --git a/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt b/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt index a71f5f18f..e8b541822 100644 --- a/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +++ b/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt @@ -6,20 +6,18 @@ ReactOnRails.configure do |config| config.generated_assets_dir = File.join(%w(app assets webpack)) # Define the files for we need to check for webpack compilation when running tests - <%- if options.server_rendering? %> - config.webpack_generated_files = %w( client-bundle.js server-bundle.js ) - <% else %> - config.webpack_generated_files = %w( client-bundle.js ) - <%- end %> - - # Server rendering: - # Server bundle is a single file for all server rendering of components. - # Set the server_bundle_js_file to "" if you know that you will not be server rendering. - <%- if options.server_rendering? %> - config.server_bundle_js_file = "server-bundle.js" - <% else %> - config.server_bundle_js_file = "" - <%- end %> + config.webpack_generated_files = %w( webpack-bundle.js ) + + # This is the file used for server rendering. + # This only needs to be modified for advanced usage + # or if you change your webpack bundle file name. + config.server_bundle_js_file = "webpack-bundle.js" + + # If you are using the ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config) + # with rspec then this controls what npm command is run + # to automatically refresh your webpack assets on every test run. + config.npm_build_test_command = "npm run build:test" + # increase if you're on JRuby config.server_renderer_pool_size = 1 # seconds diff --git a/lib/generators/react_on_rails/templates/base/base/lib/tasks/assets.rake.tt b/lib/generators/react_on_rails/templates/base/base/lib/tasks/assets.rake.tt index 596a20652..2d4985f1b 100644 --- a/lib/generators/react_on_rails/templates/base/base/lib/tasks/assets.rake.tt +++ b/lib/generators/react_on_rails/templates/base/base/lib/tasks/assets.rake.tt @@ -14,10 +14,7 @@ namespace :assets do desc "Compile assets with webpack" task :webpack do - sh "cd client && npm run build:client" - <%- if options[:server_rendering] -%> - sh "cd client && npm run build:server" - <%- end -%> + sh "cd client && npm run build:production" end task :clobber do diff --git a/lib/generators/react_on_rails/templates/base/base/package.json.tt b/lib/generators/react_on_rails/templates/base/base/package.json.tt index 2878d897e..fff2d91c8 100644 --- a/lib/generators/react_on_rails/templates/base/base/package.json.tt +++ b/lib/generators/react_on_rails/templates/base/base/package.json.tt @@ -8,18 +8,6 @@ "scripts": { "postinstall": "cd client && npm install", "rails-server": "echo 'visit http://localhost:3000/hello_world' && foreman start -f Procfile.dev", - "build:production:client": "(cd client && npm run build:production:client --silent)", - <%- if options.server_rendering? -%> - "build:production:server": "(cd client && npm run build:production:server --silent)", - <%- end -%> - "build:client": "(cd client && npm run build:client --silent)", - <%- if options.server_rendering? -%> - "build:server": "(cd client && npm run build:server --silent)", - <%- end -%> - "build:dev:client": "(cd client && npm run build:dev:client --silent)", - <%- if options.server_rendering? -%> - "build:dev:server": "(cd client && npm run build:dev:server --silent)", - <%- end -%> "test": "rspec" } } diff --git a/lib/generators/react_on_rails/templates/base/server_rendering/client/app/bundles/HelloWorld/startup/serverRegistration.jsx b/lib/generators/react_on_rails/templates/base/server_rendering/client/app/bundles/HelloWorld/startup/serverRegistration.jsx deleted file mode 100644 index 4f1090e32..000000000 --- a/lib/generators/react_on_rails/templates/base/server_rendering/client/app/bundles/HelloWorld/startup/serverRegistration.jsx +++ /dev/null @@ -1,4 +0,0 @@ -import ReactOnRails from 'react-on-rails'; -import HelloWorldApp from './HelloWorldAppServer'; - -ReactOnRails.register({ HelloWorldApp }); diff --git a/lib/generators/react_on_rails/templates/base/server_rendering/client/webpack.server.rails.config.js b/lib/generators/react_on_rails/templates/base/server_rendering/client/webpack.server.rails.config.js deleted file mode 100644 index d0e421245..000000000 --- a/lib/generators/react_on_rails/templates/base/server_rendering/client/webpack.server.rails.config.js +++ /dev/null @@ -1,39 +0,0 @@ -// Webpack configuration for server bundle - -const webpack = require('webpack'); -const path = require('path'); - -const devBuild = process.env.NODE_ENV !== 'production'; -const nodeEnv = devBuild ? 'development' : 'production'; - -module.exports = { - - // the project dir - context: __dirname, - entry: [ - 'babel-polyfill', - './app/bundles/HelloWorld/startup/serverRegistration', - ], - output: { - filename: 'server-bundle.js', - path: '../app/assets/webpack', - }, - resolve: { - extensions: ['', '.js', '.jsx'], - alias: { - lib: path.join(process.cwd(), 'app', 'lib'), - }, - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(nodeEnv), - }, - }), - ], - module: { - loaders: [ - { test: /\.jsx?$/, loader: 'babel-loader', exclude: /node_modules/ }, - ], - }, -}; diff --git a/lib/generators/react_on_rails/templates/dev_tests/spec/features/hello_world_spec.rb b/lib/generators/react_on_rails/templates/dev_tests/spec/features/hello_world_spec.rb index cca380ab8..23d219890 100644 --- a/lib/generators/react_on_rails/templates/dev_tests/spec/features/hello_world_spec.rb +++ b/lib/generators/react_on_rails/templates/dev_tests/spec/features/hello_world_spec.rb @@ -3,7 +3,7 @@ feature "Hello World", js: true do scenario "the hello world example works" do visit "/hello_world" - expect(heading).to have_text("Rendering") + expect(heading).to have_text("Hello World") expect(message).to have_text("Stranger") name_input.set("John Doe") expect(message).to have_text("John Doe") diff --git a/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorld.jsx b/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorld.jsx index dd4dd9bd6..a5a52641d 100644 --- a/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorld.jsx +++ b/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorld.jsx @@ -1,6 +1,5 @@ import React, { PropTypes } from 'react'; import HelloWorldWidget from '../components/HelloWorldWidget'; -import _ from 'lodash'; // Simple example of a React "smart" component export default class HelloWorld extends React.Component { @@ -14,11 +13,6 @@ export default class HelloWorld extends React.Component { // How to set initial state in ES6 class syntax // https://facebook.github.io/react/docs/reusable-components.html#es6-classes this.state = { name: this.props.name }; - - // Uses lodash to bind all methods to the context of the object instance, otherwise - // the methods defined here would not refer to the component's class, not the component - // instance itself. - _.bindAll(this, 'updateName'); } updateName(name) { @@ -28,7 +22,7 @@ export default class HelloWorld extends React.Component { render() { return (
- + this.updateName(e)} />
); } diff --git a/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/startup/clientRegistration.jsx.tt b/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt similarity index 51% rename from lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/startup/clientRegistration.jsx.tt rename to lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt index 1cbb1eb1f..233830242 100644 --- a/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/startup/clientRegistration.jsx.tt +++ b/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt @@ -1,5 +1,11 @@ +import React from 'react'; import ReactOnRails from 'react-on-rails'; -import HelloWorldApp from './HelloWorldAppClient'; + +import HelloWorld from '../containers/HelloWorld'; + +const HelloWorldApp = (props) => ( + +); // This is how react_on_rails can see the HelloWorldApp in the browser. ReactOnRails.register({ HelloWorldApp }); diff --git a/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt b/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt deleted file mode 100644 index 0e0ec41af..000000000 --- a/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import HelloWorld from '../containers/HelloWorld'; - -export default (props) => ( - -); diff --git a/lib/generators/react_on_rails/templates/no_redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx b/lib/generators/react_on_rails/templates/no_redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx deleted file mode 100644 index 0e0ec41af..000000000 --- a/lib/generators/react_on_rails/templates/no_redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import HelloWorld from '../containers/HelloWorld'; - -export default (props) => ( - -); diff --git a/lib/generators/react_on_rails/templates/redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx b/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt similarity index 73% rename from lib/generators/react_on_rails/templates/redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx rename to lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt index 17a7cf503..c0e72aa82 100644 --- a/lib/generators/react_on_rails/templates/redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx +++ b/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt @@ -1,4 +1,5 @@ import React from 'react'; +import ReactOnRails from 'react-on-rails'; import { Provider } from 'react-redux'; import createStore from '../store/helloWorldStore'; @@ -7,8 +8,7 @@ import HelloWorld from '../containers/HelloWorld'; // See documentation for https://github.com/reactjs/react-redux. // This is how you get props from the Rails view into the redux store. // This code here binds your smart component to the redux store. -// This is how the server redux gets hydrated with data. -export default (props) => { +const HelloWorldApp = (props) => { const store = createStore(props); const reactComponent = ( @@ -17,3 +17,6 @@ export default (props) => { ); return reactComponent; }; + +// This is how react_on_rails can see the HelloWorldApp in the browser. +ReactOnRails.register({ HelloWorldApp }); diff --git a/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt b/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt deleted file mode 100644 index b469d6653..000000000 --- a/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { Provider } from 'react-redux'; - -import createStore from '../store/helloWorldStore'; -import HelloWorld from '../containers/HelloWorld'; - -// See documentation for https://github.com/reactjs/react-redux. -// This is how you get props from the Rails view into the redux store. -// This code here binds your smart component to the redux store. -export default (props) => { - const store = createStore(props); - const reactComponent = ( - - - - ); - return reactComponent; -}; diff --git a/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/store/helloWorldStore.jsx b/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/store/helloWorldStore.jsx index 872cd7a53..85d21edd5 100644 --- a/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/store/helloWorldStore.jsx +++ b/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/store/helloWorldStore.jsx @@ -6,10 +6,6 @@ import { compose, createStore, applyMiddleware, combineReducers } from 'redux'; // once your app has asynchronous actions. import thunkMiddleware from 'redux-thunk'; -// This provides an example of logging redux actions to the console. -// You'd want to disable this for production. -import loggerMiddleware from 'lib/middlewares/loggerMiddleware'; - import reducers from '../reducers'; import { initialStates } from '../reducers'; @@ -27,7 +23,7 @@ export default props => { const reducer = combineReducers(reducers); const composedStore = compose( - applyMiddleware(thunkMiddleware, loggerMiddleware) + applyMiddleware(thunkMiddleware) ); const storeCreator = composedStore(createStore); const store = storeCreator(reducer, initialState); diff --git a/lib/generators/react_on_rails/templates/redux/base/client/app/lib/middlewares/loggerMiddleware.js b/lib/generators/react_on_rails/templates/redux/base/client/app/lib/middlewares/loggerMiddleware.js deleted file mode 100644 index 51f1de3db..000000000 --- a/lib/generators/react_on_rails/templates/redux/base/client/app/lib/middlewares/loggerMiddleware.js +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint no-console: 0 */ - -// This logger should be configured not to run in a production environment. -// See https://github.com/petehunt/webpack-howto#6-feature-flags for how you might turn this -// off for production. -export default function logger({ getState }) { - return next => action => { - console.log('will dispatch', action); - - // Call the next dispatch method in the middleware chain. - const result = next(action); - - const immutableState = getState(); - - console.log('state after dispatch', JSON.stringify(immutableState)); - - // This will likely be the action itself, unless - // a middleware further in chain changed it. - return result; - }; -} diff --git a/lib/react_on_rails.rb b/lib/react_on_rails.rb index 44bf9b9aa..e8bc066f3 100644 --- a/lib/react_on_rails.rb +++ b/lib/react_on_rails.rb @@ -14,6 +14,5 @@ require "react_on_rails/test_helper" require "react_on_rails/test_helper/webpack_assets_compiler" require "react_on_rails/test_helper/webpack_assets_status_checker" -require "react_on_rails/test_helper/webpack_process_checker" require "react_on_rails/test_helper/ensure_assets_compiled" require "react_on_rails/test_helper/node_process_launcher" diff --git a/lib/react_on_rails/configuration.rb b/lib/react_on_rails/configuration.rb index 054797720..d840e8d1f 100644 --- a/lib/react_on_rails/configuration.rb +++ b/lib/react_on_rails/configuration.rb @@ -8,7 +8,7 @@ def self.configure def self.setup_config_values if @configuration.webpack_generated_files.empty? - files = ["client-bundle.js"] + files = ["webpack-bundle.js"] if @configuration.server_bundle_js_file.present? files << @configuration.server_bundle_js_file end @@ -44,7 +44,6 @@ def self.configuration # generated_assets_dirs is deprecated generated_assets_dir: "", - server_bundle_js_file: "", prerender: false, replay_console: true, @@ -58,7 +57,8 @@ def self.configuration webpack_generated_files: [], rendering_extension: nil, server_render_method: "", - symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/ + symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/, + npm_build_test_command: "" ) end @@ -68,7 +68,7 @@ class Configuration :logging_on_server, :server_renderer_pool_size, :server_renderer_timeout, :raise_on_prerender_error, :skip_display_none, :generated_assets_dirs, :generated_assets_dir, - :webpack_generated_files, :rendering_extension, + :webpack_generated_files, :rendering_extension, :npm_build_test_command, :server_render_method, :symlink_non_digested_assets_regex def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil, @@ -77,11 +77,12 @@ def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil, server_renderer_timeout: nil, raise_on_prerender_error: nil, skip_display_none: nil, generated_assets_dirs: nil, generated_assets_dir: nil, webpack_generated_files: nil, - rendering_extension: nil, server_render_method: nil, - symlink_non_digested_assets_regex: nil) + rendering_extension: nil, npm_build_test_command: nil, + server_render_method: nil, symlink_non_digested_assets_regex: nil) self.server_bundle_js_file = server_bundle_js_file self.generated_assets_dirs = generated_assets_dirs self.generated_assets_dir = generated_assets_dir + self.npm_build_test_command = npm_build_test_command self.prerender = prerender self.replay_console = replay_console diff --git a/lib/react_on_rails/test_helper.rb b/lib/react_on_rails/test_helper.rb index 71ccd5d4a..d831750ec 100644 --- a/lib/react_on_rails/test_helper.rb +++ b/lib/react_on_rails/test_helper.rb @@ -44,8 +44,6 @@ def self.configure_rspec_to_compile_assets(config, *metatags) # Typical usage passes all params as nil defaults. # webpack_assets_status_checker: provide: `up_to_date?`, `whats_not_up_to_date`, `client_dir` # defaults to ReactOnRails::TestHelper::WebpackAssetsStatusChecker - # webpack_process_checker: provide one method: `def running?` - # defaults to ReactOnRails::TestHelper::WebpackProcessChecker # webpack_assets_compiler: provide one method: `def compile` # defaults to ReactOnRails::TestHelper::WebpackAssetsCompiler # client_dir and generated_assets_dir are passed into the default webpack_assets_status_checker if you @@ -54,7 +52,6 @@ def self.configure_rspec_to_compile_assets(config, *metatags) # webpack_generated_files in your configuration def self.ensure_assets_compiled(webpack_assets_status_checker: nil, webpack_assets_compiler: nil, - webpack_process_checker: nil, client_dir: nil, generated_assets_dir: nil, webpack_generated_files: nil) @@ -80,12 +77,10 @@ def self.ensure_assets_compiled(webpack_assets_status_checker: nil, end webpack_assets_compiler ||= WebpackAssetsCompiler.new - webpack_process_checker ||= WebpackProcessChecker.new ReactOnRails::TestHelper::EnsureAssetsCompiled.new( webpack_assets_status_checker: webpack_assets_status_checker, - webpack_assets_compiler: webpack_assets_compiler, - webpack_process_checker: webpack_process_checker + webpack_assets_compiler: webpack_assets_compiler ).call end end diff --git a/lib/react_on_rails/test_helper/ensure_assets_compiled.rb b/lib/react_on_rails/test_helper/ensure_assets_compiled.rb index 02f73796d..b4a4a9d11 100644 --- a/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +++ b/lib/react_on_rails/test_helper/ensure_assets_compiled.rb @@ -1,31 +1,20 @@ module ReactOnRails module TestHelper class EnsureAssetsCompiled - SECONDS_TO_WAIT = 10 - class << self attr_accessor :has_been_run @has_been_run = false end attr_reader :webpack_assets_status_checker, - :webpack_assets_compiler, - :webpack_process_checker - - MAX_TIME_TO_WAIT = 5 + :webpack_assets_compiler def initialize(webpack_assets_status_checker: nil, - webpack_assets_compiler: nil, - webpack_process_checker: nil) + webpack_assets_compiler: nil) @webpack_assets_status_checker = webpack_assets_status_checker @webpack_assets_compiler = webpack_assets_compiler - @webpack_process_checker = webpack_process_checker end - # rubocop:disable Metrics/AbcSize - # rubocop:disable Metrics/CyclomaticComplexity - # rubocop:disable Metrics/PerceivedComplexity - # Several Scenarios: # 1. No webpack watch processes for static assets and files are mising or out of date. # 2. Only webpack watch process for server bundle as we're the hot reloading setup. @@ -46,79 +35,17 @@ def call # Inform the developer that we're ensuring gen assets are ready. puts_start_compile_check_message(stale_gen_files) - hot_running = webpack_process_checker.hot_running? - client_running = webpack_process_checker.client_running? - server_running = webpack_process_checker.server_running? - already_compiled_client_file = false - - # Check if running "hot" and not running a process to statically compile the client files. - if hot_running && !client_running - puts "Appears you're running hot reloading and are not rebuilding client files "\ - "automatically. We'll try rebuilding only your client files first." - webpack_assets_compiler.compile_client(stale_gen_files) - already_compiled_client_file = true - - stale_gen_files = webpack_assets_status_checker.stale_generated_webpack_files - - # Return if we're all done! - return if stale_gen_files.empty? - end - - loop_count = 0 - if (already_compiled_client_file && server_running) || - (!already_compiled_client_file && client_running) - puts "Waiting #{SECONDS_TO_WAIT} for webpack watch processes to compile files" - loop do - sleep 1 - stale_gen_files = webpack_assets_status_checker.stale_generated_webpack_files - loop_count += 1 - break if loop_count == SECONDS_TO_WAIT || stale_gen_files.empty? - end - end - - final_compilation_check(already_compiled_client_file, client_running, server_running, stale_gen_files) - end - - # rubocop:enable Metrics/AbcSize - # rubocop:enable Metrics/CyclomaticComplexity - # rubocop:enable Metrics/PerceivedComplexity - - def final_compilation_check(already_compiled_client_file, client_running, server_running, stale_gen_files) - return unless stale_gen_files.present? - if client_running || server_running - puts <<-MSG -Arghhhhhh! We still have the following stale generated files after waiting for Webpack to compile: -#{stale_gen_files.join("\n")} - -This can happen if you removed the generated files after they've been created by your webpack -watch processes, such by running a clean on your generated bundles before starting your tests. - MSG - end - - puts <<-MSG - -If you are frequently running tests, you can run webpack in watch mode for static assets to -speed up this process. See the official documentation: -https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/rspec-configuration.md - MSG - - if already_compiled_client_file - # So only do serer file - webpack_assets_compiler.compile_server(stale_gen_files) - else - webpack_assets_compiler.compile_as_necessary(stale_gen_files) - end + webpack_assets_compiler.compile_assets end def puts_start_compile_check_message(stale_files) - server_msg = Utils.server_rendering_is_enabled? ? "and `build:server`" : "" puts <<-MSG Detected are the following stale generated files: #{stale_files.join("\n")} React on Rails will ensure your JavaScript generated files are up to date, using your -top level package.json `build:client` #{server_msg} commands. +client level package.json `build:test` command. MSG end diff --git a/lib/react_on_rails/test_helper/webpack_assets_compiler.rb b/lib/react_on_rails/test_helper/webpack_assets_compiler.rb index 768e5e329..07a31091c 100644 --- a/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +++ b/lib/react_on_rails/test_helper/webpack_assets_compiler.rb @@ -3,38 +3,14 @@ module ReactOnRails module TestHelper class WebpackAssetsCompiler - def compile_as_necessary(stale_files) - compile_client(stale_files) - compile_server(stale_files) - end - - def compile_client(stale_files) - compile_type(:client) if needs_client_compile?(stale_files) - end - - def compile_server(stale_files) - compile_type(:server) if needs_server_compile?(stale_files) - end - - private + def compile_assets + puts "\nBuilding Webpack assets..." - def compile_type(type) - puts "\nBuilding Webpack #{type}-rendering assets..." - - build_output = `cd client && npm run build:#{type}` + build_output = `cd client && #{ReactOnRails.configuration.npm_build_test_command}` raise "Error in building assets!\n#{build_output}" unless Utils.last_process_completed_successfully? - puts "Completed building Webpack #{type}-rendering assets." - end - - def needs_client_compile?(stale_files) - !stale_files.all? { |name| name.include?("server") } - end - - def needs_server_compile?(stale_files) - return false unless Utils.server_rendering_is_enabled? - stale_files.any? { |name| name.include?("server") } + puts "Completed building Webpack assets." end end end diff --git a/lib/react_on_rails/test_helper/webpack_process_checker.rb b/lib/react_on_rails/test_helper/webpack_process_checker.rb deleted file mode 100644 index b52bb5487..000000000 --- a/lib/react_on_rails/test_helper/webpack_process_checker.rb +++ /dev/null @@ -1,54 +0,0 @@ -# You can replace this implementation with your own for use by the -# ReactOnRails::TestHelper.ensure_assets_compiled helper -module ReactOnRails - module TestHelper - class WebpackProcessChecker - def initialize - @printed_once = {} - @needs_client_compile = true - @needs_server_compile = Utils.server_rendering_is_enabled? - @wait_longer = false - end - - # Return true if we should keep waiting - # type is either client or server - def client_running? - client_running = check_running_for_type("client") - return false unless client_running - end - - def server_running? - if Utils.server_rendering_is_enabled? - return true if check_running_for_type("server") - end - false - end - - def hot_running? - _response = `pgrep -fl 'babel-node +server-rails-hot.js'` - Utils.last_process_completed_successfully? - end - - private - - def check_running_for_type(type) - type = type.to_sym - - response = `pgrep -fl 'bin/webpack\s(\\-w|\\-\\-watch)\s\\-\\-config\s.*#{type}.*\\.js'` - is_running = Utils.last_process_completed_successfully? - - if is_running - if @printed_once.empty? - puts "\nDetected Webpack processes running to rebuild your generated files:" - end - unless @printed_once[type] - puts "#{type}: #{response}" - @printed_once[type] = true - end - end - - is_running - end - end - end -end diff --git a/rakelib/example_type.rb b/rakelib/example_type.rb index fa3df2faa..49aea8670 100644 --- a/rakelib/example_type.rb +++ b/rakelib/example_type.rb @@ -28,10 +28,6 @@ def name_pretty "#{@name} example app" end - def server_rendering? - generator_options.include?("--server-rendering") - end - def dir File.join(examples_dir, name) end @@ -53,14 +49,12 @@ def node_modules_dir end def webpack_bundles_dir - File.join(dir, "app", "assets", "javascripts", "generated") + File.join(dir, "app", "assets", "javascripts", "webpack") end def webpack_bundles bundles = [] - bundles << File.join(webpack_bundles_dir, "app-bundle.js") - bundles << File.join(webpack_bundles_dir, "server-bundle.js") if server_rendering? - bundles << File.join(webpack_bundles_dir, "vendor-bundle.js") + bundles << File.join(webpack_bundles_dir, "webpack-bundle.js") end def gemfile @@ -137,8 +131,7 @@ def clean_files def build_webpack_bundles_shell_commands webpack_command = File.join("$(npm bin)", "webpack") shell_commands = [] - shell_commands << "#{webpack_command} --config webpack.server.rails.config.js" if server_rendering? - shell_commands << "#{webpack_command} --config webpack.client.rails.config.js" + shell_commands << "#{webpack_command} --config webpack.config.js" end # Assumes we are inside a rails app's folder and necessary gems have been installed diff --git a/rakelib/examples_config.yml b/rakelib/examples_config.yml index 596281881..043d6fb01 100644 --- a/rakelib/examples_config.yml +++ b/rakelib/examples_config.yml @@ -4,11 +4,11 @@ example_type_data: generator_options: "" - name: basic-server-rendering - generator_options: --server-rendering + generator_options: --example-server-rendering - name: redux generator_options: --redux - name: redux-server-rendering - generator_options: --redux --server-rendering + generator_options: --redux --example-server-rendering diff --git a/spec/dummy/Gemfile.lock b/spec/dummy/Gemfile.lock index 92bb4862c..a1f87ef03 100644 --- a/spec/dummy/Gemfile.lock +++ b/spec/dummy/Gemfile.lock @@ -258,8 +258,9 @@ GEM thread_safe (0.3.5) tilt (2.0.2) tins (1.6.0) - turbolinks (2.5.3) - coffee-rails + turbolinks (5.0.0.beta2) + turbolinks-source + turbolinks-source (5.0.0.beta4) tzinfo (1.2.2) thread_safe (~> 0.1) uglifier (2.7.2) @@ -312,7 +313,7 @@ DEPENDENCIES spring sqlite3 therubyracer - turbolinks (= 2.5.3) + turbolinks (~> 5.0.0.beta2) uglifier (>= 2.7.2) web-console diff --git a/spec/dummy/client/package.json b/spec/dummy/client/package.json index 07b721926..f1252af43 100644 --- a/spec/dummy/client/package.json +++ b/spec/dummy/client/package.json @@ -64,8 +64,8 @@ "eslint": "eslint --ext .js,.jsx .", "jscs": "jscs --verbose .", "jscs:fix": "jscs --verbose -x . --silent", - "build:test": "webpack --config webpack.client.js && webpack --config webpack.server.js", "test": "npm run build:test && rspec", + "build:test": "npm run build:client && npm run build:server", "build:production:client": "NODE_ENV=production webpack --config webpack.client.rails.build.config.js", "build:production:server": "NODE_ENV=production webpack --config webpack.server.rails.build.config.js", "build:client": "webpack --config webpack.client.rails.build.config.js", diff --git a/spec/dummy/config/initializers/react_on_rails.rb b/spec/dummy/config/initializers/react_on_rails.rb index 9688dd0aa..70090820b 100644 --- a/spec/dummy/config/initializers/react_on_rails.rb +++ b/spec/dummy/config/initializers/react_on_rails.rb @@ -20,6 +20,8 @@ def self.custom_context(view_context) # If you are not using server rendering `(prerender: true)`, set this to "". config.server_bundle_js_file = "server-bundle.js" + config.npm_build_test_command = "npm run build:test" + ################################################################################ # CLIENT RENDERING OPTIONS # Below options can be overriden by passing options to the react_on_rails diff --git a/spec/react_on_rails/generators/dev_tests_generator_spec.rb b/spec/react_on_rails/generators/dev_tests_generator_spec.rb index a538e2de0..1eed60ee8 100644 --- a/spec/react_on_rails/generators/dev_tests_generator_spec.rb +++ b/spec/react_on_rails/generators/dev_tests_generator_spec.rb @@ -3,43 +3,44 @@ describe DevTestsGenerator, type: :generator do destination File.expand_path("../../dummy-for-generators/", __FILE__) - before(:all) do - run_generator_test_with_args(%w(), - package_json: true, - webpack_client_base_config: true, - spec: false) - end + context "without server rendering" do + before(:all) do + run_generator_test_with_args(%w(), + package_json: true, + webpack_client_base_config: true, + spec: false) + end - it "copies rspec files" do - %w(spec/spec_helper.rb - spec/rails_helper.rb - spec/simplecov_helper.rb - .rspec).each { |file| assert_file(file) } - end + it "copies rspec files" do + %w(spec/spec_helper.rb + spec/rails_helper.rb + spec/simplecov_helper.rb + .rspec).each { |file| assert_file(file) } + end - it "copies tests" do - %w(spec/features/hello_world_spec.rb).each { |file| assert_file(file) } - end + it "copies tests" do + %w(spec/features/hello_world_spec.rb).each { |file| assert_file(file) } + end - it "changes package.json to use local react-on-rails version of module" do - assert_file("client/package.json") do |contents| - assert_match('"react-on-rails": "../../../.."', contents) - refute_match('"react-on-rails": "ReactOnRails::VERSION"', contents) + it "changes package.json to use local react-on-rails version of module" do + assert_file("client/package.json") do |contents| + assert_match('"react-on-rails": "../../../.."', contents) + refute_match('"react-on-rails": "ReactOnRails::VERSION"', contents) + end end - end - it "adds test-related gems to Gemfile" do - assert_file("Gemfile") do |contents| - assert_match("gem 'rspec-rails', group: :test", contents) - assert_match("gem 'capybara', group: :test", contents) - assert_match("gem 'selenium-webdriver', group: :test", contents) - assert_match("gem 'coveralls', require: false", contents) - assert_match("gem 'poltergeist'", contents) + it "adds test-related gems to Gemfile" do + assert_file("Gemfile") do |contents| + assert_match("gem 'rspec-rails', group: :test", contents) + assert_match("gem 'capybara', group: :test", contents) + assert_match("gem 'selenium-webdriver', group: :test", contents) + assert_match("gem 'coveralls', require: false", contents) + assert_match("gem 'poltergeist'", contents) + end end - end - it "changes the webpack.client.base.config.js to use a resolveLoader" do - expected = <<-TEXT + it "changes the webpack.config.js to use a resolveLoader" do + expected = <<-TEXT resolve: { ... }, @@ -54,8 +55,25 @@ ] TEXT - assert_file("client/webpack.client.base.config.js") do |contents| - assert_match(expected, contents) + assert_file("client/webpack.config.js") do |contents| + assert_match(expected, contents) + end + end + end + + context "with server-rendering" do + before(:all) do + run_generator_test_with_args(%w(--example-server-rendering), + package_json: true, + webpack_client_base_config: true, + spec: false, + hello_world_file: true) + end + + it "adds prerender for examples with example-server-rendering" do + assert_file("app/views/hello_world/index.html.erb") do |contents| + assert_match("prerender: true", contents) + end end end end diff --git a/spec/react_on_rails/generators/install_generator_spec.rb b/spec/react_on_rails/generators/install_generator_spec.rb index 325774a22..5efacafac 100644 --- a/spec/react_on_rails/generators/install_generator_spec.rb +++ b/spec/react_on_rails/generators/install_generator_spec.rb @@ -6,86 +6,40 @@ context "no args" do before(:all) { run_generator_test_with_args(%w()) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:no_server_rendering" - include_examples "no_redux_generator:base" - include_examples "no_redux_generator:no_server_rendering" - end - - context "--server-rendering" do - before(:all) { run_generator_test_with_args(%w(--server-rendering)) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:server_rendering" - include_examples "no_redux_generator:base" - include_examples "no_redux_generator:server_rendering" - end - - context "-S" do - before(:all) { run_generator_test_with_args(%w(-S)) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:server_rendering" - include_examples "no_redux_generator:base" - include_examples "no_redux_generator:server_rendering" + include_examples "base_generator", application_js: true + include_examples "no_redux_generator" end context "--redux" do before(:all) { run_generator_test_with_args(%w(--redux)) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:no_server_rendering" - include_examples "react_with_redux_generator:base" - include_examples "react_with_redux_generator:no_server_rendering" + include_examples "base_generator", application_js: true + include_examples "react_with_redux_generator" end context "-R" do before(:all) { run_generator_test_with_args(%w(-R)) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:no_server_rendering" - include_examples "react_with_redux_generator:base" - include_examples "react_with_redux_generator:no_server_rendering" - end - - context "--redux --server_rendering" do - before(:all) { run_generator_test_with_args(%w(--redux --server-rendering)) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:server_rendering" - include_examples "react_with_redux_generator:base" - include_examples "react_with_redux_generator:server_rendering" - end - - context "-R -S" do - before(:all) { run_generator_test_with_args(%w(-R -S)) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:server_rendering" - include_examples "react_with_redux_generator:base" - include_examples "react_with_redux_generator:server_rendering" - end - - context "-R -S" do - before(:all) { run_generator_test_with_args(%w(-R -S)) } - include_examples "base_generator:base", application_js: true - include_examples "base_generator:server_rendering" - include_examples "react_with_redux_generator:base" - include_examples "react_with_redux_generator:server_rendering" + include_examples "base_generator", application_js: true + include_examples "react_with_redux_generator" end context "without existing application.js or application.js.coffee file" do before(:all) { run_generator_test_with_args([], application_js: false) } - include_examples "base_generator:base", application_js: false + include_examples "base_generator", application_js: false end context "with existing application.js or application.js.coffee file" do before(:all) { run_generator_test_with_args([], application_js: true) } - include_examples "base_generator:base", application_js: true + include_examples "base_generator", application_js: true end context "without existing assets.rb file" do before(:all) { run_generator_test_with_args([], assets_rb: false) } - include_examples "base_generator:base", assets_rb: false + include_examples "base_generator", assets_rb: false end context "with existing assets.rb file" do before(:all) { run_generator_test_with_args([], assets_rb: true) } - include_examples "base_generator:base", assets_rb: true + include_examples "base_generator", assets_rb: true end context "with rails_helper" do diff --git a/spec/react_on_rails/support/generator_spec_helper.rb b/spec/react_on_rails/support/generator_spec_helper.rb index edde76802..9623e8f31 100644 --- a/spec/react_on_rails/support/generator_spec_helper.rb +++ b/spec/react_on_rails/support/generator_spec_helper.rb @@ -13,6 +13,12 @@ def simulate_existing_rails_files(options) simulate_existing_file(".gitignore") if options.fetch(:gitignore, true) + if options.fetch(:hello_world_file, false) + simulate_existing_file( + "app/views/hello_world/index.html.erb", + "<%= react_component('HelloWorldApp', props: @hello_world_props, prerender: false) %>" + ) + end simulate_existing_file("Gemfile", "") simulate_existing_file("config/routes.rb", "Rails.application.routes.draw do\nend\n") simulate_existing_file("config/application.rb", @@ -48,12 +54,12 @@ def simulate_existing_assets_files(options) def simulate_npm_files(options) if options.fetch(:package_json, false) package_json = "client/package.json" - package_json_data = ' "react-on-rails": "2.0.0-beta.1",' + package_json_data = ' "react-on-rails": "5.2.0",' simulate_existing_file(package_json, package_json_data) end return unless options.fetch(:webpack_client_base_config, false) - config = "client/webpack.client.base.config.js" + config = "client/webpack.config.js" text = <<-TEXT resolve: { ... @@ -74,18 +80,6 @@ def run_generator_test_with_args(args, options = {}) run_generator(args + ["--ignore-warnings"]) end -def assert_server_render_procfile - assert_file "Procfile.dev" do |contents| - assert_match(/\n\s*server:/, contents) - end -end - -def assert_client_render_procfile - assert_file "Procfile.dev" do |contents| - refute_match(/\n\s*server:/, contents) - end -end - # Simulate having an existing file for cases where the generator needs to modify, not create, a file def simulate_existing_file(file, data = "some existing text\n") # raise "File #{file} already exists in call to simulate_existing_file" if File.exist?(file) diff --git a/spec/react_on_rails/support/shared_examples/base_generator_examples.rb b/spec/react_on_rails/support/shared_examples/base_generator_examples.rb index 1e3c3080a..c095928e1 100644 --- a/spec/react_on_rails/support/shared_examples/base_generator_examples.rb +++ b/spec/react_on_rails/support/shared_examples/base_generator_examples.rb @@ -1,4 +1,4 @@ -shared_examples "base_generator:base" do |options| +shared_examples "base_generator" do it "adds a route for get 'hello_world' to 'hello_world#index'" do match = <<-MATCH.strip_heredoc Rails.application.routes.draw do @@ -23,14 +23,7 @@ it "updates application.js" do match = <<-MATCH.strip_heredoc - // DO NOT REQUIRE jQuery or jQuery-ujs in this file! - // DO NOT REQUIRE TREE! - - // CRITICAL that vendor-bundle must be BEFORE bootstrap-sprockets and turbolinks - // since it is exposing jQuery and jQuery-ujs - - //= require vendor-bundle - //= require app-bundle + //= require webpack-bundle MATCH assert_file("app/assets/javascripts/application.js") do |contents| @@ -38,25 +31,6 @@ end end - it "doesn't include incompatible sprockets require statements" do - assert_file("app/assets/javascripts/application.js") do |contents| - refute_match(%r{//= require_tree \.$}, contents) - refute_match(%r{//= require jquery$}, contents) - refute_match("//= require jquery_ujs", contents) - end - end - - it "comments out incompatible sprockets require statements" do - assert_file("app/assets/javascripts/application.js") do |contents| - if options[:application_js] - assert_match(%r{// require_tree \.$}, contents) - assert_match(%r{// require jquery$}, contents) - assert_match("//= require jquery-ui", contents) - assert_match("// require jquery_ujs", contents) - end - end - end - it "creates react directories" do dirs = %w(components containers startup) dirs.each { |dirname| assert_directory "client/app/bundles/HelloWorld/#{dirname}" } @@ -65,98 +39,23 @@ it "copies react files" do %w(app/controllers/hello_world_controller.rb app/views/hello_world/index.html.erb - client/REACT_ON_RAILS_CLIENT_README.md - client/app/bundles/HelloWorld/startup/clientRegistration.jsx - client/webpack.client.rails.config.js + client/webpack.config.js client/.babelrc + client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx client/package.json config/initializers/react_on_rails.rb package.json - Procfile.dev - REACT_ON_RAILS.md).each { |file| assert_file(file) } + Procfile.dev).each { |file| assert_file(file) } end it "appends path configurations to assets.rb" do expected = ReactOnRails::Generators::BaseGenerator::ASSETS_RB_APPEND assert_file("config/initializers/assets.rb") { |contents| assert_match(expected, contents) } end -end - -shared_examples "base_generator:no_server_rendering" do - it "copies client-side-rendering version of Procfile.dev" do - %w(Procfile.dev).each do |file| - assert_file(file) do |contents| - refute_match(/server: sh -c 'cd client && npm run build:dev:server'/, contents) - end - end - end - - it "copies client-side-rendering version of hello_world/index.html.erb" do - assert_file("app/views/hello_world/index.html.erb") do |contents| - assert_match("prerender: false", contents) - end - end - - it "templates client-side-rendering version of webpack.client.base.js" do - assert_file("client/webpack.client.base.config.js") do |contents| - assert_match("clientRegistration", contents) - end - end - - it "doesn't add therubyracer to the Gemfile" do - assert_file("Gemfile") do |contents| - refute_match("gem 'therubyracer', platforms: :ruby", contents) - end - end - - it "doesn't copy server-side-rendering-only files" do - %w(client/webpack.server.rails.config.js - client/app/bundles/HelloWorld/startup/serverRegistration.jsx).each { |file| assert_no_file(file) } - end - - it "sets server bundle js file to '' in react_on_rails initializer" do - assert_file("config/initializers/react_on_rails.rb") do |contents| - assert_match(/config.server_bundle_js_file = ""/, contents) - end - end -end - -shared_examples "base_generator:server_rendering" do - it "copies server-rendering-only files" do - %w(client/webpack.server.rails.config.js - client/app/bundles/HelloWorld/startup/serverRegistration.jsx).each { |file| assert_file(file) } - end - - it "templates client-side-rendering version of webpack.client.base.js" do - assert_file("client/webpack.client.base.config.js") do |contents| - assert_match("clientRegistration", contents) - end - end - - it "copies server-side-rendering version of Procfile.dev" do - %w(Procfile.dev).each do |file| - assert_file(file) do |contents| - assert_match(/server: sh -c 'cd client && npm run build:dev:server'/, contents) - end - end - end - - it "copies the server-side-rendering version of hello_world/index.html.erb" do - assert_file("app/views/hello_world/index.html.erb") do |contents| - assert_match("prerender: true", contents) - end - end - - it "adds therubyracer to the Gemfile" do - assert_file("Gemfile") do |contents| - assert_match("gem 'therubyracer', platforms: :ruby", contents) - end - end - it "sets server bundle js file to server-bundle in react_on_rails initializer" do - regexp = /config.server_bundle_js_file = "server-bundle.js"/ - assert_file("config/initializers/react_on_rails.rb") do |contents| - assert_match(regexp, contents) + it "templates HelloWorldApp into webpack.config.js" do + assert_file("client/webpack.config.js") do |contents| + assert_match("HelloWorldApp", contents) end end end diff --git a/spec/react_on_rails/support/shared_examples/react_no_redux_generator_examples.rb b/spec/react_on_rails/support/shared_examples/react_no_redux_generator_examples.rb index 4c8045c6a..e9a088bc1 100644 --- a/spec/react_on_rails/support/shared_examples/react_no_redux_generator_examples.rb +++ b/spec/react_on_rails/support/shared_examples/react_no_redux_generator_examples.rb @@ -1,6 +1,9 @@ -shared_examples "no_redux_generator:base" do +shared_examples "no_redux_generator" do it "copies non-redux base files" do assert_file("client/app/bundles/HelloWorld/containers/HelloWorld.jsx") + assert_file("client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx") do |contents| + assert_match("HelloWorld", contents) + end end it "does not place react folders in root" do @@ -9,29 +12,3 @@ end end end - -shared_examples "no_redux_generator:no_server_rendering" do - it "does not copy react server-rendering-specific files" do - assert_no_file("client/webpack.server.rails.config.js") - assert_no_file("client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx") - end - - it "templates the client-side-rendering version of HelloWorldApp" do - assert_file("client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx") do |contents| - assert_match("HelloWorld", contents) - end - end -end - -shared_examples "no_redux_generator:server_rendering" do - it "copies the react server-rendering-specific files" do - assert_file("client/webpack.server.rails.config.js") - assert_file("client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx") - end - - it "templates the server-side-rendering version of HelloWorldApp" do - assert_file("client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx") do |contents| - assert_match("HelloWorld", contents) - end - end -end diff --git a/spec/react_on_rails/support/shared_examples/react_with_redux_generator_examples.rb b/spec/react_on_rails/support/shared_examples/react_with_redux_generator_examples.rb index 3857a5d7d..1546dda2e 100644 --- a/spec/react_on_rails/support/shared_examples/react_with_redux_generator_examples.rb +++ b/spec/react_on_rails/support/shared_examples/react_with_redux_generator_examples.rb @@ -1,7 +1,6 @@ -shared_examples "react_with_redux_generator:base" do +shared_examples "react_with_redux_generator" do it "creates redux directories" do %w(actions constants reducers store).each { |dir| assert_directory("client/app/bundles/HelloWorld/#{dir}") } - assert_directory("client/app/lib/middlewares") end it "copies base redux files" do @@ -11,21 +10,6 @@ client/app/bundles/HelloWorld/reducers/helloWorldReducer.jsx client/app/bundles/HelloWorld/reducers/index.jsx client/app/bundles/HelloWorld/store/helloWorldStore.jsx - client/app/lib/middlewares/loggerMiddleware.js - client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx).each { |file| assert_file(file) } - end -end - -shared_examples "react_with_redux_generator:no_server_rendering" do - it "does not template the server-side rendering files" do - assert_no_file "client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx" - end -end - -shared_examples "react_with_redux_generator:server_rendering" do - it "copies redux version of helloWorldAppServer.jsx" do - assert_file("client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx") do |contents| - assert_match(/import { Provider } from 'react-redux';/, contents) - end + client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx).each { |file| assert_file(file) } end end diff --git a/spec/react_on_rails/test_helper/ensure_assets_compiled_spec.rb b/spec/react_on_rails/test_helper/ensure_assets_compiled_spec.rb index 5a3e3df28..7a9eb664b 100644 --- a/spec/react_on_rails/test_helper/ensure_assets_compiled_spec.rb +++ b/spec/react_on_rails/test_helper/ensure_assets_compiled_spec.rb @@ -11,72 +11,17 @@ %w( client-bundle.js server-bundle.js )) end - context "and webpack process is running" do - let(:process_checker) do - double_process_checker(client_running?: true, - server_running?: true, - hot_running?: false) - end - - it "sleeps until assets are up to date" do - expect(compiler).not_to receive(:compile_as_necessary) - - thread = Thread.new { invoke_ensurer_with_doubles } - - sleep 0.1 - allow(assets_checker).to receive(:stale_generated_webpack_files).and_return([]) - - thread.join - - expect(ReactOnRails::TestHelper::EnsureAssetsCompiled.has_been_run).to eq(true) - end - end - - context "and webpack process is NOT running" do - let(:process_checker) do - double_process_checker(client_running?: false, - server_running?: false, - hot_running?: false) - end - - it "compiles the webpack assets" do - expect(compiler).to receive(:compile_as_necessary).once - invoke_ensurer_with_doubles - end - end - - context "and hot reloading (only server webpack running)" do - let(:process_checker) do - double_process_checker(client_running?: false, - server_running?: true, - hot_running?: true) - end - - it "compiles the webpack assets" do - expect(compiler).to receive(:compile_as_necessary).never - expect(compiler).to receive(:compile_client).once - thread = Thread.new { invoke_ensurer_with_doubles } - - sleep 0.1 - allow(assets_checker).to receive(:stale_generated_webpack_files).and_return([]) - - thread.join - - expect(ReactOnRails::TestHelper::EnsureAssetsCompiled.has_been_run).to eq(true) - end + it "compiles the webpack assets" do + expect(compiler).to receive(:compile_assets).once + invoke_ensurer_with_doubles end end context "when assets are up to date" do let(:assets_checker) { double_assets_checker(stale_generated_webpack_files: []) } - let(:process_checker) do - double_process_checker(client_running?: true, - server_running?: true, - hot_running?: false) - end it "does nothing" do - expect(compiler).not_to receive(:compile_as_necessary) + expect(compiler).not_to receive(:compile_assets) invoke_ensurer_with_doubles end end @@ -84,15 +29,7 @@ def invoke_ensurer_with_doubles ReactOnRails::TestHelper.ensure_assets_compiled( webpack_assets_status_checker: assets_checker, - webpack_assets_compiler: compiler, - webpack_process_checker: process_checker) - end - - def double_process_checker(args = {}) - instance_double(ReactOnRails::TestHelper::WebpackProcessChecker, - client_running?: args.fetch(:client_running?), - server_running?: args.fetch(:server_running?), - hot_running?: args.fetch(:hot_running?)) + webpack_assets_compiler: compiler) end def double_assets_checker(args = {}) @@ -102,7 +39,7 @@ def double_assets_checker(args = {}) def double_assets_compiler instance_double(ReactOnRails::TestHelper::WebpackAssetsCompiler, - :compile_as_necessary) + :compile_assets) end end end