Skip to content

Commit 68b9f08

Browse files
gauravtiwariDavid Heinemeier Hansson
authored andcommitted
Add dev server config class and setup proxy (#637)
* Add rack proxy Add options for ssl and set publicPath to only pack output path * Setup dev_server class Add dev_server config * Add and mount the dev_server proxy Move dev-server to defaults * Add tests Move to private Fix paths Update path names * Update changelog * Update changelog Fix typos Delete if path exists * Fix test env and update tests * Only add proxy in development Remove extra if * Nix extra CR * Move skipping compile on manifest lookups when dev server is running to manifest * Give proxy middleware its own initializer * Rely on @javan's fix instead of changing all these * Remove needless local variable * Fix compile predicate check * Nix dealing with HTTPS in development * Only proxy to dev server if its running * Better grouping * Nix need for config to return anything but full paths * Supply host_with_port * Only needed to delete this for HTTPS * Rare occurrence to run dev server in production Don't need to advertise that so loudly. * Not needed * Not needed * Not needed * Update documentation to our new proxy approach * Fix rubocop offenses
1 parent acd81f5 commit 68b9f08

18 files changed

+144
-48
lines changed

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,31 @@
1313
- `Webpacker::Compiler.fresh?` and `Webpacker::Compiler.stale?` answer the question of whether compilation is needed.
1414
The old `Webpacker::Compiler.compile?` predicate is deprecated.
1515

16+
- Dev server config class that exposes config options through singleton.
17+
18+
```rb
19+
Webpacker.dev_server.running?
20+
```
21+
22+
- Rack middleware proxies webpacker requests to dev server so we can always serve from same-origin and the lookup works out of the box - no more paths prefixing
23+
24+
### Breaking changes
25+
26+
**Note:** requires running `bundle exec rails webpacker:install` and update webpacker.yml
27+
28+
- Move dev-server config options under defaults so it's transparently available in all environments
29+
30+
31+
### Removed
32+
33+
- Host info from manifest.json, now looks like this:
34+
35+
```json
36+
{
37+
"hello_react.js": "/packs/hello_react.js"
38+
}
39+
```
40+
1641
### Fixed
1742

1843
- Update `webpack-dev-server.tt` to respect RAILS_ENV and NODE_ENV values [#502](https://github.com/rails/webpacker/issues/502)

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ gemspec
55
gem "rails"
66
gem "rake", ">= 11.1"
77
gem "rubocop", ">= 0.49", require: false
8+
gem "rack-proxy", require: false
89

910
group :test do
1011
gem "minitest", "~> 5.0"

Gemfile.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ PATH
33
specs:
44
webpacker (2.0)
55
activesupport (>= 4.2)
6+
rack-proxy (>= 0.6.1)
67
railties (>= 4.2)
78

89
GEM
@@ -72,6 +73,8 @@ GEM
7273
ast (~> 2.2)
7374
powerpack (0.1.1)
7475
rack (2.0.1)
76+
rack-proxy (0.6.1)
77+
rack
7578
rack-test (0.6.3)
7679
rack (>= 1.0)
7780
rails (5.0.1)
@@ -131,6 +134,7 @@ DEPENDENCIES
131134
bundler (~> 1.12)
132135
byebug
133136
minitest (~> 5.0)
137+
rack-proxy
134138
rails
135139
rake (>= 11.1)
136140
rubocop (>= 0.49)

README.md

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -246,40 +246,13 @@ happens when you refer to any of the pack assets using the Webpacker helper meth
246246
That means you don't have to run any separate process. Compilation errors are logged
247247
to the standard Rails log.
248248

249-
If you want to use live code reloading, you'll need to run `./bin/webpack-dev-server`
249+
If you want to use live code reloading, or you have enough JavaScript that on-demand compilation is too slow, you'll need to run `./bin/webpack-dev-server`
250250
in a separate terminal from `./bin/rails server`. This process will watch for changes
251251
in the `app/javascript/packs/*.js` files and automatically reload the browser to match.
252252

253-
Note: The dev server serves pack files from `http://localhost:8080/` by default, which
254-
is a different origin than your application server. Therefore it's not compatible with
255-
things like Service Workers, that requires you to serve from the same origin.
256-
257-
If you'd rather not have to run the two processes separately by hand, you can use [Foreman](https://ddollar.github.io/foreman):
258-
259-
```bash
260-
gem install foreman
261-
```
262-
263-
```yml
264-
# Procfile
265-
web: bundle exec rails s
266-
webpacker: ./bin/webpack-dev-server
267-
```
268-
269-
```bash
270-
foreman start
271-
```
272-
273-
By default, `webpack-dev-server` listens on `0.0.0.0` that means listening
274-
on all IP addresses available on your system: LAN IP address, localhost, 127.0.0.1 etc.
275-
However, we use `localhost` as default hostname for serving assets in browser
276-
and if you want to change that, for example on cloud9 you can do so
277-
by changing host set in `config/webpacker.yml`.
278-
279-
```bash
280-
dev_server:
281-
host: example.com
282-
```
253+
Once you start this development server, Webpacker will automatically start proxying all
254+
webpack asset requests to this server. When you stop the server, it'll revert to
255+
on-demand compilation again.
283256

284257
You can also pass CLI options supported by [webpack-dev-server](https://webpack.js.org/configuration/dev-server/). Please note that inline options will always take
285258
precedence over the ones already set in the configuration file.

lib/install/bin/webpack-dev-server.tt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ begin
2828

2929
HOSTNAME = args('--host') || dev_server["host"]
3030
PORT = args('--port') || dev_server["port"]
31-
HTTPS = ARGV.include?('--https') || dev_server["https"]
32-
DEV_SERVER_ADDR = "http#{"s" if HTTPS}://#{HOSTNAME}:#{PORT}"
31+
DEV_SERVER_ADDR = "http://#{HOSTNAME}:#{PORT}"
3332

3433
rescue Errno::ENOENT, NoMethodError
3534
$stdout.puts "Webpack dev_server configuration not found in #{CONFIG_FILE}."

lib/install/config/loaders/core/assets.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ module.exports = {
55
use: [{
66
loader: 'file-loader',
77
options: {
8-
publicPath: output.publicPath,
8+
// Set publicPath with ASSET_HOST env if available so internal assets can use CDN
9+
publicPath: output.publicPathWithHost,
910
name: env.NODE_ENV === 'production' ? '[name]-[hash].[ext]' : '[name].[ext]'
1011
}
1112
}]

lib/install/config/webpack/configuration.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ function formatPublicPath(host = '', path = '') {
2424

2525
const output = {
2626
path: resolve('public', settings.public_output_path),
27-
publicPath: formatPublicPath(env.ASSET_HOST, settings.public_output_path)
27+
publicPath: `/${settings.public_output_path}/`.replace(/([^:]\/)\/+/g, '$1'),
28+
publicPathWithHost: formatPublicPath(env.ASSET_HOST, settings.public_output_path)
2829
}
2930

3031
let resolvedModules = [

lib/install/config/webpack/development.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ module.exports = merge(sharedConfig, {
1313

1414
devServer: {
1515
clientLogLevel: 'none',
16-
https: settings.dev_server.https,
1716
host: settings.dev_server.host,
1817
port: settings.dev_server.port,
1918
contentBase: output.path,

lib/install/config/webpacker.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ default: &default
1010
# ['app/assets', 'engine/foo/app/assets']
1111
resolved_paths: []
1212

13+
# webpack-dev-server configuration
14+
dev_server: &dev_server
15+
host: localhost
16+
port: 3035
17+
1318
extensions:
1419
- .coffee
1520
- .erb
@@ -29,10 +34,6 @@ default: &default
2934
development:
3035
<<: *default
3136
compile: true
32-
dev_server:
33-
host: localhost
34-
port: 8080
35-
https: false
3637

3738
test:
3839
<<: *default

lib/webpacker.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def instance
1414
end
1515

1616
delegate :logger, :logger=, :env, to: :instance
17-
delegate :config, :compiler, :manifest, :commands, to: :instance
17+
delegate :config, :compiler, :manifest, :commands, :dev_server, to: :instance
1818
delegate :bootstrap, :clobber, :compile, to: :commands
1919
end
2020

@@ -23,5 +23,6 @@ def instance
2323
require "webpacker/manifest"
2424
require "webpacker/compiler"
2525
require "webpacker/commands"
26+
require "webpacker/dev_server"
2627

2728
require "webpacker/railtie" if defined?(Rails)

lib/webpacker/configuration.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ def refresh
99
@data = load
1010
end
1111

12+
def dev_server
13+
fetch(:dev_server)
14+
end
15+
16+
def compile?
17+
fetch(:compile)
18+
end
19+
1220
def source_path
1321
root_path.join(fetch(:source_path))
1422
end
@@ -33,10 +41,6 @@ def cache_path
3341
root_path.join(fetch(:cache_path))
3442
end
3543

36-
def compile?
37-
fetch(:compile)
38-
end
39-
4044
private
4145
def fetch(key)
4246
data.fetch(key, defaults[key])

lib/webpacker/dev_server.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
class Webpacker::DevServer
2+
delegate :config, to: :@webpacker
3+
4+
def initialize(webpacker)
5+
@webpacker = webpacker
6+
end
7+
8+
def running?
9+
Socket.tcp(host, port, connect_timeout: 1).close
10+
true
11+
rescue Errno::ECONNREFUSED, NoMethodError
12+
false
13+
end
14+
15+
def host
16+
fetch(:host)
17+
end
18+
19+
def port
20+
fetch(:port)
21+
end
22+
23+
def host_with_port
24+
"#{host}:#{port}"
25+
end
26+
27+
private
28+
def fetch(key)
29+
config.dev_server.fetch(key, defaults[key])
30+
end
31+
32+
def defaults
33+
config.send(:defaults)[:dev_server]
34+
end
35+
end

lib/webpacker/dev_server_proxy.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
require "rack/proxy"
2+
3+
class Webpacker::DevServerProxy < Rack::Proxy
4+
def rewrite_response(response)
5+
status, headers, body = response
6+
headers.delete "transfer-encoding"
7+
response
8+
end
9+
10+
def perform_request(env)
11+
if env["PATH_INFO"] =~ /#{public_output_uri_path}/ && Webpacker.dev_server.running?
12+
env["HTTP_HOST"] = Webpacker.dev_server.host_with_port
13+
super(env)
14+
else
15+
@app.call(env)
16+
end
17+
end
18+
19+
private
20+
def public_output_uri_path
21+
Webpacker.config.public_output_path.relative_path_from(Webpacker.config.public_path)
22+
end
23+
end

lib/webpacker/instance.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def compiler
2121
@compiler ||= Webpacker::Compiler.new self
2222
end
2323

24+
def dev_server
25+
@dev_server ||= Webpacker::DevServer.new self
26+
end
27+
2428
def manifest
2529
@manifest ||= Webpacker::Manifest.new self
2630
end

lib/webpacker/manifest.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class Webpacker::Manifest
1313
class MissingEntryError < StandardError; end
1414

15-
delegate :config, :compiler, :env, to: :@webpacker
15+
delegate :config, :compiler, :env, :dev_server, to: :@webpacker
1616

1717
def initialize(webpacker)
1818
@webpacker = webpacker
@@ -23,13 +23,17 @@ def refresh
2323
end
2424

2525
def lookup(name)
26-
compile
26+
compile if compiling?
2727
find name
2828
end
2929

3030
private
31+
def compiling?
32+
config.compile? && !dev_server.running?
33+
end
34+
3135
def compile
32-
Webpacker.logger.tagged("Webpacker") { compiler.compile } if config.compile?
36+
Webpacker.logger.tagged("Webpacker") { compiler.compile }
3337
end
3438

3539
def find(name)

lib/webpacker/railtie.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
require "rails/railtie"
22

33
require "webpacker/helper"
4+
require "webpacker/dev_server_proxy"
45

56
class Webpacker::Engine < ::Rails::Engine
7+
initializer "webpacker.proxy" do |app|
8+
if Rails.env.development?
9+
app.middleware.insert_before 0,
10+
Rails::VERSION::MAJOR >= 5 ?
11+
Webpacker::DevServerProxy : "Webpacker::DevServerProxy"
12+
end
13+
end
14+
615
initializer "webpacker.helper" do |app|
716
ActiveSupport.on_load :action_controller do
817
ActionController::Base.helper Webpacker::Helper

test/dev_server_test.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require "webpacker_test_helper"
2+
3+
class DevServerTest < Minitest::Test
4+
def test_host
5+
assert_equal "localhost", Webpacker.dev_server.host
6+
end
7+
8+
def test_port
9+
assert_equal Webpacker.dev_server.port, 3035
10+
end
11+
end

webpacker.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
1414

1515
s.add_dependency "activesupport", ">= 4.2"
1616
s.add_dependency "railties", ">= 4.2"
17+
s.add_dependency "rack-proxy", ">= 0.6.1"
1718

1819
s.add_development_dependency "bundler", "~> 1.12"
1920

0 commit comments

Comments
 (0)