ember-cli-rails 0.13.0.beta1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89b0e32290ff43666d7f220c5cd91b0ea8fb6a544bd353f6a3f65d9c5daf9823
4
- data.tar.gz: 20d38958d7e6efec4f53dcc36f0af29a00021402cef02247b157481cba158e1f
3
+ metadata.gz: 88933ba7736d53f0cf1f9fc79e6b9997469517188a1b904571222f7e57d15091
4
+ data.tar.gz: fdd038c1e831096567b4bbdef03ed722c40ff11da77e87a29c3059073109d620
5
5
  SHA512:
6
- metadata.gz: 7e46c51bbd566dfdb337227ab884eab7d9a037fb8dc08ba1e4f970694ce0ef02eebe9f777683ef997efb638c0b0dafdad083507491f0831f2e67a4fa8ae4aef1
7
- data.tar.gz: 58a951962724029db87ed4bf969e85bcef65babb964ffedc05a13c5093c0da31cce85a98724b41a38b4116b0b4fc94998d696aadd9da00cfc0c79da2742e1bb5
6
+ metadata.gz: 10ad87d14effd255d9b13ecfd73ed2a26290199ea410d3204280cee51a2e90dd39c9802cf2201787d119fbafd7da10b29fee6d9e2305f6cf67d81b9946e8c0df
7
+ data.tar.gz: e6deabf31ce35858c53174386ffb9ae94cbbbf7a6b2eab5a72cec66deb607040b184c217a124b77ac06ac414d77ec86d6d62198f0fb425119657ca460403d509
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ 0.13.0
2
+ ------
3
+
4
+ * Serve Vite-based applications from Vite's development server in
5
+ `development`, so that changes are hot-reloaded instead of requiring a
6
+ restart. Configure it with the `dev_server` option, or opt out with
7
+ `dev_server: false`
8
+ * Require `ember-cli-rails-assets >= 0.9.0`, which serves the
9
+ `include_ember_script_tags` startup tags from Vite's development server
10
+ when the application is served from it
11
+ * Add an `origin` option to `dev_server`, separating the origin the browser
12
+ loads assets from, from the address the development server binds to — for
13
+ containers, where the server must bind to `0.0.0.0` but browsers refuse
14
+ that address as an origin
15
+
1
16
  0.13.0.beta1
2
17
  ------
3
18
 
data/README.md CHANGED
@@ -81,6 +81,10 @@ c.app :frontend, path: "~/projects/my-ember-app"
81
81
 
82
82
  - `yarn` - enables the [yarn](https://github.com/yarnpkg/yarn) package manager when installing dependencies
83
83
 
84
+ - `dev_server` - configures [Vite's development server](#vite-based-applications)
85
+ for Vite-based applications in `development`. Pass `false` to opt out of it,
86
+ or a Hash of `host`, `port`, and `timeout` settings.
87
+
84
88
  ```ruby
85
89
  EmberCli.configure do |c|
86
90
  c.app :adminpanel # path defaults to `Rails.root.join("adminpanel")`
@@ -176,16 +180,83 @@ suites, configure the `default` task to depend on both `spec` and `ember:test`.
176
180
  task default: [:spec, "ember:test"]
177
181
  ```
178
182
 
179
- **Vite-based applications**
183
+ ### Vite-based applications
180
184
 
181
185
  When Rails is running in development mode, classic (Broccoli-based) Ember
182
186
  applications are built with `ember build --watch`, so changes to the Ember
183
187
  application are picked up automatically.
184
188
 
185
- Vite-based Ember applications (generated with `ember-cli >= 6.8`) are instead
186
- built once, synchronously, when they are first requested. To pick up changes
187
- to the Ember application, restart the Rails server, or iterate on the Ember
188
- application directly with its own development server (`npm start`).
189
+ Vite-based Ember applications (generated with `ember-cli >= 6.8`) are served by
190
+ Vite's own development server instead the same one the application's
191
+ `npm start` script runs. `ember-cli-rails` starts it on the first request,
192
+ waits for it to accept connections, and shuts it down when Rails exits.
193
+
194
+ Rails still renders the application's `index.html`, but reads it from the
195
+ development server rather than from disk. The root-relative URLs in that
196
+ document are rewritten to point at the development server, so the browser
197
+ loads the application's modules — and Vite's HMR client — from it directly.
198
+ Changes to the Ember application are hot-reloaded without reloading the page,
199
+ and without restarting Rails.
200
+
201
+ Assets that the Ember application references relatively (an `<img>` in a
202
+ template, for instance) are still requested from Rails, which proxies them to
203
+ the development server.
204
+
205
+ **Configuring the development server**
206
+
207
+ By default the development server listens on an available port on `127.0.0.1`,
208
+ and `ember-cli-rails` waits up to 30 seconds for it to start:
209
+
210
+ ```rb
211
+ EmberCli.configure do |c|
212
+ c.app :frontend, dev_server: { host: "127.0.0.1", port: 4200, timeout: 60 }
213
+ end
214
+ ```
215
+
216
+ If something is already listening on the configured `host` and `port`,
217
+ `ember-cli-rails` uses it instead of starting a second server. That makes it
218
+ possible to run `npm start` yourself, on a port the initializer names, and have
219
+ Rails serve the application from it.
220
+
221
+ `host` is both the address the development server binds to and — together with
222
+ `port` — the origin the browser loads the application's modules from. When the
223
+ two differ, configure the browser-facing origin separately with `origin`. The
224
+ typical case is Rails running in a container: the development server must bind
225
+ to `0.0.0.0` to be reachable through the container's published port, but
226
+ browsers refuse to connect to `http://0.0.0.0`:
227
+
228
+ ```rb
229
+ EmberCli.configure do |c|
230
+ c.app :frontend, dev_server: {
231
+ host: "0.0.0.0",
232
+ port: 4200,
233
+ origin: "http://localhost:4200",
234
+ }
235
+ end
236
+ ```
237
+
238
+ With `host: "0.0.0.0"`, Rails itself reaches the development server through the
239
+ loopback interface.
240
+
241
+ The development server's output is written to
242
+ `log/ember-<app>.<environment>.log`.
243
+
244
+ **Opting out**
245
+
246
+ To build the application once, synchronously, on the first request instead of
247
+ running a development server, disable it:
248
+
249
+ ```rb
250
+ EmberCli.configure do |c|
251
+ c.app :frontend, dev_server: false
252
+ end
253
+ ```
254
+
255
+ Changes to the Ember application are then only picked up by restarting the
256
+ Rails server.
257
+
258
+ The development server is only used in `development`. `test` and `production`
259
+ are served from the output of `ember build`, as they always have been.
189
260
 
190
261
  ## Deploy
191
262
 
@@ -472,6 +543,17 @@ and `modulepreload` links, and the ES module script tags — extracted from
472
543
  the generated `index.html`. `include_ember_stylesheet_tags` only supports
473
544
  classic (Broccoli-based) applications.
474
545
 
546
+ When the application is served by [Vite's development
547
+ server](#vite-based-applications), `include_ember_script_tags` (from
548
+ [ember-cli-rails-assets]) reads `index.html` from the server and emits the
549
+ startup tags with absolute URLs pointing at it — nothing is built, and changes
550
+ to the application are picked up by reloading the page.
551
+
552
+ With the development server disabled (`dev_server: false`), the helpers read
553
+ the output of `ember build` instead: the application is built once,
554
+ synchronously, on the first request, and changes to it are only picked up by
555
+ restarting the Rails server.
556
+
475
557
  Following the example above, configure the mounted EmberCLI application to be
476
558
  served by a custom controller (`ApplicationController`, in this case).
477
559
 
@@ -627,6 +709,11 @@ make sure it's configured to run a single worker process.
627
709
  Without restricting the server to a single process, [it is possible for multiple
628
710
  EmberCLI runners to clobber each others' work][#94].
629
711
 
712
+ This does not apply to Vite-based applications served by [Vite's development
713
+ server](#vite-based-applications): nothing is written to a shared build
714
+ directory. Give the application a fixed `port` so that the workers share a
715
+ single development server rather than starting one each.
716
+
630
717
  [Puma]: https://github.com/puma/puma
631
718
  [Unicorn]: https://rubygems.org/gems/unicorn
632
719
  [#94]: https://github.com/tricknotes/ember-cli-rails/issues/94#issuecomment-77627453
@@ -689,8 +776,11 @@ Note the following limitations for Vite-based applications:
689
776
  * `include_ember_script_tags` emits the full set of tags the application
690
777
  needs to boot, stylesheets included; `include_ember_stylesheet_tags` is
691
778
  classic-only and must not be called for Vite-based applications
692
- * in development, the application is built synchronously on first request
693
- instead of being rebuilt on file changes
779
+ * in development, the application is served by [Vite's development
780
+ server](#vite-based-applications) rather than out of a build directory. The
781
+ asset helpers serve their tags from the development server too; with
782
+ `dev_server: false` they read the build output, which is built once,
783
+ synchronously, on the first request
694
784
 
695
785
  ## Ruby and Rails support
696
786
 
data/lib/ember_cli/app.rb CHANGED
@@ -2,7 +2,9 @@ require "html_page/renderer"
2
2
  require "ember_cli/path_set"
3
3
  require "ember_cli/shell"
4
4
  require "ember_cli/build_monitor"
5
+ require "ember_cli/deploy/dev_server"
5
6
  require "ember_cli/deploy/file"
7
+ require "ember_cli/dev_server"
6
8
 
7
9
  module EmberCli
8
10
  class App
@@ -49,20 +51,15 @@ module EmberCli
49
51
 
50
52
  def build
51
53
  unless EmberCli.skip?
52
- if development?
53
- if paths.vite?
54
- # The Vite-based blueprint (`ember-cli >= 6.8`) has no
55
- # `ember-cli-rails-addon` to manage the build lock, so build
56
- # synchronously instead of watching for changes.
57
- compile
58
- else
59
- build_and_watch
60
- end
61
- elsif test?
62
- compile
54
+ if dev_server?
55
+ # Vite's own development server rebuilds and hot-reloads the
56
+ # application, so there is nothing to build ahead of time.
57
+ dev_server.start
58
+ else
59
+ build_for_environment
60
+
61
+ @build.wait!
63
62
  end
64
-
65
- @build.wait!
66
63
  end
67
64
  end
68
65
 
@@ -106,6 +103,24 @@ module EmberCli
106
103
  deploy.to_rack
107
104
  end
108
105
 
106
+ def dev_server
107
+ @dev_server ||= DevServer.new(
108
+ name: name,
109
+ paths: paths,
110
+ shell: @shell,
111
+ options: dev_server_options,
112
+ )
113
+ end
114
+
115
+ # Whether this application is served by Vite's development server rather
116
+ # than out of the directory `ember build` writes to.
117
+ def dev_server?
118
+ strategy = deploy_strategy
119
+
120
+ strategy.is_a?(Class) &&
121
+ strategy.ancestors.include?(EmberCli::Deploy::DevServer)
122
+ end
123
+
109
124
  private
110
125
 
111
126
  def development?
@@ -124,12 +139,38 @@ module EmberCli
124
139
  strategy = options.fetch(:deploy, {})
125
140
 
126
141
  if strategy.respond_to?(:fetch)
127
- strategy.fetch(rails_env, EmberCli::Deploy::File)
142
+ strategy.fetch(rails_env) { default_deploy_strategy }
128
143
  else
129
144
  strategy
130
145
  end
131
146
  end
132
147
 
148
+ def default_deploy_strategy
149
+ if development? && paths.vite? && dev_server_enabled?
150
+ EmberCli::Deploy::DevServer
151
+ else
152
+ EmberCli::Deploy::File
153
+ end
154
+ end
155
+
156
+ def dev_server_option
157
+ options.fetch(:dev_server, true)
158
+ end
159
+
160
+ def dev_server_enabled?
161
+ dev_server_option != false
162
+ end
163
+
164
+ def dev_server_options
165
+ option = dev_server_option
166
+
167
+ if option.respond_to?(:fetch)
168
+ option
169
+ else
170
+ {}
171
+ end
172
+ end
173
+
133
174
  def rails_env
134
175
  Rails.env.to_s.to_sym
135
176
  end
@@ -138,6 +179,21 @@ module EmberCli
138
179
  EmberCli.env
139
180
  end
140
181
 
182
+ def build_for_environment
183
+ if development?
184
+ if paths.vite?
185
+ # The Vite-based blueprint (`ember-cli >= 6.8`) has no
186
+ # `ember-cli-rails-addon` to manage the build lock, so build
187
+ # synchronously instead of watching for changes.
188
+ compile
189
+ else
190
+ build_and_watch
191
+ end
192
+ elsif test?
193
+ compile
194
+ end
195
+ end
196
+
141
197
  def build_and_watch
142
198
  prepare
143
199
  @shell.build_and_watch
@@ -17,6 +17,20 @@ module EmberCli
17
17
  ember_build(watch: watch)
18
18
  end
19
19
 
20
+ # Boots Vite's development server for an application generated with the
21
+ # Vite-based blueprint (`ember-cli >= 6.8`). This is what the blueprint's
22
+ # own `npm start` script runs.
23
+ def dev_server(host:, port:)
24
+ line = Terrapin::CommandLine.new(paths.vite, [
25
+ "--host :host",
26
+ "--port :port",
27
+ "--strictPort",
28
+ "--clearScreen false",
29
+ ].join(" "))
30
+
31
+ line.command(host: host.to_s, port: port.to_s)
32
+ end
33
+
20
34
  private
21
35
 
22
36
  attr_reader :options, :paths
@@ -0,0 +1,47 @@
1
+ require "ember_cli/dev_server_proxy"
2
+ require "ember_cli/errors"
3
+
4
+ module EmberCli
5
+ module Deploy
6
+ # Serves an Ember application from its Vite development server instead of
7
+ # from the `dist` directory written by `ember build`.
8
+ #
9
+ # The `index.html` served by the development server refers to its assets
10
+ # (`/@vite/client` included) with root-relative URLs. Rails serves the
11
+ # document from its own origin, so those URLs are rewritten to absolute
12
+ # URLs pointing at the development server. Loading them from there means
13
+ # the Vite client opens its HMR WebSocket against the development server
14
+ # directly, without Rails proxying it.
15
+ class DevServer
16
+ ROOT_RELATIVE_URL = %r{(\s)(src|href)=(["'])/(?!/)}i
17
+
18
+ def initialize(app)
19
+ @app = app
20
+ end
21
+
22
+ def mountable?
23
+ true
24
+ end
25
+
26
+ def to_rack
27
+ DevServerProxy.new(app)
28
+ end
29
+
30
+ def index_html
31
+ rewrite_root_relative_urls(dev_server.index_html)
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :app
37
+
38
+ delegate :dev_server, to: :app
39
+
40
+ def rewrite_root_relative_urls(html)
41
+ html.gsub(ROOT_RELATIVE_URL) do
42
+ "#{$1}#{$2}=#{$3}#{dev_server.origin}/"
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,187 @@
1
+ require "monitor"
2
+ require "net/http"
3
+ require "socket"
4
+ require "uri"
5
+
6
+ require "ember_cli/errors"
7
+
8
+ module EmberCli
9
+ # Manages the Vite development server backing a single Ember application.
10
+ #
11
+ # The server is booted lazily, and the Ember application's `index.html` and
12
+ # assets are read from it over HTTP instead of from the `dist` directory
13
+ # written by `ember build`.
14
+ class DevServer
15
+ DEFAULT_HOST = "127.0.0.1".freeze
16
+ DEFAULT_TIMEOUT = 30
17
+ POLL_INTERVAL = 0.1
18
+ CONNECT_TIMEOUT = 1
19
+
20
+ def initialize(name:, paths:, shell:, options: {})
21
+ @name = name
22
+ @paths = paths
23
+ @shell = shell
24
+ @options = options.respond_to?(:fetch) ? options : {}
25
+ @monitor = Monitor.new
26
+ end
27
+
28
+ def host
29
+ @host ||= option(:host) { DEFAULT_HOST }.to_s
30
+ end
31
+
32
+ def port
33
+ @port ||= option(:port) { available_port }.to_i
34
+ end
35
+
36
+ def timeout
37
+ @timeout ||= option(:timeout) { DEFAULT_TIMEOUT }.to_f
38
+ end
39
+
40
+ # The origin the browser loads the application's assets from. It defaults
41
+ # to the address the development server binds to, but can be configured
42
+ # separately for setups where the two differ — a development server bound
43
+ # to `0.0.0.0` inside a container, reached by the browser through a
44
+ # published port, for instance.
45
+ def origin
46
+ @origin ||= option(:origin) { "http://#{host}:#{port}" }.to_s.chomp("/")
47
+ end
48
+
49
+ # Boots the development server unless something is already listening on
50
+ # its address, and blocks until it accepts connections.
51
+ def start
52
+ return true if listening?
53
+
54
+ # Requests are served concurrently, so make sure only one of them boots
55
+ # the development server.
56
+ monitor.synchronize do
57
+ return true if listening?
58
+
59
+ shell.start_dev_server(host: host, port: port)
60
+
61
+ wait_until_listening!
62
+ end
63
+ end
64
+
65
+ def index_html
66
+ response = get("/")
67
+
68
+ unless response.is_a?(Net::HTTPSuccess)
69
+ fail BuildError.new(<<~MSG)
70
+ #{name.inspect} failed to serve an `index.html` file.
71
+
72
+ #{origin}/ responded with #{response.code} #{response.message}:
73
+
74
+ #{response.body}
75
+ MSG
76
+ end
77
+
78
+ response.body.to_s
79
+ end
80
+
81
+ def get(path, headers = {})
82
+ request(Net::HTTP::Get, path, headers)
83
+ end
84
+
85
+ def head(path, headers = {})
86
+ request(Net::HTTP::Head, path, headers)
87
+ end
88
+
89
+ def options_request(path, headers = {})
90
+ request(Net::HTTP::Options, path, headers)
91
+ end
92
+
93
+ private
94
+
95
+ attr_reader :monitor, :name, :options, :paths, :shell
96
+
97
+ def option(key)
98
+ options.fetch(key) { options.fetch(key.to_s) { yield } }
99
+ end
100
+
101
+ def request(request_class, path, headers)
102
+ start
103
+
104
+ uri = URI.join("http://#{connect_host}:#{port}", path)
105
+ # Pass `nil` as the proxy address so that a `http_proxy` environment
106
+ # variable never routes requests for the local server through a proxy.
107
+ Net::HTTP.start(uri.hostname, uri.port, nil, read_timeout: timeout) do |http|
108
+ http.request(request_class.new(uri, headers))
109
+ end
110
+ rescue SystemCallError, IOError, Timeout::Error => error
111
+ fail BuildError.new(<<~MSG)
112
+ #{name.inspect} could not reach its development server at #{origin}.
113
+
114
+ #{error.class}: #{error.message}
115
+
116
+ Its output is written to #{paths.log}.
117
+ MSG
118
+ end
119
+
120
+ # The address Rails connects to the development server on. `0.0.0.0` asks
121
+ # the server to listen on every interface, but is not an address to
122
+ # connect to, so requests go to the loopback interface instead.
123
+ def connect_host
124
+ if host == "0.0.0.0"
125
+ "127.0.0.1"
126
+ else
127
+ host
128
+ end
129
+ end
130
+
131
+ def listening?
132
+ Socket.tcp(connect_host, port, connect_timeout: CONNECT_TIMEOUT, &:close)
133
+
134
+ true
135
+ rescue SystemCallError, IOError
136
+ false
137
+ end
138
+
139
+ def wait_until_listening!
140
+ deadline = now + timeout
141
+
142
+ loop do
143
+ return true if listening?
144
+
145
+ unless shell.dev_server_running?
146
+ fail BuildError.new(<<~MSG)
147
+ #{name.inspect} failed to start its development server on #{origin}.
148
+
149
+ Its output is written to #{paths.log}.
150
+ MSG
151
+ end
152
+
153
+ if now >= deadline
154
+ fail BuildError.new(<<~MSG)
155
+ #{name.inspect} timed out after #{timeout.round} seconds waiting for
156
+ its development server to listen on #{origin}.
157
+
158
+ Its output is written to #{paths.log}.
159
+
160
+ Configure a longer timeout with:
161
+
162
+ EmberCli.configure do |config|
163
+ config.app #{name.to_sym.inspect}, dev_server: { timeout: 60 }
164
+ end
165
+
166
+ MSG
167
+ end
168
+
169
+ sleep POLL_INTERVAL
170
+ end
171
+ end
172
+
173
+ def now
174
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
175
+ end
176
+
177
+ def available_port
178
+ server = TCPServer.new(host, 0)
179
+
180
+ begin
181
+ server.addr[1]
182
+ ensure
183
+ server.close
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,103 @@
1
+ require "rack"
2
+
3
+ module EmberCli
4
+ # Forwards requests made to an Ember application's mount point to its Vite
5
+ # development server.
6
+ #
7
+ # Assets referenced by the Ember application itself (rather than by its
8
+ # `index.html`) are resolved against the document's URL, so they are
9
+ # requested from Rails. Proxying them keeps those references working the
10
+ # same way they do when the application is served out of `dist`.
11
+ class DevServerProxy
12
+ ALLOWED_VERBS = %w[GET HEAD OPTIONS].freeze
13
+ # Hop-by-hop headers, plus the `Content-Encoding` header describing a body
14
+ # that `Net::HTTP` may have decoded already.
15
+ SKIPPED_HEADERS = %w[
16
+ connection
17
+ content-encoding
18
+ keep-alive
19
+ proxy-authenticate
20
+ proxy-authorization
21
+ te
22
+ trailer
23
+ transfer-encoding
24
+ upgrade
25
+ ].freeze
26
+
27
+ def initialize(app)
28
+ @app = app
29
+ end
30
+
31
+ def call(env)
32
+ request = Rack::Request.new(env)
33
+
34
+ unless ALLOWED_VERBS.include?(request.request_method)
35
+ return method_not_allowed
36
+ end
37
+
38
+ rack_response(proxy(request))
39
+ end
40
+
41
+ private
42
+
43
+ attr_reader :app
44
+
45
+ delegate :dev_server, to: :app
46
+
47
+ def proxy(request)
48
+ path = path_for(request)
49
+ headers = { "accept-encoding" => "identity" }
50
+
51
+ case request.request_method
52
+ when "HEAD" then dev_server.head(path, headers)
53
+ when "OPTIONS" then dev_server.options_request(path, headers)
54
+ else dev_server.get(path, headers)
55
+ end
56
+ end
57
+
58
+ def path_for(request)
59
+ path = request.path_info.presence || "/"
60
+ query = request.query_string
61
+
62
+ if query.present?
63
+ "#{path}?#{query}"
64
+ else
65
+ path
66
+ end
67
+ end
68
+
69
+ def rack_response(response)
70
+ body = response.body.to_s
71
+
72
+ [response.code.to_i, response_headers(response, body), [body]]
73
+ end
74
+
75
+ def response_headers(response, body)
76
+ headers = {}
77
+
78
+ response.each_header do |name, value|
79
+ unless SKIPPED_HEADERS.include?(name.downcase)
80
+ headers[name.downcase] = value
81
+ end
82
+ end
83
+
84
+ headers["content-length"] ||= body.bytesize.to_s
85
+
86
+ headers
87
+ end
88
+
89
+ def method_not_allowed
90
+ body = "Method Not Allowed"
91
+
92
+ [
93
+ 405,
94
+ {
95
+ "allow" => ALLOWED_VERBS.join(", "),
96
+ "content-type" => "text/plain",
97
+ "content-length" => body.bytesize.to_s,
98
+ },
99
+ [body],
100
+ ]
101
+ end
102
+ end
103
+ end
@@ -64,6 +64,24 @@ module EmberCli
64
64
  end
65
65
  end
66
66
 
67
+ def vite
68
+ @vite ||= begin
69
+ root.join("node_modules", ".bin", "vite").tap do |path|
70
+ unless path.executable?
71
+ fail DependencyError.new <<-MSG.strip_heredoc
72
+ No `vite` executable found for `#{app_name}`.
73
+
74
+ Install it:
75
+
76
+ $ cd #{root}
77
+ $ #{package_manager} install
78
+
79
+ MSG
80
+ end
81
+ end
82
+ end
83
+ end
84
+
67
85
  def lockfile
68
86
  @lockfile ||= tmp.join("build.lock")
69
87
  end
@@ -20,16 +20,44 @@ module EmberCli
20
20
  def build_and_watch
21
21
  unless running?
22
22
  lock_buildfile
23
- self.pid = spawn ember.build(watch: true)
23
+ self.pid = spawn(
24
+ ember.build(watch: true),
25
+ err: paths.build_error_file.to_s,
26
+ )
24
27
  detach
25
28
  end
26
29
  end
27
30
 
31
+ def start_dev_server(host:, port:)
32
+ unless dev_server_running?
33
+ # Run the development server in its own process group so that the
34
+ # whole tree can be signaled when Rails exits.
35
+ self.dev_server_pid = spawn(
36
+ ember.dev_server(host: host, port: port),
37
+ out: [paths.log.to_s, "a"],
38
+ err: [:child, :out],
39
+ pgroup: true,
40
+ )
41
+ Process.detach(dev_server_pid)
42
+ end
43
+
44
+ dev_server_pid
45
+ end
46
+
47
+ def dev_server_running?
48
+ process_running?(dev_server_pid)
49
+ end
50
+
28
51
  def stop
29
52
  if pid.present?
30
- Process.kill(:INT, pid)
53
+ signal(pid)
31
54
  self.pid = nil
32
55
  end
56
+
57
+ if dev_server_pid.present?
58
+ signal(-dev_server_pid)
59
+ self.dev_server_pid = nil
60
+ end
33
61
  end
34
62
 
35
63
  def install
@@ -58,7 +86,7 @@ module EmberCli
58
86
 
59
87
  private
60
88
 
61
- attr_accessor :pid
89
+ attr_accessor :dev_server_pid, :pid
62
90
  attr_reader :ember, :env, :options, :paths
63
91
 
64
92
  delegate :run, :run!, to: :runner
@@ -80,15 +108,21 @@ module EmberCli
80
108
  ].select(&:exist?)
81
109
  end
82
110
 
83
- def spawn(command)
111
+ def spawn(command, **redirects)
84
112
  Kernel.spawn(
85
113
  env,
86
114
  command,
87
115
  chdir: paths.root.to_s,
88
- err: paths.build_error_file.to_s,
116
+ **redirects,
89
117
  ) || exit(1)
90
118
  end
91
119
 
120
+ def signal(process_id)
121
+ Process.kill(:INT, process_id)
122
+ rescue Errno::ESRCH, Errno::EPERM
123
+ nil
124
+ end
125
+
92
126
  def runner
93
127
  Runner.new(
94
128
  options: { chdir: paths.root.to_s },
@@ -99,7 +133,11 @@ module EmberCli
99
133
  end
100
134
 
101
135
  def running?
102
- pid.present? && Process.getpgid(pid)
136
+ process_running?(pid)
137
+ end
138
+
139
+ def process_running?(process_id)
140
+ process_id.present? && !!Process.getpgid(process_id)
103
141
  rescue Errno::ESRCH
104
142
  false
105
143
  end
@@ -1,3 +1,3 @@
1
1
  module EmberCli
2
- VERSION = "0.13.0.beta1".freeze
2
+ VERSION = "0.13.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ember-cli-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0.beta1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Pravosud
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.8.0
21
+ version: 0.9.0
22
22
  - - "<"
23
23
  - !ruby/object:Gem::Version
24
24
  version: '1.0'
@@ -28,7 +28,7 @@ dependencies:
28
28
  requirements:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: 0.8.0
31
+ version: 0.9.0
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '1.0'
@@ -117,7 +117,7 @@ dependencies:
117
117
  version: 3.6.0
118
118
  - - "<"
119
119
  - !ruby/object:Gem::Version
120
- version: '7.0'
120
+ version: '9.0'
121
121
  type: :development
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
@@ -127,7 +127,7 @@ dependencies:
127
127
  version: 3.6.0
128
128
  - - "<"
129
129
  - !ruby/object:Gem::Version
130
- version: '7.0'
130
+ version: '9.0'
131
131
  - !ruby/object:Gem::Dependency
132
132
  name: capybara-selenium
133
133
  requirement: !ruby/object:Gem::Requirement
@@ -177,7 +177,10 @@ files:
177
177
  - lib/ember_cli/build_monitor.rb
178
178
  - lib/ember_cli/command.rb
179
179
  - lib/ember_cli/configuration.rb
180
+ - lib/ember_cli/deploy/dev_server.rb
180
181
  - lib/ember_cli/deploy/file.rb
182
+ - lib/ember_cli/dev_server.rb
183
+ - lib/ember_cli/dev_server_proxy.rb
181
184
  - lib/ember_cli/ember_constraint.rb
182
185
  - lib/ember_cli/engine.rb
183
186
  - lib/ember_cli/errors.rb
@@ -214,7 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
217
  - !ruby/object:Gem::Version
215
218
  version: '0'
216
219
  requirements: []
217
- rubygems_version: 4.0.16
220
+ rubygems_version: 4.0.20
218
221
  specification_version: 4
219
222
  summary: Integration between Ember CLI and Rails
220
223
  test_files: []