From 39adba24caba58e166fd40e4387dd81d79434a53 Mon Sep 17 00:00:00 2001 From: jbhatab Date: Sat, 23 Apr 2016 22:48:53 -0500 Subject: [PATCH 1/2] Updates to generator, docs, webpack config Objective of these changes is to make the generator simpler, partly by simplfying the default behavior of ReactOnRails. * combined webpack files into one webpack config, fixed corresponding tests and code. cleaned up some documentation. * removed jquery, fixed some linting. removed lodash completely * changed asset compliation checks * moved files from server rendering to base for templates * changed server-bundle to webpack-bundle * added prodcution build command and test build command. changed configuration to test build command to be more explicit. changed around some readmes * changed build:dev to build:development --- .gitignore | 2 + CHANGELOG.md | 8 ++ README.md | 19 +-- app/helpers/react_on_rails_helper.rb | 2 +- docs/additional-reading/heroku-deployment.md | 4 +- .../node-server-rendering.md | 2 +- .../additional-reading/rspec-configuration.md | 4 +- docs/additional-reading/webpack.md | 10 -- docs/api/ruby-api-hot-reload-view-helpers.md | 3 +- docs/basics/generator.md | 3 +- lib/generators/USAGE | 97 +-------------- .../react_on_rails/base_generator.rb | 50 ++------ .../react_on_rails/dev_tests_generator.rb | 18 ++- .../react_on_rails/install_generator.rb | 6 - .../react_no_redux_generator.rb | 20 +-- .../react_with_redux_generator.rb | 25 +--- .../templates/base/base/.DS_Store | Bin 0 -> 6148 bytes .../templates/base/base/Procfile.dev.tt | 5 +- .../templates/base/base/REACT_ON_RAILS.md | 16 --- .../app/views/hello_world/index.html.erb.tt | 7 +- .../client/REACT_ON_RAILS_CLIENT_README.md | 3 - .../components/HelloWorldWidget.jsx.tt | 12 +- .../client/node/package.json | 2 +- .../client/node/server.js | 2 +- .../base/base/client/package.json.tt | 23 +--- .../base/client/webpack.client.base.config.js | 65 ---------- .../client/webpack.client.rails.config.js | 53 -------- .../base/base/client/webpack.config.js | 58 +++++++++ .../config/initializers/react_on_rails.rb.tt | 26 ++-- .../base/base/lib/tasks/assets.rake.tt | 5 +- .../templates/base/base/package.json.tt | 12 -- .../HelloWorld/startup/serverRegistration.jsx | 4 - .../client/webpack.server.rails.config.js | 39 ------ .../spec/features/hello_world_spec.rb | 2 +- .../HelloWorld/containers/HelloWorld.jsx | 8 +- .../HelloWorld/startup/HelloWorldApp.jsx.tt} | 8 +- .../startup/HelloWorldAppClient.jsx.tt | 6 - .../startup/HelloWorldAppServer.jsx | 6 - .../HelloWorld/startup/HelloWorldApp.jsx.tt} | 7 +- .../startup/HelloWorldAppClient.jsx.tt | 18 --- .../HelloWorld/store/helloWorldStore.jsx | 6 +- .../app/lib/middlewares/loggerMiddleware.js | 21 ---- lib/react_on_rails.rb | 1 - lib/react_on_rails/configuration.rb | 13 +- lib/react_on_rails/test_helper.rb | 7 +- .../test_helper/ensure_assets_compiled.rb | 81 +----------- .../test_helper/webpack_assets_compiler.rb | 32 +---- .../test_helper/webpack_process_checker.rb | 54 -------- rakelib/example_type.rb | 13 +- rakelib/examples_config.yml | 4 +- spec/dummy/Gemfile.lock | 7 +- spec/dummy/client/package.json | 2 +- .../config/initializers/react_on_rails.rb | 2 + .../generators/dev_tests_generator_spec.rb | 82 +++++++----- .../generators/install_generator_spec.rb | 66 ++-------- .../support/generator_spec_helper.rb | 22 ++-- .../base_generator_examples.rb | 117 ++---------------- .../react_no_redux_generator_examples.rb | 31 +---- .../react_with_redux_generator_examples.rb | 20 +-- .../ensure_assets_compiled_spec.rb | 75 +---------- 60 files changed, 273 insertions(+), 1043 deletions(-) create mode 100644 lib/generators/react_on_rails/templates/base/base/.DS_Store delete mode 100644 lib/generators/react_on_rails/templates/base/base/REACT_ON_RAILS.md delete mode 100644 lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md rename lib/generators/react_on_rails/templates/base/{server_rendering => base}/client/node/package.json (70%) rename lib/generators/react_on_rails/templates/base/{server_rendering => base}/client/node/server.js (97%) delete mode 100644 lib/generators/react_on_rails/templates/base/base/client/webpack.client.base.config.js delete mode 100644 lib/generators/react_on_rails/templates/base/base/client/webpack.client.rails.config.js create mode 100644 lib/generators/react_on_rails/templates/base/base/client/webpack.config.js delete mode 100644 lib/generators/react_on_rails/templates/base/server_rendering/client/app/bundles/HelloWorld/startup/serverRegistration.jsx delete mode 100644 lib/generators/react_on_rails/templates/base/server_rendering/client/webpack.server.rails.config.js rename lib/generators/react_on_rails/templates/{base/base/client/app/bundles/HelloWorld/startup/clientRegistration.jsx.tt => no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt} (51%) delete mode 100644 lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt delete mode 100644 lib/generators/react_on_rails/templates/no_redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx rename lib/generators/react_on_rails/templates/redux/{server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx => base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt} (73%) delete mode 100644 lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt delete mode 100644 lib/generators/react_on_rails/templates/redux/base/client/app/lib/middlewares/loggerMiddleware.js delete mode 100644 lib/react_on_rails/test_helper/webpack_process_checker.rb 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 02602dde8..5ab64a03d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ Contributors: please follow the recommendations outlined at [keepachangelog.com] ##### 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 59dd51130..877da39a8 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 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 -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 From 6286cdd791fc6ed4fad628583600938aa9523902 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Mon, 9 May 2016 22:45:43 -1000 Subject: [PATCH 2/2] Mainly updated docs Misc fine tuning * Update travis to ruby 2.3.1 * Fixed doc in config file * Update the assets.rake inclusion, as it cannot read the configuration when defining tasks. * Add require for Addressable --- .travis.yml | 2 +- CHANGELOG.md | 24 +++-- README.md | 30 +++---- app/helpers/react_on_rails_helper.rb | 4 +- docs/additional-reading/heroku-deployment.md | 31 ------- .../node-server-rendering.md | 19 +++- .../additional-reading/rspec-configuration.md | 42 ++++++++- docs/api/ruby-api-hot-reload-view-helpers.md | 4 +- lib/generators/USAGE | 3 +- .../react_on_rails/base_generator.rb | 12 ++- .../templates/base/base/.DS_Store | Bin 6148 -> 0 bytes .../client/REACT_ON_RAILS_CLIENT_README.md | 9 ++ .../config/initializers/react_on_rails.rb.tt | 55 +++++++++--- .../HelloWorld/startup/HelloWorldApp.jsx.tt | 4 +- lib/react_on_rails/configuration.rb | 6 +- lib/react_on_rails/test_helper.rb | 3 +- .../test_helper/ensure_assets_compiled.rb | 2 +- lib/react_on_rails/version.rb | 2 +- lib/tasks/assets.rake | 85 +++++++++++++----- package.json | 2 +- spec/dummy/Gemfile.lock | 75 ++++++++-------- .../config/initializers/react_on_rails.rb | 40 +++++++-- .../base_generator_examples.rb | 1 + .../ensure_assets_compiled_spec.rb | 3 +- 24 files changed, 298 insertions(+), 160 deletions(-) delete mode 100644 lib/generators/react_on_rails/templates/base/base/.DS_Store create mode 100644 lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md diff --git a/.travis.yml b/.travis.yml index 019df864f..59f894770 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: required language: ruby rvm: - - 2.2.4 + - 2.3.1 services: - docker diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab64a03d..1ae03dbbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,23 +2,37 @@ All notable changes to this project will be documented in this file. Items under `Unreleased` is upcoming features that will be out in next version. Contributors: please follow the recommendations outlined at [keepachangelog.com](http://keepachangelog.com/). Please use the existing headings and styling as a guide, and add a link for the version diff at the bottom of the file. Also, please update the `Unreleased` link to compare to the latest release version. + ## [Unreleased] +##### Breaking Changes +- Added automatic compilation of assets at precompile is now done by ReactOnRails. Thus, you don't need to provide your own assets.rake file that does the precompilation. + [#398](https://github.com/shakacode/react_on_rails/pull/398). +- Migration: you can either + + 1. Specify a `config/react_on_rails` setting for `npm_build_production_command` to be nil to turn this feature off. + 2. Specify the script command you want to run to build your production assets, and remove your assets.rake file. + +Here is the addition to the generated config file: +```ruby + # This configures the script to run to build the production assets by webpack. Set this to nil + # if you don't want react_on_rails building this file for you. + config.npm_build_production_command = "npm run build:production" +``` + ##### Fixed - Fixed errors when server rendered props contain \u2028 or \u2029 characters [#375](https://github.com/shakacode/react_on_rails/pull/375) by [mariusandra] ##### 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). +- Replace URI with Addressable gem. See [#405](https://github.com/shakacode/react_on_rails/pull/405) by [lucke84] + ##### 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] ## [5.2.0] - 2016-04-08 ##### Added diff --git a/README.md b/README.md index 872993a56..c57894675 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,9 @@ and for a store: reduxStore = MyReduxStore(props, railsContext); ``` -Note, you never make these calls. This is what React on Rails does when either server or client rendering. +Note, you never make these calls. This is what React on Rails does when either server or client rendering. You'll be definining functions that take take these params and return a React component or a Redux Store. + +(Note, see below [section](#multiple-react-components-on-a-page-with-one-store) on how to setup redux stores that allow multiple components to talk to the same store.) The `railsContext` has: (see implementation in file react_on_rails_helper.rb for method rails_context for the definitive list). @@ -231,6 +233,9 @@ Suppose you want to display a nav bar with the current navigation link highlight ##### Needing the I18n.locale Suppose you want to server render your react components with localization applied given the current Rails locale. The `railsContext` contains the I18n.locale. +##### Configuring different code for server side rendering +Suppose you want to turn off animation when doing server side rendering. The `serverSide` value is just what you need. + #### Customization of the rails_context You can customize the values passed in the `railsContext` in your `config/initializers/react_on_rails.rb`. Here's how. @@ -263,10 +268,7 @@ 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**. - - -*Default Mode (works for server and client rendering):* - This is an example of how to expose a component to the `react_component` view helper. +This is an example of how to expose a component to the `react_component` view helper. ```javascript // client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx @@ -275,19 +277,11 @@ Place your JavaScript code inside of the provided `client/app` folder. Use modul ReactOnRails.register({ HelloWorld }); ``` -*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. +#### Different Server-Side Rendering Code (and a Server Specific Bundle) + +You may want different initialization for your server rendered components. For example, if you have animation that runs when a component is displayed, you might need to turn that off when server rendering. However, the `railsContext` will tell you if your JavaScript code is running client side or server side. So code that required a different server bundle previously may no longer require this! + +If you do want different code to run, you'd setup a separate webpack compilation file and you'd specify a different, server side entry file. ex. 'serverHelloWorldApp.jsx'. Note, you might be initializing HelloWorld with version specialized for server rendering. ## ReactOnRails View Helpers API Once the bundled files have been generated in your `app/assets/webpack` folder and you have exposed your components globally, you will want to run your code in your Rails views using the included helper method. diff --git a/app/helpers/react_on_rails_helper.rb b/app/helpers/react_on_rails_helper.rb index 877da39a8..9ebb15dca 100644 --- a/app/helpers/react_on_rails_helper.rb +++ b/app/helpers/react_on_rails_helper.rb @@ -4,6 +4,7 @@ # 1. The white spacing in this file matters! # 2. Keep all #{some_var} fully to the left so that all indentation is done evenly in that var require "react_on_rails/prerender_error" +require "addressable/uri" module ReactOnRailsHelper # The env_javascript_include_tag and env_stylesheet_link_tag support the usage of a webpack @@ -270,7 +271,8 @@ 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 webpack-bundle + # Make sure that we use up-to-date bundle file used for server rendering, which is defined + # by config file value for config.server_bundle_js_file 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 46d4b17dc..26dab1318 100644 --- a/docs/additional-reading/heroku-deployment.md +++ b/docs/additional-reading/heroku-deployment.md @@ -64,34 +64,3 @@ bundle bin/rake db:migrate bin/rake db:setup ``` - -#### 3. Create a rake file to add webpack compilation to asset precompilation. You may already have this file if you used the React on Rails generator. - -```ruby -# lib/tasks/assets.rake -# The webpack task must run before assets:environment task. -# Otherwise Sprockets cannot find the files that webpack produces. -# This is the secret sauce for how a Heroku deployment knows to create the webpack generated JavaScript files. -Rake::Task["assets:precompile"] - .clear_prerequisites - .enhance(["assets:compile_environment"]) - -namespace :assets do - # In this task, set prerequisites for the assets:precompile task - task compile_environment: :webpack do - Rake::Task["assets:environment"].invoke - end - - desc "Compile assets with webpack" - task :webpack do - sh "cd client && npm run build:production" - end - - task :clobber do - rm_r Dir.glob(Rails.root.join("app/assets/webpack/*")) - end -end -``` - - - diff --git a/docs/additional-reading/node-server-rendering.md b/docs/additional-reading/node-server-rendering.md index f12c719a7..257ccaec4 100644 --- a/docs/additional-reading/node-server-rendering.md +++ b/docs/additional-reading/node-server-rendering.md @@ -3,10 +3,10 @@ ### 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 webpack-bundle.js and +Node server rendering allows you to use separate NodeJS process as a renderer. The process loads your configured server_bundle_js file and then executes javascript to render the component inside its environment. The communication between rails and node occurs via socket (`client/node/node.sock`) - + ### Getting started To use node process just set `server_render_method = "NodeJS"` in `config/initializers/react_on_rails.rb`. To change back @@ -14,4 +14,17 @@ to ExecJS set `server_render_method = "ExecJS"` ### Configuration -To change the name of server bundle adjust npm start script in `client/node/package.json` +You need to configure the name of the server bundle in two places: + +1. JavaScript: Change the name of server bundle adjust npm start script in `client/node/package.json` +2. Ruby: The configured server bundle file is defined in `config/react_on_rails.rb`, and you'll have a webpack file that creates this. You maybe using the same file for client rendering. + +```ruby + # This is the file used for server rendering of React when using `(prerender: true)` + # If you are never using server rendering, you may set this to "". + # If you are using the same file for client and server rendering, having this set probably does + # not affect performance. + config.server_bundle_js_file = "webpack-bundle.js" +``` + + diff --git a/docs/additional-reading/rspec-configuration.md b/docs/additional-reading/rspec-configuration.md index de99e0f10..4f540b0e7 100644 --- a/docs/additional-reading/rspec-configuration.md +++ b/docs/additional-reading/rspec-configuration.md @@ -9,16 +9,50 @@ RSpec.configure do |config| ReactOnRails::TestHelper.configure_rspec_to_compile_assets(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). +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). The helper is configurable in terms of what command is used to prepare the files. Please take note of the following: -- 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. +- This utility uses your `npm_build_test_command' to build the static generated files. This command **must** not include the `--watch` option. If you have different server and client bundle files, this command **must** create all the bundles. +- By default, the webpack processes look for the `app/assets/webpack` folders (configured as setting `webpack_generated_files` in the `config/react_on_rails.rb`. If this folder is missing, is empty, or contains files in the `config.webpack_generated_files` list with `mtime`s older than any of the files in your `client` folder, the helper will recompile your assets. You can override the location of these files 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: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. +The following `config/react_on_rails.rb` settings **must** match your setup: +```ruby + # Directory where your generated assets go. All generated assets must go to the same directory. + # Configure this in your webpack config files. This relative to your Rails root directory. + config.generated_assets_dir = File.join(%w(app assets webpack)) + + # Define the files we need to check for webpack compilation when running tests. + config.webpack_generated_files = %w( 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" +``` + +If you want to speed up the re-compiling process, you can call `npm run build:development` (per below script) 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, assuming you have your setup like this: + +``` + "scripts": { + "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" + }, +``` [spec/dummy](../../spec/dummy) contains examples of how to set the proc files for this purpose. +## Hot Reloading +If you're using the hot reloading setup, you'll be running a Webpack development server to provide the JavaScript and mabye CSS assets to your Rails app. If you're doing server rendering, you'll also have a webpack watch process to refresh the server rendering file. **If your server and client bundles are different**, and you run specs, the client bundle files will not be created until React on Rails detects it's out of date. Then your script to create all bundle files will redo the server bundle file. There's a few simple remedies for this situation: + +1. Switch to using static compilation of the webpack bundle files. This way, you're running a Webpack watch process to generate the same files used for tests as well as developmentment. You should have a separate Procfile for doing development using a "static" setup, rather than a "hot" setup. +2. Change your Procfile for starting the hot reloading server to also run a webpack process to automatically rebuild a the client assets while also doing hot reloading for browser testing. + +Note, none of these issues matter if you're using the same file for both server and client side rendering. + +## Using RubyMine and other IDEs that save files right before invoking tests +We had previously tried to allow using a process check to see if a Webpack watch process would already be automatically compiling the files. However, we removed this as it proved to be fragile with various setups. Thus, you want to hit the save keystroke when you save a JavaScript file, and then run your tests. Yes, you might not do this in time, and the test runner may be building the same files as you Webpack watch processes. This will probably happen infrequently, but if this does become an issue, we can look into bring back this functionality ([#398](https://github.com/shakacode/react_on_rails/pull/398)). + If you want to use a testing framework other than RSpec, please submit let us know on the changes you need to do and we'll update the docs. ![2016-01-27_02-36-43](https://cloud.githubusercontent.com/assets/1118459/12611951/7c56d070-c4a4-11e5-8a80-9615f99960d9.png) diff --git a/docs/api/ruby-api-hot-reload-view-helpers.md b/docs/api/ruby-api-hot-reload-view-helpers.md index 12f2a8759..d0c05a1af 100644 --- a/docs/api/ruby-api-hot-reload-view-helpers.md +++ b/docs/api/ruby-api-hot-reload-view-helpers.md @@ -13,7 +13,9 @@ static vs. hot is picked based on whether `ENV["REACT_ON_RAILS_ENV"] == "HOT"` - <%= env_javascript_include_tag(hot: ['http://localhost:3500/webpack-bundle.js') %> + + + <%= env_javascript_include_tag(hot: ['http://localhost:3500/webpack-bundle.js]') %> <%= env_javascript_include_tag(static: 'application_static', diff --git a/lib/generators/USAGE b/lib/generators/USAGE index c44323a39..f66f1a7f7 100644 --- a/lib/generators/USAGE +++ b/lib/generators/USAGE @@ -1,6 +1,7 @@ Description: -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. +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 diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb index e32ca2c0b..fb71add49 100644 --- a/lib/generators/react_on_rails/base_generator.rb +++ b/lib/generators/react_on_rails/base_generator.rb @@ -66,7 +66,8 @@ def copy_base_files base_path = "base/base/" base_files = %w(app/controllers/hello_world_controller.rb client/.babelrc - client/webpack.config.js) + client/webpack.config.js + client/REACT_ON_RAILS_CLIENT_README.md) base_files.each { |file| copy_file(base_path + file, file) } end @@ -92,17 +93,14 @@ def install_node_files end 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 # Add client/assets/ folders to asset pipeline's search path. # 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( webpack-bundle.js ) +# If you have a different server bundle file than your client bundle, you'll +# need to add it here, like this: +# Rails.application.config.assets.precompile += %w( server-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/templates/base/base/.DS_Store b/lib/generators/react_on_rails/templates/base/base/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 1 + # If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering. + config.server_renderer_pool_size = 1 # increase if you're on JRuby + config.server_renderer_timeout = 20 # seconds + + ################################################################################ + # MISCELLANEOUS OPTIONS + ################################################################################ - # Default is false - config.prerender = false - # Default is true for development, off otherwise - config.trace = Rails.env.development? # Default is false, enable if your content security policy doesn't include `style-src: 'unsafe-inline'` config.skip_display_none = false diff --git a/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt b/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt index c0e72aa82..603620c04 100644 --- a/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt +++ b/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt @@ -8,7 +8,9 @@ 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. -const HelloWorldApp = (props) => { +// railsContext provides contextual information especially useful for server rendering, such as +// knowing the locale. See the React on Rails documentation for more info on the railsContext +const HelloWorldApp = (props, _railsContext) => { const store = createStore(props); const reactComponent = ( diff --git a/lib/react_on_rails/configuration.rb b/lib/react_on_rails/configuration.rb index d840e8d1f..25c06d3b9 100644 --- a/lib/react_on_rails/configuration.rb +++ b/lib/react_on_rails/configuration.rb @@ -58,7 +58,8 @@ def self.configuration rendering_extension: nil, server_render_method: "", symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/, - npm_build_test_command: "" + npm_build_test_command: "", + npm_build_production_command: "" ) end @@ -69,6 +70,7 @@ class Configuration :server_renderer_timeout, :raise_on_prerender_error, :skip_display_none, :generated_assets_dirs, :generated_assets_dir, :webpack_generated_files, :rendering_extension, :npm_build_test_command, + :npm_build_production_command, :server_render_method, :symlink_non_digested_assets_regex def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil, @@ -78,11 +80,13 @@ def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil, skip_display_none: nil, generated_assets_dirs: nil, generated_assets_dir: nil, webpack_generated_files: nil, rendering_extension: nil, npm_build_test_command: nil, + npm_build_production_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.npm_build_production_command = npm_build_production_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 d831750ec..1fcb50b17 100644 --- a/lib/react_on_rails/test_helper.rb +++ b/lib/react_on_rails/test_helper.rb @@ -64,8 +64,7 @@ def self.ensure_assets_compiled(webpack_assets_status_checker: nil, webpack_assets_status_checker ||= WebpackAssetsStatusChecker.new(client_dir: client_dir, generated_assets_dir: generated_assets_dir, - webpack_generated_files: webpack_generated_files - ) + webpack_generated_files: webpack_generated_files) unless @printed_once puts 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 b4a4a9d11..80c97cc8f 100644 --- a/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +++ b/lib/react_on_rails/test_helper/ensure_assets_compiled.rb @@ -45,7 +45,7 @@ def puts_start_compile_check_message(stale_files) #{stale_files.join("\n")} React on Rails will ensure your JavaScript generated files are up to date, using your -client level package.json `build:test` command. +/client level package.json `build:test` command. MSG end diff --git a/lib/react_on_rails/version.rb b/lib/react_on_rails/version.rb index 253630b89..bfce13867 100644 --- a/lib/react_on_rails/version.rb +++ b/lib/react_on_rails/version.rb @@ -1,4 +1,4 @@ # frozen_string_literal: true module ReactOnRails - VERSION = "5.2.0".freeze + VERSION = "6.0.0.beta.4".freeze end diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index 112a37d9c..f0f1184bc 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -19,32 +19,26 @@ module ReactOnRails end end -if ReactOnRails.configuration.symlink_non_digested_assets_regex - Rake::Task["assets:precompile"].enhance do - Rake::Task["react_on_rails:assets:symlink_non_digested_assets"].invoke - Rake::Task["react_on_rails:assets:delete_broken_symlinks"].invoke - end -end - namespace :react_on_rails do namespace :assets do - desc "Creates non-digested symlinks for the assets in the public asset dir" task symlink_non_digested_assets: :"assets:environment" do - manifest_path = Dir.glob(ReactOnRails::assets_path.join(".sprockets-manifest-*.json")) + if ReactOnRails.configuration.symlink_non_digested_assets_regex + manifest_path = Dir.glob(ReactOnRails::assets_path.join(".sprockets-manifest-*.json")) .first - manifest_data = JSON.load(File.new(manifest_path)) + manifest_data = JSON.load(File.new(manifest_path)) - manifest_data["assets"].each do |logical_path, digested_path| - regex = ReactOnRails.configuration.symlink_non_digested_assets_regex - if logical_path =~ regex - full_digested_path = ReactOnRails::assets_path.join(digested_path) - full_nondigested_path = ReactOnRails::assets_path.join(logical_path) - extension = full_digested_path.extname - full_digested_gz_path = full_digested_path.sub_ext("#{extension}.gz") - full_nondigested_gz_path = full_nondigested_path.sub_ext("#{extension}.gz") - ReactOnRails::symlink_file(full_digested_path, full_nondigested_path) - ReactOnRails::symlink_file(full_digested_gz_path, full_nondigested_gz_path) + manifest_data["assets"].each do |logical_path, digested_path| + regex = ReactOnRails.configuration.symlink_non_digested_assets_regex + if logical_path =~ regex + full_digested_path = ReactOnRails::assets_path.join(digested_path) + full_nondigested_path = ReactOnRails::assets_path.join(logical_path) + extension = full_digested_path.extname + full_digested_gz_path = full_digested_path.sub_ext("#{extension}.gz") + full_nondigested_gz_path = full_nondigested_path.sub_ext("#{extension}.gz") + ReactOnRails::symlink_file(full_digested_path, full_nondigested_path) + ReactOnRails::symlink_file(full_digested_gz_path, full_nondigested_gz_path) + end end end end @@ -57,7 +51,7 @@ namespace :react_on_rails do target = File.readlink(filename) rescue puts "React on Rails: Warning: your platform doesn't support File::readlink method."/ - "Skipping broken link check." + "Skipping broken link check." return end path = Pathname.new(File.dirname(filename)) @@ -70,6 +64,55 @@ namespace :react_on_rails do end end + # In this task, set prerequisites for the assets:precompile task + desc <<-DESC +Create webpack assets before calling assets:environment +The webpack task must run before assets:environment task. +Otherwise Sprockets cannot find the files that webpack produces. +This is the secret sauce for how a Heroku deployment knows to create the webpack generated JavaScript files. + DESC + task compile_environment: :webpack do + Rake::Task["assets:environment"].invoke + end + + desc <<-DESC +Compile assets with webpack +Uses command defined with ReactOnRails.configuration.npm_build_production_command +sh "cd client && `ReactOnRails.configuration.npm_build_production_command`" + DESC + task webpack: :environment do + if ReactOnRails.configuration.npm_build_production_command.present? + sh "cd client && #{ReactOnRails.configuration.npm_build_production_command}" + end + end + + desc "Delete assets created with webpack, in the generated assetst directory (/app/assets/webpack)" + task clobber: :environment do + dir = Rails.root.join(ReactOnRails.configuration.generated_assets_dir) + if dir.present? && File.directory?(dir) + puts "Deleting files in directory #{dir}" + rm_r Dir.glob(Rails.root.join("#{ReactOnRails.configuration.generated_assets_dir}/*")) + else + puts "Could not find dir #{dir}" + end + end end end +# These tasks run as pre-requisites of assets:precompile. +# Note, it's not possible to refer to ReactOnRails configuration values at this point. +Rake::Task["assets:precompile"] + .clear_prerequisites + .enhance([:environment, + "react_on_rails:assets:compile_environment", + "react_on_rails:assets:symlink_non_digested_assets", + "react_on_rails:assets:delete_broken_symlinks"]) + +# puts "Enhancing assets:precompile with react_on_rails:assets:compile_environment" +# Rake::Task["assets:precompile"] +# .clear_prerequisites +# .enhance([:environment]) do +# Rake::Task["react_on_rails:assets:compile_environment"].invoke +# Rake::Task["react_on_rails:assets:symlink_non_digested_assets"].invoke +# Rake::Task["react_on_rails:assets:delete_broken_symlinks"].invoke +# end diff --git a/package.json b/package.json index a0415bd3d..b7739fee4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-on-rails", - "version": "5.2.0", + "version": "6.0.0-beta.4", "description": "react-on-rails JavaScript for react_on_rails Ruby gem", "main": "node_package/lib/ReactOnRails.js", "directories": { diff --git a/spec/dummy/Gemfile.lock b/spec/dummy/Gemfile.lock index a1f87ef03..1ff365853 100644 --- a/spec/dummy/Gemfile.lock +++ b/spec/dummy/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: ../.. specs: - react_on_rails (5.2.0) + react_on_rails (6.0.0.beta.4) addressable connection_pool execjs (~> 2.5) @@ -56,19 +56,19 @@ GEM binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) builder (3.2.2) - byebug (8.2.2) - capybara (2.6.2) + byebug (8.2.5) + capybara (2.7.1) addressable mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) - capybara-screenshot (1.0.11) + capybara-screenshot (1.0.12) capybara (>= 1.0, < 3) launchy - capybara-webkit (1.8.0) - capybara (>= 2.3.0, < 2.7.0) + capybara-webkit (1.11.1) + capybara (>= 2.3.0, < 2.8.0) json childprocess (0.5.9) ffi (~> 1.0, >= 1.0.11) @@ -84,7 +84,7 @@ GEM coffee-script-source execjs coffee-script-source (1.10.0) - concurrent-ruby (1.0.1) + concurrent-ruby (1.0.2) connection_pool (2.2.0) coveralls (0.8.13) json (~> 1.8) @@ -111,26 +111,28 @@ GEM jbuilder (2.4.1) activesupport (>= 3.0.0, < 5.1) multi_json (~> 1.2) - jquery-rails (4.1.0) - rails-dom-testing (~> 1.0) + jquery-rails (4.1.1) + rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (1.8.3) launchy (2.4.3) addressable (~> 2.3) - libv8 (3.16.14.13) + libv8 (3.16.14.15) loofah (2.0.3) nokogiri (>= 1.5.9) - mail (2.6.3) - mime-types (>= 1.16, < 3) + mail (2.6.4) + mime-types (>= 1.16, < 4) method_source (0.8.2) - mime-types (2.99.1) + mime-types (3.0) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0221) mini_portile2 (2.0.0) minitest (5.8.4) - multi_json (1.11.2) + multi_json (1.12.0) nokogiri (1.6.7.2) mini_portile2 (~> 2.0.0.rc2) - parser (2.3.0.6) + parser (2.3.1.0) ast (~> 2.2) poltergeist (1.9.0) capybara (~> 2.1) @@ -184,11 +186,11 @@ GEM rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.1.0) - rake (10.5.0) + rake (11.1.2) rdoc (4.2.2) json (~> 1.4) ref (2.0.0) - rspec-core (3.4.3) + rspec-core (3.4.4) rspec-support (~> 3.4.0) rspec-expectations (3.4.0) diff-lcs (>= 1.2.0, < 2.0) @@ -205,33 +207,32 @@ GEM rspec-mocks (~> 3.4.0) rspec-support (~> 3.4.0) rspec-support (3.4.1) - rubocop (0.37.2) - parser (>= 2.3.0.4, < 3.0) + rubocop (0.40.0) + parser (>= 2.3.1.0, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) - unicode-display_width (~> 0.3) + unicode-display_width (~> 1.0, >= 1.0.1) ruby-lint (2.1.0) parser (~> 2.2) slop (~> 3.4, >= 3.4.7) - ruby-progressbar (1.7.5) + ruby-progressbar (1.8.0) rubyzip (1.2.0) - sass (3.4.21) + sass (3.4.22) sass-rails (5.0.4) railties (>= 4.0.0, < 5.0) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - scss_lint (0.47.1) - rake (>= 0.9, < 11) + scss_lint (0.48.0) + rake (>= 0.9, < 12) sass (~> 3.4.15) sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) - selenium-webdriver (2.52.0) + selenium-webdriver (2.53.0) childprocess (~> 0.5) - multi_json (~> 1.0) rubyzip (~> 1.0) websocket (~> 1.0) simplecov (0.11.2) @@ -240,8 +241,8 @@ GEM simplecov-html (~> 0.10.0) simplecov-html (0.10.0) slop (3.6.0) - spring (1.6.4) - sprockets (3.5.2) + spring (1.7.1) + sprockets (3.6.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.0.4) @@ -258,20 +259,18 @@ GEM thread_safe (0.3.5) tilt (2.0.2) tins (1.6.0) - turbolinks (5.0.0.beta2) - turbolinks-source - turbolinks-source (5.0.0.beta4) + turbolinks (2.5.3) + coffee-rails tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.7.2) - execjs (>= 0.3.0) - json (>= 1.8.0) - unicode-display_width (0.3.1) + uglifier (3.0.0) + execjs (>= 0.3.0, < 3) + unicode-display_width (1.0.5) web-console (3.1.1) activemodel (>= 4.2) debug_inspector railties (>= 4.2) - websocket (1.2.2) + websocket (1.2.3) websocket-driver (0.6.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -313,9 +312,9 @@ DEPENDENCIES spring sqlite3 therubyracer - turbolinks (~> 5.0.0.beta2) + turbolinks (= 2.5.3) uglifier (>= 2.7.2) web-console BUNDLED WITH - 1.11.2 + 1.12.3 diff --git a/spec/dummy/config/initializers/react_on_rails.rb b/spec/dummy/config/initializers/react_on_rails.rb index 70090820b..6e2e87ec5 100644 --- a/spec/dummy/config/initializers/react_on_rails.rb +++ b/spec/dummy/config/initializers/react_on_rails.rb @@ -13,30 +13,48 @@ def self.custom_context(view_context) # Configure this in your webpack config files. This relative to your Rails root directory. config.generated_assets_dir = File.join(%w(app assets webpack)) - # Define the files for we need to check for webpack compilation when running tests. + # Define the files we need to check for webpack compilation when running tests. config.webpack_generated_files = %w( app-bundle.js vendor-bundle.js server-bundle.js ) - # The server bundle is a single file for all server rendering of components. - # If you are not using server rendering `(prerender: true)`, set this to "". + # This is the file used for server rendering of React when using `(prerender: true)` + # If you are never using server rendering, you may set this to "". + # If you are using the same file for client and server rendering, having this set probably does + # not affect performance. config.server_bundle_js_file = "server-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" + # This configures the script to run to build the production assets by webpack. Set this to nil + # if you don't want react_on_rails building this file for you. + config.npm_build_production_command = "npm run build:production" + ################################################################################ # CLIENT RENDERING OPTIONS # Below options can be overriden by passing options to the react_on_rails # `render_component` view helper method. ################################################################################ - config.prerender = false # default is false - config.trace = Rails.env.development? # default is true for development, off otherwise + # default is false + config.prerender = false + + # default is true for development, off otherwise + config.trace = Rails.env.development? ################################################################################ # SERVER RENDERING OPTIONS ################################################################################ + + # If set to true, this forces Rails to reload the server bundle if it is modified + config.development_mode = Rails.env.development? + # For server rendering. This can be set to false so that server side messages are discarded. - config.replay_console = true # Default is true. Be cautious about turning this off. + # Default is true. Be cautious about turning this off. + config.replay_console = true - config.logging_on_server = true # Default is true. Logs server rendering messags to Rails.logger.info + # Default is true. Logs server rendering messages to Rails.logger.info + config.logging_on_server = true config.raise_on_prerender_error = false # change to true to raise exception on server if the JS code throws @@ -58,4 +76,12 @@ def self.custom_context(view_context) # This allows you to add additional values to the Rails Context. Implement one static method # called `custom_context(view_context)` and return a Hash. config.rendering_extension = RenderingExtension + + # The server render method - either ExecJS or NodeJS + config.server_render_method = "ExecJS" + + # Client js uses assets not digested by rails. + # For any asset matching this regex, non-digested symlink will be created + # To disable symlinks set this parameter to nil. + config.symlink_non_digested_assets_regex = /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/ end 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 c095928e1..87954848b 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 @@ -39,6 +39,7 @@ 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/webpack.config.js client/.babelrc client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx 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 7a9eb664b..4898f4500 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 @@ -29,7 +29,8 @@ def invoke_ensurer_with_doubles ReactOnRails::TestHelper.ensure_assets_compiled( webpack_assets_status_checker: assets_checker, - webpack_assets_compiler: compiler) + webpack_assets_compiler: compiler + ) end def double_assets_checker(args = {})