Skip to content

Commit

Permalink
Support React on Rails by merging Webpacker Lite
Browse files Browse the repository at this point in the history
See #594

From a long discussion on #464, this issue will summarize. I'll soon be
posting proposed changes to the README.md.

Summary of changes

* Move base url out from manifest.json to manifest.rb
* Assign env variables to dev server settings so it can be overridden at
  runtime.
* The keys for dev_server should use same format as of now as documented
  in Paths on the README.md. Note that
* hot is a new setting to indicate that the dev_server is used with hot
  reloading, which means that CSS should be inlined to be hot loaded.
  The presence of dev_server means that the webpack-dev-server is used for
  the given env.

development:
  // put the created files to the /public/webpack/development directory
  public_output_path: webpack/development

 //# if dev_server is not provided, then dev_server is not used
 dev_server:
   hot: true # This is a new setting
   static: false
   host: localhost
   https: false
  • Loading branch information
justin808 committed Jul 31, 2017
1 parent 265a54d commit e782dc3
Show file tree
Hide file tree
Showing 18 changed files with 424 additions and 54 deletions.
10 changes: 10 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ gem "rubocop", ">= 0.47", require: false
group :test do
gem "minitest", "~> 5.0"
end

if ENV["USE_PRY"]
gem "awesome_print"
gem "pry"
gem "pry-byebug"
gem "pry-doc"
gem "pry-rails"
gem "pry-rescue"
gem "pry-stack_explorer"
end
36 changes: 35 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,19 @@ GEM
tzinfo (~> 1.1)
arel (7.1.4)
ast (2.3.0)
awesome_print (1.8.0)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
builder (3.2.3)
byebug (9.0.6)
coderay (1.1.1)
concurrent-ruby (1.0.5)
debug_inspector (0.0.3)
erubis (2.7.0)
globalid (0.3.7)
activesupport (>= 4.1.0)
i18n (0.8.1)
interception (0.5)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.4)
Expand All @@ -71,6 +78,24 @@ GEM
parser (2.4.0.0)
ast (~> 2.2)
powerpack (0.1.1)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-byebug (3.4.2)
byebug (~> 9.0)
pry (~> 0.10)
pry-doc (0.10.0)
pry (~> 0.9)
yard (~> 0.9)
pry-rails (0.3.6)
pry (>= 0.10.4)
pry-rescue (1.4.5)
interception (>= 0.5)
pry
pry-stack_explorer (0.4.9.2)
binding_of_caller (>= 0.7)
pry (>= 0.9.11)
rack (2.0.1)
rack-test (0.6.3)
rack (>= 1.0)
Expand Down Expand Up @@ -106,6 +131,7 @@ GEM
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.1)
slop (3.6.0)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
Expand All @@ -121,17 +147,25 @@ GEM
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
yard (0.9.9)

PLATFORMS
ruby

DEPENDENCIES
awesome_print
bundler (~> 1.12)
minitest (~> 5.0)
pry
pry-byebug
pry-doc
pry-rails
pry-rescue
pry-stack_explorer
rails
rake (>= 11.1)
rubocop (>= 0.47)
webpacker!

BUNDLED WITH
1.14.6
1.15.3
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,14 @@ development:
host: 0.0.0.0
port: 8080
https: false
hot: false
```

If you have hot turned to `true`, then the `stylesheet_pack_tag` generates no output, as you will want
to configure your styles to be inlined in your JavaScript for hot reloading. During production and testing, the
`stylesheet_pack_tag` will create the appropriate HTML tags.


#### Resolved Paths

If you are adding webpacker to an existing app that has most of the assets inside
Expand Down Expand Up @@ -601,8 +607,12 @@ and

#### React

You may consider using [react-rails](https://github.com/reactjs/react-rails) or
[webpacker-react](https://github.com/renchap/webpacker-react) for more advanced react integration. However here is how you can do it yourself:
The most widely used React integration is [shakacode/react_on_rails](https://github.com/shakacode/react_on_rails) which includes support for server rendering, redux and react-router.

Other alternatives include [react-rails](https://github.com/reactjs/react-rails) and
[webpacker-react](https://github.com/renchap/webpacker-react) for more advanced react integration.

If you're not concerned with view helpers to pass props or server rendering, can do it yourself:

```erb
<%# views/layouts/application.html.erb %>
Expand Down Expand Up @@ -1103,6 +1113,8 @@ git push heroku master
Webpacker lazily compiles assets in test env so you can write your tests without any extra
setup and everything will just work out of the box.

Note, [React on Rails] users should set configuration value `compile` to false, as React on Rails
handle compilation for test and production environments.

Here is a sample system test case with hello_react example component:

Expand Down
4 changes: 1 addition & 3 deletions lib/install/config/webpack/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ module.exports = {

output: {
filename: '[name].js',
path: output.path,
publicPath: output.publicPath
path: output.path
},

module: {
Expand All @@ -39,7 +38,6 @@ module.exports = {
new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css'),
new ManifestPlugin({
publicPath: output.publicPath,
writeToFileEmit: true
})
],
Expand Down
1 change: 1 addition & 0 deletions lib/install/config/webpacker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ development:
host: localhost
port: 8080
https: false
hot: false

test:
<<: *default
Expand Down
10 changes: 6 additions & 4 deletions lib/webpacker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ module Webpacker
extend self

def bootstrap
Webpacker::Env.load
Webpacker::Configuration.load
Webpacker::Manifest.load
Webpacker::Env.load_instance
Webpacker::Configuration.load_instance
Webpacker::DevServer.load_instance
Webpacker::Manifest.load_instance
end

def compile
Webpacker::Compiler.compile
Webpacker::Manifest.load
Webpacker::Manifest.load_instance
end

def env
Expand All @@ -19,6 +20,7 @@ def env

require "webpacker/env"
require "webpacker/configuration"
require "webpacker/dev_server"
require "webpacker/manifest"
require "webpacker/compiler"
require "webpacker/railtie" if defined?(Rails)
30 changes: 25 additions & 5 deletions lib/webpacker/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@

class Webpacker::Configuration < Webpacker::FileLoader
class << self
def reset
@defaults = nil
super
end

def entry_path
source_path.join(fetch(:source_entry_path))
end

def public_output_path
fetch(:public_output_path)
end

def output_path
public_path.join(fetch(:public_output_path))
public_path.join(public_output_path)
end

def manifest_path
Expand Down Expand Up @@ -45,19 +54,30 @@ def fetch(key)
end

def data
load if Webpacker.env.development?
raise Webpacker::FileLoader::FileLoaderError.new("Webpacker::Configuration.load must be called first") unless instance
load_instance if Webpacker.env.development?
raise Webpacker::FileLoader::FileLoaderError.new("Webpacker::Configuration.load_data must be called first") unless instance
instance.data
end

def defaults
@defaults ||= HashWithIndifferentAccess.new(YAML.load(default_file_path.read)[Webpacker.env])
end

# Uses the webpack dev server host if appropriate
def output_path_or_url
if Webpacker::DevServer.dev_server?
Webpacker::DevServer.base_url
else
# Ensure we start with a slash so that the asset helpers don't prepend the default asset
# pipeline locations.
public_output_path.starts_with?("/") ? public_output_path : "/#{public_output_path}"
end
end
end

private
def load
return super unless File.exist?(@path)
def load_data
return Webpacker::Configuration.defaults unless File.exist?(@path)
HashWithIndifferentAccess.new(YAML.load(File.read(@path))[Webpacker.env])
end
end
78 changes: 78 additions & 0 deletions lib/webpacker/dev_server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Same convention as manifest/configuration.rb

# Loads webpacker configuration from config/webpacker.yml

require "webpacker/configuration"

class Webpacker::DevServer < Webpacker::FileLoader
class << self
def dev_server?
!dev_server_values.nil?
end

# read settings for dev_server
def hot?
return false unless dev_server?
if ENV["WEBPACKER_HMR"].present?
val = ENV["WEBPACKER_HMR"].downcase
return true if val == "true"
return false if val == "false"
raise new ArgumentError("WEBPACKER_HMR value is #{ENV['WEBPACKER_HMR']}. Set to TRUE|FALSE")
end
fetch(:hot)
end

def host
fetch(:host)
end

def port
fetch(:port)
end

def https?
fetch(:https)
end

def protocol
https? ? "https" : "http"
end

def file_path
Webpacker::Configuration.file_path
end

# Uses the hot_reloading_host if appropriate
def base_url
"#{protocol}://#{host}:#{port}"
end

private

def dev_server_values
data.fetch(:dev_server, nil)
end

def fetch(key)
return nil unless dev_server?
dev_server_values.fetch(key, dev_server_defaults[key])
end

def data
load_instance if Webpacker.env.development?
unless instance
raise Webpacker::FileLoader::FileLoaderError.new("Webpacker::DevServer.load_data must be called first")
end
instance.data
end

def dev_server_defaults
@defaults ||= Webpacker::Configuration.defaults[:dev_server]
end
end

private
def load_data
Webpacker::Configuration.instance.data
end
end
2 changes: 1 addition & 1 deletion lib/webpacker/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def file_path
end

private
def load
def load_data
environments = File.exist?(@path) ? YAML.load(File.read(@path)).keys : [].freeze
return ENV["NODE_ENV"] if environments.include?(ENV["NODE_ENV"])
return Rails.env if environments.include?(Rails.env)
Expand Down
31 changes: 27 additions & 4 deletions lib/webpacker/file_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,44 @@ class NotFoundError < StandardError; end
class FileLoaderError < StandardError; end

class_attribute :instance
attr_accessor :data
attr_accessor :data, :mtime, :path

class << self
def load(path = file_path)
def load_instance(path = file_path)
# Assume production is 100% cached and don't reload if file's mtime not changed
cached = self.instance && # if we have a singleton
(env == "production" || # skip if production bc always cached
(File.exist?(path) && self.instance.mtime == File.mtime(path))) # skip if mtime not changed

return if cached
self.instance = new(path)
end

def file_path
raise FileLoaderError.new("Subclass of Webpacker::FileLoader should override this method")
end

def reset
self.instance = nil
load_instance
end

private

# Prefer the NODE_ENV to the rails env.
def env
ENV["NODE_ENV"].presence || Rails.env
end
end

private
def initialize(path)
@path = path
@data = load
@mtime = File.exist?(path) ? File.mtime(path) : nil
@data = load_data
end

def load
def load_data
{}.freeze
end
end
Loading

0 comments on commit e782dc3

Please sign in to comment.