ember-cli-rails 0.12.3 → 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 +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +128 -2
- data/lib/ember_cli/app.rb +70 -7
- data/lib/ember_cli/command.rb +14 -0
- data/lib/ember_cli/deploy/dev_server.rb +47 -0
- data/lib/ember_cli/dev_server.rb +187 -0
- data/lib/ember_cli/dev_server_proxy.rb +103 -0
- data/lib/ember_cli/path_set.rb +25 -0
- data/lib/ember_cli/shell.rb +44 -6
- data/lib/ember_cli/version.rb +1 -1
- metadata +9 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 88933ba7736d53f0cf1f9fc79e6b9997469517188a1b904571222f7e57d15091
|
|
4
|
+
data.tar.gz: fdd038c1e831096567b4bbdef03ed722c40ff11da77e87a29c3059073109d620
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10ad87d14effd255d9b13ecfd73ed2a26290199ea410d3204280cee51a2e90dd39c9802cf2201787d119fbafd7da10b29fee6d9e2305f6cf67d81b9946e8c0df
|
|
7
|
+
data.tar.gz: e6deabf31ce35858c53174386ffb9ae94cbbbf7a6b2eab5a72cec66deb607040b184c217a124b77ac06ac414d77ec86d6d62198f0fb425119657ca460403d509
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
0.13.0
|
|
2
2
|
------
|
|
3
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
|
+
|
|
16
|
+
0.13.0.beta1
|
|
17
|
+
------
|
|
18
|
+
|
|
19
|
+
* Support Ember applications generated with the Vite-based blueprint
|
|
20
|
+
(`ember-cli >= 6.8`), without `ember-cli-rails-addon`
|
|
21
|
+
* Require `ember-cli-rails-assets >= 0.8.0`, which adds Vite support to
|
|
22
|
+
`include_ember_script_tags`
|
|
23
|
+
|
|
4
24
|
0.12.3
|
|
5
25
|
------
|
|
6
26
|
|
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")`
|
|
@@ -90,7 +94,8 @@ EmberCli.configure do |c|
|
|
|
90
94
|
end
|
|
91
95
|
```
|
|
92
96
|
|
|
93
|
-
Next,
|
|
97
|
+
Next, if your Ember application uses the classic (Broccoli-based) build
|
|
98
|
+
(generated with `ember-cli < 6.8`), install the [ember-cli-rails-addon][addon]:
|
|
94
99
|
|
|
95
100
|
```bash
|
|
96
101
|
$ cd path/to/frontend
|
|
@@ -111,6 +116,10 @@ For instance, if you're using the `0.6.x` version of the gem, specify
|
|
|
111
116
|
}
|
|
112
117
|
```
|
|
113
118
|
|
|
119
|
+
If your Ember application uses the Vite-based build (generated with
|
|
120
|
+
`ember-cli >= 6.8`), do **not** install the addon: it is incompatible with the
|
|
121
|
+
Vite-based build, and `ember-cli-rails` does not require it there.
|
|
122
|
+
|
|
114
123
|
[addon]: https://github.com/rondale-sc/ember-cli-rails-addon/
|
|
115
124
|
[semver]: http://semver.org/
|
|
116
125
|
|
|
@@ -171,6 +180,84 @@ suites, configure the `default` task to depend on both `spec` and `ember:test`.
|
|
|
171
180
|
task default: [:spec, "ember:test"]
|
|
172
181
|
```
|
|
173
182
|
|
|
183
|
+
### Vite-based applications
|
|
184
|
+
|
|
185
|
+
When Rails is running in development mode, classic (Broccoli-based) Ember
|
|
186
|
+
applications are built with `ember build --watch`, so changes to the Ember
|
|
187
|
+
application are picked up automatically.
|
|
188
|
+
|
|
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.
|
|
260
|
+
|
|
174
261
|
## Deploy
|
|
175
262
|
|
|
176
263
|
When Rails is running in production mode, EmberCLI-Rails stops doing runtime
|
|
@@ -449,6 +536,24 @@ actively supported method of serving EmberCLI applications.
|
|
|
449
536
|
However, for the sake of backwards compatibility, `ember-cli-rails` supports
|
|
450
537
|
injecting the EmberCLI-generated assets into an existing Rails layout.
|
|
451
538
|
|
|
539
|
+
**Note:** for Vite-based applications (generated with `ember-cli >= 6.8`),
|
|
540
|
+
use `include_ember_script_tags` on its own. It emits everything the
|
|
541
|
+
application needs to boot — the configuration `<meta>` tag, the stylesheet
|
|
542
|
+
and `modulepreload` links, and the ES module script tags — extracted from
|
|
543
|
+
the generated `index.html`. `include_ember_stylesheet_tags` only supports
|
|
544
|
+
classic (Broccoli-based) applications.
|
|
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
|
+
|
|
452
557
|
Following the example above, configure the mounted EmberCLI application to be
|
|
453
558
|
served by a custom controller (`ApplicationController`, in this case).
|
|
454
559
|
|
|
@@ -604,6 +709,11 @@ make sure it's configured to run a single worker process.
|
|
|
604
709
|
Without restricting the server to a single process, [it is possible for multiple
|
|
605
710
|
EmberCLI runners to clobber each others' work][#94].
|
|
606
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
|
+
|
|
607
717
|
[Puma]: https://github.com/puma/puma
|
|
608
718
|
[Unicorn]: https://rubygems.org/gems/unicorn
|
|
609
719
|
[#94]: https://github.com/tricknotes/ember-cli-rails/issues/94#issuecomment-77627453
|
|
@@ -654,7 +764,23 @@ if (environment === 'development') {
|
|
|
654
764
|
|
|
655
765
|
This project supports:
|
|
656
766
|
|
|
657
|
-
* EmberCLI versions `>= 1.13.13`
|
|
767
|
+
* EmberCLI versions `>= 1.13.13` using the classic (Broccoli-based) build,
|
|
768
|
+
together with [ember-cli-rails-addon][addon]
|
|
769
|
+
* EmberCLI versions `>= 6.8` using the Vite-based build, without the addon
|
|
770
|
+
|
|
771
|
+
The test suite currently exercises the `5.12.x` and `6.7.x` (classic) and
|
|
772
|
+
`7.0.x` (Vite) series.
|
|
773
|
+
|
|
774
|
+
Note the following limitations for Vite-based applications:
|
|
775
|
+
|
|
776
|
+
* `include_ember_script_tags` emits the full set of tags the application
|
|
777
|
+
needs to boot, stylesheets included; `include_ember_stylesheet_tags` is
|
|
778
|
+
classic-only and must not be called for Vite-based applications
|
|
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
|
|
658
784
|
|
|
659
785
|
## Ruby and Rails support
|
|
660
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,13 +51,15 @@ module EmberCli
|
|
|
49
51
|
|
|
50
52
|
def build
|
|
51
53
|
unless EmberCli.skip?
|
|
52
|
-
if
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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!
|
|
56
62
|
end
|
|
57
|
-
|
|
58
|
-
@build.wait!
|
|
59
63
|
end
|
|
60
64
|
end
|
|
61
65
|
|
|
@@ -99,6 +103,24 @@ module EmberCli
|
|
|
99
103
|
deploy.to_rack
|
|
100
104
|
end
|
|
101
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
|
+
|
|
102
124
|
private
|
|
103
125
|
|
|
104
126
|
def development?
|
|
@@ -117,12 +139,38 @@ module EmberCli
|
|
|
117
139
|
strategy = options.fetch(:deploy, {})
|
|
118
140
|
|
|
119
141
|
if strategy.respond_to?(:fetch)
|
|
120
|
-
strategy.fetch(rails_env
|
|
142
|
+
strategy.fetch(rails_env) { default_deploy_strategy }
|
|
121
143
|
else
|
|
122
144
|
strategy
|
|
123
145
|
end
|
|
124
146
|
end
|
|
125
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
|
+
|
|
126
174
|
def rails_env
|
|
127
175
|
Rails.env.to_s.to_sym
|
|
128
176
|
end
|
|
@@ -131,6 +179,21 @@ module EmberCli
|
|
|
131
179
|
EmberCli.env
|
|
132
180
|
end
|
|
133
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
|
+
|
|
134
197
|
def build_and_watch
|
|
135
198
|
prepare
|
|
136
199
|
@shell.build_and_watch
|
data/lib/ember_cli/command.rb
CHANGED
|
@@ -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
|
data/lib/ember_cli/path_set.rb
CHANGED
|
@@ -39,6 +39,13 @@ module EmberCli
|
|
|
39
39
|
root.join("bower.json")
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
# Apps generated with the Vite-based blueprint (`ember-cli >= 6.8`)
|
|
43
|
+
# ship a Vite config file at their root.
|
|
44
|
+
def vite?
|
|
45
|
+
%w[vite.config.mjs vite.config.js vite.config.ts].
|
|
46
|
+
any? { |config| root.join(config).exist? }
|
|
47
|
+
end
|
|
48
|
+
|
|
42
49
|
def ember
|
|
43
50
|
@ember ||= begin
|
|
44
51
|
root.join("node_modules", "ember-cli", "bin", "ember").tap do |path|
|
|
@@ -57,6 +64,24 @@ module EmberCli
|
|
|
57
64
|
end
|
|
58
65
|
end
|
|
59
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
|
+
|
|
60
85
|
def lockfile
|
|
61
86
|
@lockfile ||= tmp.join("build.lock")
|
|
62
87
|
end
|
data/lib/ember_cli/shell.rb
CHANGED
|
@@ -20,16 +20,44 @@ module EmberCli
|
|
|
20
20
|
def build_and_watch
|
|
21
21
|
unless running?
|
|
22
22
|
lock_buildfile
|
|
23
|
-
self.pid = spawn
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
data/lib/ember_cli/version.rb
CHANGED
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.
|
|
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.
|
|
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.
|
|
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: '
|
|
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: '
|
|
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.
|
|
220
|
+
rubygems_version: 4.0.20
|
|
218
221
|
specification_version: 4
|
|
219
222
|
summary: Integration between Ember CLI and Rails
|
|
220
223
|
test_files: []
|