Skip to content

Commit

Permalink
Fix testing issues with Rails hot reloading setup
Browse files Browse the repository at this point in the history
Configured testing so that:
* If we're not running a webpack process to watch the client JS files,
  then we build the client or server files.
* Test will let you know if it's skipping building.

Expression used to see if a watch process is running:
`pgrep -fl '\\-w \\-\\-config webpack\\.#{type}\\.rails\\.build\\.config\\.js'`

* Renamed asset helpers so usage is like this:

  <%= env_stylesheet_link_tag 'application_prod', 'application_dev', media: 'all', 'data-turbolinks-track' => true  %>
  <%= env_javascript_include_tag nil, 'http://localhost:3500/vendor-bundle.js' %>
  <%= env_javascript_include_tag nil, 'http://localhost:3500/app-bundle.js' %>
  <%= env_javascript_include_tag 'application_prod', 'application_dev', 'data-turbolinks-track' => true %>

TODO: Should we consider having tests use the Rails hot reload server?
  • Loading branch information
justin808 committed Dec 13, 2015
1 parent 5396a79 commit 410bac6
Show file tree
Hide file tree
Showing 19 changed files with 103 additions and 30 deletions.
7 changes: 7 additions & 0 deletions Procfile.dev
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
web: rails s

# Run the hot reload server for client development
client: sh -c 'rm app/assets/webpack/* || true && cd client && HOT_RAILS_PORT=3500 npm run build:dev:client'

# Keep the JS fresh for specs
client-spec: sh -c 'cd client && npm run build:test:client'

# Keep the JS fresh for server rendering
server: sh -c 'cd client && npm run build:dev:server'
hot: sh -c 'cd client && HOT_PORT=4000 npm start'
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,14 @@ Note that it's important to run the Rails server on a different port than the no

# Webpack configuration
## Config Files

- `webpack.client.base.config.js`: Common configuration file to minimize code duplication for client.rails and client.hot.
- `webpack.client.rails.config.js`: Used to generate the Rails bundles for Rails use.
- `webpack.client.hot.config.js`: Used by server.js to run the Webpack Dev server.
- `webpack.server.rails.config.js`: Common configuration file to minimize code duplication
between the HMR and Rails configurations.
- `webpack.client.rails.build.config.js`: Client side js bundle.
- `webpack.server.rails.build.config.js`: Server side js bundle

These are used for hot reloading (Webpack Dev Server):
- `webpack.client.rails.hot.config.js`: Used to generate the Rails bundles for Rails use so you get hot reloading within your Rails app.
- `webpack.client.hot.config.js`: Used by server.js to run the Webpack Dev server for stubbing the api end points

## Webpack Resources
- Good overview: [Pete Hunt's Webpack Howto](https://github.com/petehunt/webpack-howto)
Expand Down
1 change: 1 addition & 0 deletions app/assets/javascripts/application_dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// This one depend on jQuery
//= require turbolinks

// This will soon be removed as it will be in vendor-bundle with react_on_rails 2.0
//= require react_on_rails

//= require rails_startup
11 changes: 7 additions & 4 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
module ApplicationHelper
def javascript_include_env_tag(asset, dev_asset, params = {})
asset_file = Rails.env.production? ? asset : dev_asset
# TODO: MOVE TO helper in react_on_rails
# See application.html.erb for usage example
def env_javascript_include_tag(prod_asset, dev_asset, params = {})
asset_file = !Rails.env.development? ? prod_asset : dev_asset
return javascript_include_tag(asset_file, params) if asset_file
end

def stylesheet_link_env_tag(asset, dev_asset, params = {})
asset_file = Rails.env.production? ? asset : dev_asset
# TODO: MOVE TO helper in react_on_rails
def env_stylesheet_link_tag(prod_asset, dev_asset, params = {})
asset_file = !Rails.env.development? ? prod_asset : dev_asset
return stylesheet_link_tag(asset_file, params) if asset_file
end
end
4 changes: 2 additions & 2 deletions app/views/comments/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<div class="comment">
<p id="notice"><%= notice %></p>

<p>
<p class="js-comment-author">
<strong>Author:</strong>
<%= @comment.author %>
</p>

<p>
<p class="js-comment-text">
<strong>Text:</strong>
<%= @comment.text %>
</p>
Expand Down
8 changes: 4 additions & 4 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
<html>
<head>
<title>RailsReactTutorial</title>
<%= stylesheet_link_env_tag 'application_prod', 'application_dev', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_env_tag nil, 'http://localhost:3500/vendor-bundle.js' %>
<%= javascript_include_env_tag nil, 'http://localhost:3500/app-bundle.js' %>
<%= javascript_include_env_tag 'application_prod', 'application_dev', 'data-turbolinks-track' => true %>
<%= env_stylesheet_link_tag 'application_prod', 'application_dev', media: 'all', 'data-turbolinks-track' => true %>
<%= env_javascript_include_tag nil, 'http://localhost:3500/vendor-bundle.js' %>
<%= env_javascript_include_tag nil, 'http://localhost:3500/app-bundle.js' %>
<%= env_javascript_include_tag 'application_prod', 'application_dev', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
Expand Down
2 changes: 1 addition & 1 deletion app/views/pages/no_router.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
<%= render "header" %>
<%= react_component('App', render(template: "/comments/index.json.jbuilder"),
generator_function: true, prerender: true) %>
generator_function: true, prerender: false) %>
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export default class Comment extends React.Component {

return (
<div className={css.comment}>
<h2 className={css.commentAuthor}>
<h2 className={`${css.commentAuthor} js-comment-author`}>
{author}
</h2>
<span
dangerouslySetInnerHTML={{ __html: rawMarkup }}
className="comment-text"
className="js-comment-text"
/>
</div>
);
Expand Down
5 changes: 3 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
"test:debug": "npm run test -- --debug-brk",
"start": "node server.js",
"build:client": "NODE_ENV=production webpack --config webpack.client.rails.build.config.js",
"build:server": "NODE_ENV=production webpack --config webpack.server.rails.config.js",
"build:server": "NODE_ENV=production webpack --config webpack.server.rails.build.config.js",
"build:dev:client": "babel-node server.rails.hot.js",
"build:dev:server": "webpack -w --config webpack.server.rails.config.js",
"build:dev:server": "webpack -w --config webpack.server.rails.build.config.js",
"build:test:client": "webpack -w --config webpack.client.rails.build.config.js",
"lint": "npm run eslint && npm run jscs",
"eslint": "eslint --ext .js,.jsx .",
"jscs": "jscs --verbose ."
Expand Down
1 change: 1 addition & 0 deletions client/webpack.client.base.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ module.exports = {
// 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-ujs'), loader: 'imports?jQuery=jquery' },
{ test: require.resolve('jquery'), loader: 'expose?jQuery' },
{ test: require.resolve('jquery'), loader: 'expose?$' },

Expand Down
File renamed without changes.
3 changes: 0 additions & 3 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ class Application < Rails::Application
# config.i18n.load_path += Dir[Rails.root.join("my", "locales", "*.{rb,yml}").to_s]
# config.i18n.default_locale = :de

# Add folder with webpack generated assets to assets.paths
config.assets.paths << Rails.root.join("app", "assets", "webpack")

# For not swallow errors in after_commit/after_rollback callbacks.
config.active_record.raise_in_transactional_callbacks = true
end
Expand Down
9 changes: 6 additions & 3 deletions config/initializers/assets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = "1.0"

# Add additional assets to the asset load path
# Rails.application.config.assets.paths << Emoji.images_path
# Add folder with webpack generated assets to assets.paths
Rails.application.config.assets.paths << Rails.root.join("app", "assets", "webpack")

# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
Rails.application.config.assets.precompile += %w( application_*.* )
Rails.application.config.assets.precompile += %w(
application_*.*
server-bundle.js
)
10 changes: 10 additions & 0 deletions docs/testing-deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Testing

1. `rake` runs the test suite
2. To test production with precompiled assets:

```sh
export SECRET_KEY_BASE=`rake secret`
alias test-prod='rake assets:clobber && RAILS_ENV=production bin/rake assets:precompile \
&& rails s -e production'
```
10 changes: 8 additions & 2 deletions lib/tasks/assets.rake
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,16 @@ namespace :assets do
task :webpack do
sh "cd client && npm run build:client"
sh "cd client && npm run build:server"
sh "mkdir -p public/assets"

# Critical to manually copy non js/css assets to public/assets as we don't want to fingerprint them
sh "cp -rf app/assets/webpack/*.woff* app/assets/webpack/*.svg app/assets/webpack/*.ttf "\
"app/assets/webpack/*.eot* public/assets"

# TODO: We should be gzipping these
end

task :clobber do
rm_rf "#{Rails.application.config.root}/app/assets/javascripts/generated/client-bundle.js"
rm_rf "#{Rails.application.config.root}/app/assets/javascripts/generated/server-bundle.js"
rm_rf "#{Rails.application.config.root}/app/assets/webpack"
end
end
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@
"postinstall": "cd client && npm install",
"test": "rspec && npm run test:client && npm run lint",
"test:client": "(cd client && npm run test --silent)",
"lint": "(cd client && npm run lint --silent)"
"lint": "(cd client && npm run lint --silent)",
"build:clean": "rm app/assets/webpack/*",
"build:client": "(cd client && npm run build:client --silent)",
"build:server": "(cd client && npm run build:server --silent)",
"build:dev:client": "(cd client && npm run build:dev:client --silent)",
"build:dev:server": "(cd client && npm run build:dev:server --silent)",
"build:test:client": "(cd client && npm run build:test:client --silent)"
},
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions spec/features/shared/examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
include_context "Form Submitted", name: :name, text: :text

scenario "comment is added" do
expect(page).to have_css(".comment", text: name)
expect(page).to have_css(".comment", text: text)
expect(page).to have_css(".js-comment-author", text: name)
expect(page).to have_css(".js-comment-text", text: text)
end
end

Expand Down
3 changes: 3 additions & 0 deletions spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with :truncation

# Next line will ensure that assets are built if webpack -w is not running
EnsureAssetsCompiled.check_built_assets
end

config.around(:each) do |example|
Expand Down
32 changes: 32 additions & 0 deletions spec/support/ensure_assets_compiled.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# TODO: Move to react_on_rails
class EnsureAssetsCompiled
def self.check_built_assets
return if @checked_built_assets
build_all_assets
end

def self.running_webpack_watch?(type)
running = `pgrep -fl '\\-w \\-\\-config webpack\\.#{type}\\.rails\\.build\\.config\\.js'`
if running.present?
puts "Found process, so skipping rebuild => #{running.ai}"
return true
end
end

def self.build_assets_for_type(type)
unless running_webpack_watch?(type)
build_output = `cd client && npm run build:#{type}`
if build_output =~ /error/i
fail "Error in building assets!\n#{build_output}"
else
puts "Webpack build completed."
end
end
end

def self.build_all_assets
build_assets_for_type("client")
build_assets_for_type("server")
@checked_built_assets = true
end
end

0 comments on commit 410bac6

Please sign in to comment.