├── .github ├── ISSUE_TEMPLATE.md └── workflows │ └── tests.yml ├── .gitignore ├── .rspec ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── RELEASING.md ├── Rakefile ├── SECURITY.md ├── UPGRADING.md ├── app ├── controller │ └── ember_cli │ │ └── ember_controller.rb ├── helpers │ └── ember_rails_helper.rb └── views │ └── ember_cli │ └── ember │ └── index.html.erb ├── bin ├── clean ├── rake ├── rspec ├── setup └── setup_ember ├── ember-cli-rails.gemspec ├── lib ├── ember-cli-rails.rb ├── ember_cli.rb ├── ember_cli │ ├── app.rb │ ├── build_monitor.rb │ ├── command.rb │ ├── configuration.rb │ ├── deploy │ │ └── file.rb │ ├── ember_constraint.rb │ ├── engine.rb │ ├── errors.rb │ ├── helpers.rb │ ├── path_set.rb │ ├── route_helpers.rb │ ├── runner.rb │ ├── shell.rb │ ├── trailing_slash_constraint.rb │ └── version.rb ├── generators │ └── ember │ │ ├── heroku │ │ ├── USAGE │ │ ├── heroku_generator.rb │ │ └── templates │ │ │ ├── package.json.erb │ │ │ └── yarn.lock.erb │ │ └── init │ │ ├── USAGE │ │ ├── init_generator.rb │ │ └── templates │ │ └── initializer.rb └── tasks │ └── ember-cli.rake └── spec ├── dummy ├── .gitignore ├── Rakefile ├── app │ ├── controllers │ │ └── application_controller.rb │ └── views │ │ ├── layouts │ │ └── application.html.erb │ │ └── pages │ │ ├── embedded.html.erb │ │ ├── include_index.html.erb │ │ ├── include_index_empty_block.html.erb │ │ └── include_index_head_and_body.html.erb ├── application.rb ├── config │ ├── initializers │ │ ├── ember.rb │ │ └── high_voltage.rb │ └── routes.rb └── public │ └── favicon.ico ├── features └── user_views_ember_app_spec.rb ├── fixtures ├── application.hbs └── logo.png ├── generators └── ember │ └── heroku │ └── heroku_generator_spec.rb ├── lib ├── ember-cli-rails_spec.rb ├── ember_cli │ ├── app_spec.rb │ ├── build_monitor_spec.rb │ ├── command_spec.rb │ ├── deploy │ │ └── file_spec.rb │ ├── ember_constraint_spec.rb │ ├── helpers_spec.rb │ ├── path_set_spec.rb │ └── runner_spec.rb └── ember_cli_spec.rb ├── requests └── assets │ └── my-app.js_spec.rb ├── spec_helper.rb └── support └── capybara.rb /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Which operating system and version is the project developed on?** 2 | 3 | **Which version of [`ruby`](https://www.ruby-lang.org/) is the project developed on?** 4 | 5 | **Which version of [`npm`](https://www.npmjs.com/) is the project developed on?** 6 | 7 | **Which version of [`ember-cli`](http://ember-cli.com/) is the project developed on?** 8 | 9 | **What is the [`rails`](https://github.com/rails/rails) version?** 10 | 11 | **What is the [`ember-cli-rails`](https://github.com/tricknotes/ember-cli-rails) version (from `Gemfile`)?** 12 | 13 | **What is the [`ember-cli-rails-addon`](https://github.com/rondale-sc/ember-cli-rails-addon/) version (from `package.json`)?** 14 | 15 | **Is your application server [multi-threaded](https://github.com/tricknotes/ember-cli-rails/commit/ef0a49546a8c2e5fb0a298ba455fba97289065a1) 16 | (such as `puma` and `unicorn`) or is it multi-process (such as thin and webrick)?** 17 | 18 | **What are the contents of `config/initializers/ember.rb`?** 19 | 20 | **What are the contents of the Rails' view that renders the Ember application?** 21 | 22 | **How are the EmberCLI-related routes defined?** 23 | 24 | **How is the application deployed?** 25 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: "CI Tests" 2 | 3 | on: 4 | push: 5 | branches: "main" 6 | pull_request: 7 | branches: "*" 8 | 9 | jobs: 10 | build: 11 | runs-on: "ubuntu-latest" 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | ruby: ["3.2", "3.3"] 17 | rails: ["7.0", "7.1", "7.2"] 18 | include: 19 | - ruby: "3.3" 20 | rails: "8.0" 21 | - ruby: "3.4" 22 | rails: "8.0" 23 | - ruby: "3.4" 24 | rails: "main" 25 | 26 | env: 27 | RAILS_ENV: "test" 28 | RAILS_VERSION: "${{ matrix.rails }}" 29 | 30 | steps: 31 | - uses: "actions/checkout@v4" 32 | 33 | - name: "Install NodeJS" 34 | uses: "actions/setup-node@v4" 35 | with: 36 | node-version: "20.x" 37 | 38 | - name: "Install Ruby ${{ matrix.ruby }}" 39 | uses: "ruby/setup-ruby@v1" 40 | with: 41 | ruby-version: "${{ matrix.ruby }}" 42 | bundler-cache: true 43 | 44 | - name: "Install Webdriver" 45 | run: | 46 | sudo apt-get update 47 | sudo apt-get -yqq install chromium-browser 48 | 49 | - name: "Run Setup" 50 | run: | 51 | bin/setup 52 | 53 | - name: "Run Tests" 54 | run: | 55 | bin/rake 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | *.gemfile.lock 15 | mkmf.log 16 | /log/ 17 | spec/dummy/my-app/ 18 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | main 2 | ------ 3 | 4 | 0.12.2 5 | ------ 6 | 7 | * Support Rack 3 and depend on Rack explicitly (#607) 8 | 9 | 0.12.1 10 | ------ 11 | 12 | * Drop explicit dependency to rexml (#602) 13 | * Remove note for PhantomJS (#604) 14 | * Allow rspec-rails 6.x (#603) 15 | * Allow ember-cli-rails-assets < 1.0 (#599) 16 | * Update webdrivers gem (#600) 17 | * Disallow rack 3 to be compatible with capybara (#601) 18 | 19 | 0.12.0 20 | ------ 21 | 22 | * Redirecting with trailing slash with query parameters 23 | * Recognize Building notice as not an error 24 | * Use keyword argument for options 25 | * Add Ruby 2.7 & 3.0 into CI matrix 26 | * Add missing gems that removed from stdlibs in Ruby 3.0.0 27 | * Fix autoload deprecation in Rails 6 28 | * Drop support for Rails versions 4.2, 5.0, 5.1, and 5.2 29 | * Drop support for End-of-Lifed Ruby versions 2.3 and 2.4 30 | 31 | 0.11.0 32 | ------ 33 | 34 | * Switch from TravisCI to GitHub Actions for Continuous Integration 35 | * Redirect Ember routes with paths that don't end in `/` to corresponding paths 36 | that end in `/`. 37 | * Don't route requests to `/rails/active_storage` through the mounted Ember application. 38 | * Only support for Ruby versions >= 2.5 39 | * Only support for Rails versions >= 5.2 40 | 41 | 0.10.0 42 | ------ 43 | 44 | * Remove `bin/heroku_install` to simplify Heroku setup. 45 | To upgrade, remove your project's generated `bin/heroku_install`. 46 | Next, execute `rake ember:heroku`. [#544] 47 | * Generate an empty `yarn.lock` so that Heroku understands that the 48 | application's deployment target requires `yarn`. Closes [#538]. [#540] 49 | * No longer support `rails < 4.2`. [#543] 50 | * Generate an empty `yarn.lock` so that Heroku understands that the 51 | application's deployment target requires `yarn`. Closes [#538]. [#540] 52 | 53 | [#543]: https://github.com/thoughtbot/ember-cli-rails/pull/543 54 | [#544]: https://github.com/thoughtbot/ember-cli-rails/pull/544 55 | [#538]: https://github.com/thoughtbot/ember-cli-rails/issues/538 56 | [#540]: https://github.com/thoughtbot/ember-cli-rails/pull/540 57 | 58 | 0.9.0 59 | ----- 60 | 61 | * Don't require `bower` installation if `bower.json` is missing [#532] 62 | 63 | [#532]: https://github.com/thoughtbot/ember-cli-rails/pull/532 64 | 65 | 0.8.7 66 | ----- 67 | 68 | * Revert [`34ff6dd`][reverted-commit] so that it can be reintroduced as a 69 | breaking change, [requiring a major version bump][#532-comment] 70 | 71 | [reverted-commit]: https://github.com/thoughtbot/ember-cli-rails/commit/34ff6dd 72 | [#532-comment]: https://github.com/thoughtbot/ember-cli-rails/pull/532#issuecomment-308141408 73 | 74 | 0.8.6 75 | ----- 76 | 77 | * Don't require `bower` installation if `bower.json` is missing [#532] 78 | 79 | [#532]: https://github.com/thoughtbot/ember-cli-rails/pull/532 80 | 81 | 0.8.5 82 | ----- 83 | 84 | * Ignore calls to `/rails/mailers`. [#520] 85 | * Call `render` with `html:` instead of `text:`. [#519] 86 | * Use `Mime::Type.html?` [#523] 87 | 88 | [#520]: https://github.com/thoughtbot/ember-cli-rails/pull/520 89 | [#519]: https://github.com/thoughtbot/ember-cli-rails/pull/519 90 | [#523]: https://github.com/thoughtbot/ember-cli-rails/pull/523 91 | 92 | 0.8.4 93 | ----- 94 | 95 | * Execute `bin/heroku_install` through `sh` [#512] 96 | * Generate `package.json` with `bower` as a `dependencies` value. 97 | 98 | [#512]: https://github.com/thoughtbot/ember-cli-rails/pull/512 99 | 100 | 0.8.3 101 | ----- 102 | 103 | * Add support for integrating with `yarn`. [#496] 104 | 105 | [#496]: https://github.com/thoughtbot/ember-cli-rails/pull/496 106 | 107 | 0.8.2. 108 | ------ 109 | 110 | * Support Rails 5 static file serving configuration. [#499] 111 | 112 | [#499]: https://github.com/thoughtbot/ember-cli-rails/pull/499 113 | 114 | 0.8.1 115 | ----- 116 | 117 | * Resolve issues inheriting from `ActionController::API`. [#481] 118 | 119 | [#481]: https://github.com/thoughtbot/ember-cli-rails/pull/481 120 | 121 | 0.8.0 122 | ----- 123 | 124 | * `EmberCli::EmberController` no longer assumes `ApplicationController` 125 | inherits from`ActionController::Base`. [#400] 126 | * Remove support for Ruby 2.1.x. [#400] 127 | * Don't route requests to `/rails/info` through the mounted Ember application. 128 | 129 | [#400]: https://github.com/thoughtbot/ember-cli-rails/pull/400 130 | 131 | 0.7.4 132 | ----- 133 | 134 | * Fix dependencies check for compile command. [#455] 135 | * Introduce the `silent` configuration value. [#445] 136 | 137 | [#455]: https://github.com/thoughtbot/ember-cli-rails/pull/455 138 | [#445]: https://github.com/thoughtbot/ember-cli-rails/pull/445 139 | 140 | 0.7.3 141 | ----- 142 | 143 | * Stream output instead of waiting until subprocesses finish. [#423] 144 | * Update `ember-cli-rails-assets` dependency. [#422] 145 | * Only write errors to `STDERR`. [#421] 146 | * Remove dependency on `tee`. Fixes bug [#417]. [#420] 147 | 148 | [#423]: https://github.com/thoughtbot/ember-cli-rails/pull/423 149 | [#422]: https://github.com/thoughtbot/ember-cli-rails/pull/422 150 | [#421]: https://github.com/thoughtbot/ember-cli-rails/issues/421 151 | [#420]: https://github.com/thoughtbot/ember-cli-rails/issues/420 152 | [#417]: https://github.com/thoughtbot/ember-cli-rails/issues/417 153 | 154 | 0.7.2 155 | ----- 156 | 157 | * Enhance `rake ember:install` to fully reinstall if necessary. [#396] 158 | * `EmberCli::Deploy::File` serves assets with Rails' `static_cache_control` 159 | value. [#403] 160 | 161 | [#400]: https://github.com/thoughtbot/ember-cli-rails/pull/400 162 | [#396]: https://github.com/thoughtbot/ember-cli-rails/pull/396 163 | [#403]: https://github.com/thoughtbot/ember-cli-rails/pull/403 164 | 165 | 0.7.1 166 | ----- 167 | 168 | * Resolve `ember` executable with full path within `node_modules`, instead of 169 | depending on the presence of `node_modules/.bin`. [#395] 170 | * Introduce the idea of `App#mountable?` and `App#to_rack` for handling deploys 171 | that don't serve assets from the file system (Redis, for example). 172 | * Fix bug with generated `bin/heroku_install` script iterating through multiple 173 | * Don't mount route helpers at top-level. Instead, mount within the surrounding 174 | context with which they're invoked. [#381] 175 | 176 | [#395]: https://github.com/thoughtbot/ember-cli-rails/pull/395 177 | [#381]: https://github.com/thoughtbot/ember-cli-rails/pull/381 178 | 179 | 0.7.0 180 | ----- 181 | 182 | * Introduce the `deploy` configuration option. 183 | * Translate Rails environments other than `test` or `development` to 184 | `production`, unless an `EMBER_ENV` is specified. [#366] 185 | 186 | [#366]: https://github.com/thoughtbot/ember-cli-rails/pull/366 187 | 188 | 0.6.1 189 | ----- 190 | 191 | * Extract `include_ember_*_tags` and the associated code to the 192 | `ember-cli-rails-assets` gem. Add `ember-cli-rails-assets` as a dependency. 193 | [#363] 194 | * Introduce `mount_ember_assets` to serve Ember assets in asset-helper style 195 | projects. 196 | 197 | [#363]: https://github.com/thoughtbot/ember-cli-rails/pull/363 198 | 199 | 0.6.0 200 | ----- 201 | 202 | * Use system-level `tee` to pipe `STDOUT` to both `STDOUT` and the logs. [#351] 203 | * Invoke `EmberCli[ember_app].build` from helpers to ensure everything is built 204 | before serving. [#347] 205 | * Remove dependency on `sprockets`. Serve generated files with `Rack::File`. 206 | [#336] 207 | * Rename generator namespace from `ember-cli` to `ember`. [#344] 208 | * Ensure `Rails.root.join("log")` exists when writing to logs. 209 | * Remove deprecated `include_ember_index_html` helper and deprecated 210 | `build_timeout` and `enabled` configurations. [#334] 211 | * Raise build errors for `render_ember_app` failures. [#325] 212 | * Remove `before_{action,filter}` in favor of explicit `EmberCli.build(app)` 213 | call. [#327] 214 | 215 | [#351]: https://github.com/thoughtbot/ember-cli-rails/pull/351 216 | [#347]: https://github.com/thoughtbot/ember-cli-rails/pull/347 217 | [#336]: https://github.com/thoughtbot/ember-cli-rails/pull/336 218 | [#344]: https://github.com/thoughtbot/ember-cli-rails/pull/344 219 | [#334]: https://github.com/thoughtbot/ember-cli-rails/pull/334 220 | [#327]: https://github.com/thoughtbot/ember-cli-rails/pull/327 221 | [#325]: https://github.com/thoughtbot/ember-cli-rails/pull/325 222 | 223 | 0.5.8 224 | ----- 225 | 226 | * Ensure cleanup method can destroy temporary folders. [#330] 227 | 228 | [#330]: https://github.com/thoughtbot/ember-cli-rails/pull/330 229 | 230 | 0.5.7 231 | ----- 232 | 233 | * Improve command failure reporting. [#324] 234 | * Use latest EmberCLI-generated asset files. [#316] 235 | * Delete previous build output on application boot instead of on process exit. 236 | [#308] 237 | 238 | [#324]: https://github.com/thoughtbot/ember-cli-rails/pull/324 239 | [#316]: https://github.com/thoughtbot/ember-cli-rails/pull/316 240 | [#308]: https://github.com/thoughtbot/ember-cli-rails/pull/308 241 | 242 | 0.5.6 243 | ----- 244 | 245 | * Fallback to `before_filter` for Rails 3.2. [#306] 246 | * No longer depend on `tee` executable. Use `Kernel#{spawn,system}` with 247 | redirection options. [#299] 248 | 249 | [#306]: https://github.com/thoughtbot/ember-cli-rails/pull/306 250 | [#299]: https://github.com/thoughtbot/ember-cli-rails/pull/299 251 | 252 | 0.5.5 253 | ----- 254 | 255 | * Expose `EmberCli::App#root` for Heroku generator. Fixes [#295]. [#296] 256 | 257 | [#295]: https://github.com/thoughtbot/ember-cli-rails/issues/295 258 | [#296]: https://github.com/thoughtbot/ember-cli-rails/pull/296 259 | 260 | 0.5.4 261 | ----- 262 | 263 | * Escape generated CLI strings. Adds support for paths with spaces. 264 | 265 | 0.5.3 266 | ----- 267 | 268 | * No longer redirect `STDERR` to `STDOUT` when executing `ember` commands. This 269 | fixes some JRuby bugs. [#288] 270 | * Don't `prune` in generated Heroku setup script. [#286] 271 | 272 | [#288]: https://github.com/thoughtbot/ember-cli-rails/pull/288 273 | [#286]: https://github.com/thoughtbot/ember-cli-rails/pull/286 274 | 275 | 0.5.2 276 | ----- 277 | 278 | * Register EmberCLI app with Sprockets on application initialization 279 | * Rename `ember-cli` to `ember_cli` in Ruby. 280 | 281 | 0.5.1 282 | ----- 283 | 284 | * Invoke `EmberCli::App#compile` in `test` environment, spawn `build` process in 285 | development, rely on `rake assets:precompile` in `production`-like 286 | environments. 287 | 288 | 0.5.0 289 | ----- 290 | 291 | * Deprecate `include_ember_index_html` in favor of the renamed 292 | `render_ember_app`. 293 | * Always pass `--environment test` to Rails-generated `ember test` commands. 294 | [#277] 295 | * No longer check dependencies within the app. Defer to EmberCLI's `stderr` 296 | streaming. [#267] 297 | * Remove `enable` configuration in favor of using `mount_ember_app`. [#261] 298 | * Introduce `mount_ember_app` route helper [#263] 299 | * Remove support for viewing Ember tests through Rails. Instead, use `ember 300 | test` or `ember test --serve` from within the Ember directory. [#264] 301 | * Remove `build_timeout` configuration [#259] 302 | * Disable JS minification when generating Heroku setup [#238] 303 | * `BuildError#message` includes first line of backtrace. [#256] 304 | * Symlink `dist/` directly to Asset Pipeline [#250] 305 | * Merge EmberCLI-generated `manifest.json` into Sprocket's [#250] 306 | * `manifest.json`. Since we now defer to EmberCLI, we no longer need to 307 | manually resolve asset URLs. [#250] 308 | 309 | [#277]: https://github.com/thoughtbot/ember-cli-rails/pull/277 310 | [#267]: https://github.com/thoughtbot/ember-cli-rails/pull/267 311 | [#264]: https://github.com/thoughtbot/ember-cli-rails/pull/264 312 | [#263]: https://github.com/thoughtbot/ember-cli-rails/pull/263 313 | [#259]: https://github.com/thoughtbot/ember-cli-rails/pull/259 314 | [#238]: https://github.com/thoughtbot/ember-cli-rails/pull/238 315 | [#256]: https://github.com/thoughtbot/ember-cli-rails/pull/256 316 | [#250]: https://github.com/thoughtbot/ember-cli-rails/pull/250 317 | [#261]: https://github.com/thoughtbot/ember-cli-rails/pull/261 318 | 319 | 0.4.3 320 | ----- 321 | 322 | * Failures in `{bundle,npm,bower} install` will now fail the host process with a 323 | non-zero exit status. [#236] 324 | * Improve error reporting: 325 | Redirect `ember build` from `$STDERR` to the build error file. [#245] 326 | 327 | [#236]: https://github.com/thoughtbot/ember-cli-rails/pull/236 328 | [#245]: https://github.com/thoughtbot/ember-cli-rails/pull/245 329 | 330 | 0.4.2 331 | ----- 332 | 333 | * Use the `EmberCli` module in implementation. Ensure backward compatibility by 334 | aliasing the `EmberCli` to `EmberCLI`. [#233] 335 | 336 | [#233]: https://github.com/thoughtbot/ember-cli-rails/pull/233 337 | 338 | 0.4.1 339 | ----- 340 | 341 | * `<%= head.append do %>` will now return `nil` so that accidentally using 342 | `<%= %>` variety of ERB tags won't render the contents of the capture [#231] 343 | 344 | [#231]: https://github.com/thoughtbot/ember-cli-rails/pull/231 345 | 346 | 0.4.0 347 | ----- 348 | 349 | * Extend `include_ember_index_html` helper to accept a block. The contents of 350 | the block will be injected into the page [#228] 351 | * Drop support for Ruby `< 2.1.0` and Rails `4.0.0, < 3.2.0` [#227] 352 | * Introduce `rails g ember-cli:heroku` generator to configure a project for 353 | deploying to Heroku [#230] 354 | * Introduce `include_ember_index_html` helper [#226] 355 | 356 | [#226]: https://github.com/thoughtbot/ember-cli-rails/pull/226 357 | [#227]: https://github.com/thoughtbot/ember-cli-rails/pull/227 358 | [#228]: https://github.com/thoughtbot/ember-cli-rails/pull/228 359 | [#230]: https://github.com/thoughtbot/ember-cli-rails/pull/230 360 | 361 | 0.3.5 362 | ----- 363 | 364 | * Update addon to 0.0.12 365 | 366 | 0.3.4 367 | ----- 368 | 369 | * Add `watcher` option 370 | 371 | 0.3.3 372 | ----- 373 | 374 | * Support ember-cli 1.13 375 | 376 | 0.3.2 377 | ----- 378 | 379 | * Inject `RAILS_ENV` into `ember build` process [#168][https://github.com/rwz/ember-cli-rails/pull/168] 380 | * Explicitly register view helpers [#148](https://github.com/rwz/ember-cli-rails/pull/148) 381 | 382 | 0.3.1 383 | ----- 384 | 385 | * Fix `assets:precompile` missing EmberCLI.compile! method 386 | 387 | 0.3.0 388 | ----- 389 | 390 | * Add enable option to speficy what paths should have ember compiled [#145](https://github.com/rwz/ember-cli-rails/pull/145) 391 | * Add Runner class to monitor ember deamon failures in development [#145](https://github.com/rwz/ember-cli-rails/pull/145) 392 | 393 | 0.2.3 394 | ----- 395 | 396 | * Handle Legacy Rails' lack of acronym support [#144](https://github.com/rwz/ember-cli-rails/pull/144) 397 | 398 | 0.2.2 399 | ----- 400 | 401 | * Don't use frozen version string in gemspec [#142](https://github.com/rwz/ember-cli-rails/pull/142) 402 | 403 | 0.2.1 404 | ----- 405 | 406 | * Fix missing App#configuration method [#141](https://github.com/rwz/ember-cli-rails/issues/141) 407 | 408 | 0.2.0 409 | ----- 410 | 411 | * Rename rake namespace from ember-cli to ember [commit](https://github.com/rwz/ember-cli-rails/commit/3f5463835f05d21a34b5f8a9dfeb482b0501d8d4) 412 | * Allow helpers to take optons for ember assets [commit](https://github.com/rwz/ember-cli-rails/commit/335d117a5bf4d3520730c9c421a25aee5274c2b3) 413 | * Make EmberCLI.skip? predicate return boolean [commit](https://github.com/rwz/ember-cli-rails/commit/6f7cd58010aaf584e0810c44568008654bd1a764) 414 | * Introduce EmberCLI.env and ember\_cli\_rails\_mode config option [commit](https://github.com/rwz/ember-cli-rails/commit/4ff9ea1a1a152bee9f909e4379f6f469650891b5) 415 | * Rename EmberCLI.get\_app to .app and add .[] alias [commit](https://github.com/rwz/ember-cli-rails/commit/71b4c5cc97d9a410e2ef7acc536994e5d71175c6) 416 | 417 | 0.1.13 418 | ------ 419 | 420 | * Don't Compile Assets if `SKIP_EMBER` set [#122](https://github.com/rwz/ember-cli-rails/pull/122) [@seanpdoyle](https://twitter.com/seanpdoyle) 421 | 422 | 0.1.12 423 | ------ 424 | 425 | * Fix inflector initializer for older Rails [#115](https://github.com/rwz/ember-cli-rails/pull/115) [#117](https://github.com/rwz/ember-cli-rails/pull/117) 426 | 427 | 0.1.11 428 | ------ 429 | 430 | * Do not include rake tasks twice [#110](https://github.com/rwz/ember-cli-rails/pull/110) [@BlakeWilliams](https://github.com/BlakeWilliams) 431 | 432 | 0.1.10 433 | ------ 434 | 435 | * Support ember-cli 0.2.\* [#88](https://github.com/rwz/ember-cli-rails/issues/88) 436 | 437 | 0.1.9 438 | ----- 439 | 440 | * Only set `BUNDLE_GEMFILE` to shell environment if it exists [#92](https://github.com/rwz/ember-cli-rails/issues/92) [@seanpdoyle](https://twitter.com/seanpdoyle) 441 | * Add Support for Rails 3.1 [#99](https://github.com/rwz/ember-cli-rails/pull/99) [@seanpdoyle](https://twitter.com/seanpdoyle) 442 | * Use Rails' configured asset prefix in tests [#104](https://github.com/rwz/ember-cli-rails/pull/104) [@seanpdoyle](https://twitter.com/seanpdoyle) 443 | 444 | 445 | 0.1.8 446 | ----- 447 | 448 | * Include engine file into gemspec [#91](https://github.com/rwz/ember-cli-rails/pull/91) [@jesenko](https://github.com/jesenko) 449 | 450 | 0.1.7 451 | ----- 452 | 453 | * Serve EmberCLI tests as mountable engine [#90](https://github.com/rwz/ember-cli-rails/pull/90) [@seanpdoyle](https://github.com/seanpdoyle) 454 | 455 | 0.1.6 456 | ----- 457 | 458 | * Support Gemfile in EmberCLI app [#84](https://github.com/rwz/ember-cli-rails/commit/652cf12c0a196b4719f6517f2fea308d8d556a5f) [@sevos](https://github.com/sevos) 459 | * Allow relative path to be set via initializer [#72](https://github.com/rwz/ember-cli-rails/issues/74) 460 | * Conditionally silence build output [#82](https://github.com/rwz/ember-cli-rails/issues/82) 461 | * [DEPRECATION] Default EmberCLI application in Rails' app path [#66](https://github.com/rwz/ember-cli-rails/issues/66) [@jesenko](https://github.com/jesenko) 462 | 463 | 0.1.5 464 | ----- 465 | 466 | * Compilation and dependencies Rake tasks improved [#79](https://github.com/rwz/ember-cli-rails/pull/79) 467 | 468 | 0.1.4 469 | ----- 470 | 471 | * Expose `ember-cli:compile` rake task [#73](https://github.com/rwz/ember-cli-rails/pull/73) 472 | 473 | 0.1.3 474 | ----- 475 | 476 | * Make sure setting optional config parameters override defaults [#70](https://github.com/rwz/ember-cli-rails/issues/70) 477 | 478 | 0.1.2 479 | ----- 480 | 481 | * Bump addon version to prevent missing tmp folder error [ember-cli-rails-addon#8](https://github.com/rondale-sc/ember-cli-rails-addon/pull/8) 482 | * Add configuration to control Middleware and live recompilation [#64](https://github.com/rwz/ember-cli-rails/issues/64) 483 | 484 | 0.1.1 485 | ----- 486 | 487 | * Add ember-cli:test take task [#60](https://github.com/rwz/ember-cli-rails/pull/60) 488 | 489 | 0.1.0 490 | ----- 491 | 492 | * Expose rake task for `npm install` [#59](https://github.com/rwz/ember-cli-rails/pull/59) 493 | * Detect and raise EmberCLI build errors [#23](https://github.com/rwz/ember-cli-rails/pull/23) 494 | 495 | 0.0.18 496 | ------ 497 | 498 | * Remove suppress jQuery feature [#49](https://github.com/rwz/ember-cli-rails/issues/49) 499 | * Add option to manually suppress Ember dependencies [#55](https://github.com/rwz/ember-cli-rails/pull/55) 500 | 501 | 0.0.17 502 | ------ 503 | 504 | * Only precompile assets that start with [#53](https://github.com/rwz/ember-cli-rails/pull/53) 505 | 506 | 0.0.16 507 | ------ 508 | 509 | * Use local executable for ember-cli instead of global one. 510 | [Commit](https://github.com/rwz/ember-cli-rails/commit/4aeee53f048f0445645fbc478770417fdb66cace). 511 | * Use `Dir.chdir` instead of passing `chdir` to `system`/`spawn`. Seems like 512 | JRuby doesn't yet support `chdir` option for these methods. 513 | Commits: [1](https://github.com/rwz/ember-cli-rails/commit/3bb149941f206153003726f1c18264dc62197f51), 514 | [2](https://github.com/rwz/ember-cli-rails/commit/82a39f6e523ad35ecdd595fb6e49a04cb54f9c6f). 515 | 516 | 0.0.15 517 | ------ 518 | 519 | * Fix NameError when addon version doesn't match. 520 | [#47](https://github.com/rwz/ember-cli-rails/pull/47) 521 | * Fix race condition in symlink creation when run multiple workers (again). 522 | [#22](https://github.com/rwz/ember-cli-rails/pull/22) 523 | 524 | 0.0.14 525 | ------ 526 | 527 | * Do not include jQuery into vendor.js when jquery-rails is available. 528 | [#32](https://github.com/rwz/ember-cli-rails/issues/32) 529 | 530 | 0.0.13 531 | ------ 532 | 533 | * Fix assets:precompile in production environment. 534 | [#38](https://github.com/rwz/ember-cli-rails/issues/38) 535 | 536 | 0.0.12 537 | ------ 538 | 539 | * Make sure ember-cli-dependency-checker is present. 540 | [#35](https://github.com/rwz/ember-cli-rails/issues/35) 541 | 542 | 0.0.11 543 | ------ 544 | 545 | * Fix locking feature by bumping addon version to 0.0.5. 546 | [#31](https://github.com/rwz/ember-cli-rails/issues/31) 547 | 548 | 0.0.10 549 | ------ 550 | 551 | * Add locking feature to prevent stale code. 552 | [#25](https://github.com/rwz/ember-cli-rails/pull/25) 553 | 554 | 0.0.9 555 | ----- 556 | 557 | * Fix a bug when path provided as a string, not pathname. 558 | [#24](https://github.com/rwz/ember-cli-rails/issues/24) 559 | 560 | 0.0.8 561 | ----- 562 | 563 | * Add support for including Ember stylesheet link tags. 564 | [#21](https://github.com/rwz/ember-cli-rails/pull/21) 565 | 566 | * Fix an error when the symlink already exists. 567 | [#22](https://github.com/rwz/ember-cli-rails/pull/22) 568 | 569 | 0.0.7 570 | ----- 571 | 572 | * Add sprockets-rails to dependency list. 573 | [Commit](https://github.com/rwz/ember-cli-rails/commit/99a893030d6b754fe71363a396fd4515b93812b6) 574 | 575 | * Add a flag to skip ember-cli integration. 576 | [#17](https://github.com/rwz/ember-cli-rails/issues/17) 577 | 578 | 0.0.6 579 | ----- 580 | 581 | * Fix compiling assets in test environment. [#15](https://github.com/rwz/ember-cli-rails/pull/15) 582 | * Use only development/production Ember environments. [#16](https://github.com/rwz/ember-cli-rails/pull/16) 583 | * Make the gem compatible with ruby 1.9.3. [#20](https://github.com/rwz/ember-cli-rails/issues/20) 584 | 585 | 0.0.5 586 | ----- 587 | 588 | * Fix generator. [Commit](https://github.com/rwz/ember-cli-rails/commit/c1bb10c6a2ec5b24d55fe69b6919fdd415fd1cdc). 589 | 590 | 0.0.4 591 | ----- 592 | 593 | * Add assets:precompile hook. [#11](https://github.com/rwz/ember-cli-rails/issues/11) 594 | 595 | 0.0.3 596 | ----- 597 | 598 | * Make gem Ruby 2.0 compatible. [#12](https://github.com/rwz/ember-cli-rails/issues/12) 599 | 600 | 0.0.2 601 | ----- 602 | 603 | * Do not assume ember-cli app name is equal to configured name. [#5](https://github.com/rwz/ember-cli-rails/issues/5) 604 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Reporting an Issue 2 | 3 | When reporting an issue, please fill out the provided 4 | [GitHub issue template][template] to the best of your ability. 5 | 6 | This template helps this project's maintainers understand and respond to issues 7 | in a timely manner. 8 | 9 | Issues that don't attempt to answer the questions asked in the issue template 10 | will likely be closed until additional information is provided. 11 | 12 | [template]: .github/ISSUE_TEMPLATE.md 13 | 14 | # Contributing 15 | 16 | We love pull requests from everyone. 17 | By participating in this project, 18 | you agree to abide by the thoughtbot [code of conduct]. 19 | 20 | [code of conduct]: https://thoughtbot.com/open-source-code-of-conduct 21 | 22 | We expect everyone to follow the code of conduct 23 | anywhere in thoughtbot's project codebases, 24 | issue trackers, chatrooms, and mailing lists. 25 | 26 | ## Setup 27 | 28 | After cloning the repository, execute the setup script: 29 | 30 | $ bin/setup 31 | 32 | Make sure the tests pass: 33 | 34 | $ bin/rake 35 | 36 | Make your change, with new passing tests. Follow the [style guide][style]. 37 | 38 | [style]: https://github.com/thoughtbot/guides/tree/master/style 39 | 40 | Fork the repository and push your changes to your fork. 41 | 42 | Write a [good commit message][commit]. Submit a pull request. 43 | 44 | [commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 45 | 46 | Others will give constructive feedback. 47 | This is a time for discussion and improvements, 48 | and making the necessary changes will be required before we can 49 | merge the contribution. 50 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | 5 | rails_version = ENV.fetch("RAILS_VERSION", "7.2") 6 | 7 | if rails_version == "main" 8 | rails_constraint = { github: "rails/rails" } 9 | else 10 | rails_constraint = "~> #{rails_version}.0" 11 | end 12 | 13 | gem "rails", rails_constraint 14 | gem "high_voltage", "~> 3.0.0" 15 | gem "webdrivers", "~> 5.0" 16 | gem "webrick" 17 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Ryunosuke Sato 2 | Copyright (c) 2015 Sean Doyle and thoughtbot, inc. 3 | Copyright (c) 2014 Pavel Pravosud 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ember CLI Rails 2 | 3 | Unify your EmberCLI and Rails Workflows! 4 | 5 | EmberCLI-Rails is designed to give you the best of both worlds: 6 | 7 | * Stay up to date with the latest JavaScript technology and EmberCLI addons 8 | * Develop your Rails API and Ember front-ends from within a single process 9 | * Inject Rails-generated content into your EmberCLI application 10 | * Avoid Cross-Origin Resource Sharing gotchas by serving your EmberCLI 11 | applications and your API from a single domain 12 | * Write truly end-to-end integration tests, exercising your application's entire 13 | stack through JavaScript-enabled Capybara tests 14 | * Deploy your entire suite of applications to Heroku with a single `git push` 15 | 16 | If you're having trouble, checkout the [example project]! 17 | 18 | **EmberCLI-Rails Supports EmberCLI 1.13.13 and later.** 19 | 20 | [example project]: https://github.com/seanpdoyle/ember-cli-rails-heroku-example 21 | 22 | ## Install 23 | 24 | Add the following to your `Gemfile`: 25 | 26 | ```ruby 27 | gem "ember-cli-rails" 28 | ``` 29 | 30 | Then run `bundle install`: 31 | 32 | ```bash 33 | $ bundle install 34 | ``` 35 | 36 | If you haven't created an Ember application yet, generate a new one: 37 | 38 | ```bash 39 | $ ember new frontend --skip-git 40 | ``` 41 | 42 | ## Setup 43 | 44 | First, generate the gem's initializer: 45 | 46 | ```bash 47 | $ rails generate ember:init 48 | ``` 49 | 50 | This will create the following initializer: 51 | 52 | ```ruby 53 | # config/initializers/ember.rb 54 | 55 | EmberCli.configure do |c| 56 | c.app :frontend 57 | end 58 | ``` 59 | 60 | This initializer assumes that your Ember application exists in 61 | `Rails.root.join("frontend")`. 62 | 63 | If this is not the case, you could 64 | 65 | * move your existing Ember application into `Rails.root.join("frontend")` 66 | * configure `frontend` to reference the Ember application in its current 67 | directory: 68 | 69 | ```rb 70 | c.app :frontend, path: "~/projects/my-ember-app" 71 | ``` 72 | 73 | **Initializer options** 74 | 75 | - `name` - this represents the name of the Ember CLI application. 76 | 77 | - `path` - the path where your Ember CLI application is located. The default 78 | value is the name of your app in the Rails root. 79 | 80 | - `silent` - this provides `--silent` option for Ember CLI commands to control verbosity of their output. 81 | 82 | - `yarn` - enables the [yarn](https://github.com/yarnpkg/yarn) package manager when installing dependencies 83 | 84 | ```ruby 85 | EmberCli.configure do |c| 86 | c.app :adminpanel # path defaults to `Rails.root.join("adminpanel")` 87 | c.app :frontend, 88 | path: "/path/to/your/ember-cli-app/on/disk" 89 | c.app :payments, silent: true # by default it's false 90 | end 91 | ``` 92 | 93 | Next, install the [ember-cli-rails-addon][addon]: 94 | 95 | ```bash 96 | $ cd path/to/frontend 97 | $ ember install ember-cli-rails-addon 98 | ``` 99 | 100 | Be sure that the addon's [`MAJOR` and `MINOR` version][semver] matches the gem's 101 | `MAJOR` and `MINOR` versions. 102 | 103 | For instance, if you're using the `0.6.x` version of the gem, specify 104 | `~> 0.6.0` in your Ember app's `package.json`: 105 | 106 | ```json 107 | { 108 | "devDependencies": { 109 | "ember-cli-rails-addon": "~> 0.6.0" 110 | } 111 | } 112 | ``` 113 | 114 | [addon]: https://github.com/rondale-sc/ember-cli-rails-addon/ 115 | [semver]: http://semver.org/ 116 | 117 | ## Mount 118 | 119 | Configure Rails to route requests to the `frontend` Ember application: 120 | 121 | ```rb 122 | # config/routes.rb 123 | 124 | Rails.application.routes.draw do 125 | mount_ember_app :frontend, to: "/" 126 | end 127 | ``` 128 | 129 | **Routing options** 130 | 131 | * `to` - The path to handle as an Ember application. This will only apply to 132 | `format: :html` requests. Additionally, this will handle child routes as well. 133 | For instance, mounting `mount_ember_app :frontend, to: "/frontend"` will handle a 134 | `format: :html` request to `/frontend/posts`. 135 | *Note:* If you specify a custom path, you must also update the `rootURL` in `frontend/config/environment.js`. See [Mounting multiple Ember applications](#mounting-multiple-ember-applications) for more information. 136 | * `controller` - Defaults to `"ember_cli/ember"` 137 | * `action` - Defaults to `"index"` 138 | 139 | Finally, install your Ember application's dependencies: 140 | 141 | ```bash 142 | $ rake ember:install 143 | ``` 144 | 145 | Boot your Rails application, navigate to `"/"`, and view your EmberCLI 146 | application! 147 | 148 | ## Develop 149 | 150 | EmberCLI Rails exposes several useful rake tasks. 151 | 152 | **`ember:install`** 153 | 154 | Install the Ember applications' dependencies. 155 | 156 | **`ember:compile`** 157 | 158 | Compile the Ember applications. 159 | 160 | **`ember:test`** 161 | 162 | Execute Ember's test suite. 163 | 164 | If you're using Rake to run the test suite, make sure to configure your test 165 | task to depend on `ember:test`. 166 | 167 | For example, to configure a bare `rake` command to run both RSpec and Ember test 168 | suites, configure the `default` task to depend on both `spec` and `ember:test`. 169 | 170 | ```rb 171 | task default: [:spec, "ember:test"] 172 | ``` 173 | 174 | ## Deploy 175 | 176 | When Rails is running in production mode, EmberCLI-Rails stops doing runtime 177 | compilation. Instead, configured apps are built during `rake assets:precompile`. 178 | This keeps things quick for end users, and extends the normal Rails asset 179 | building process. 180 | 181 | Configuration information, including instructions for Heroku and Capistrano, 182 | can be found below. 183 | 184 | ### CDN 185 | 186 | In production environments, assets should be served over a 187 | Content Delivery Network. 188 | 189 | Configuring an `ember-cli-rails` application to serve Ember's assets over a CDN 190 | is very similar to [configuring an EmberCLI application to serve assets over a 191 | CDN][ember-cli-cdn]: 192 | 193 | [ember-cli-cdn]: http://ember-cli.com/user-guide/#fingerprinting-and-cdn-urls 194 | 195 | ```js 196 | var app = new EmberApp({ 197 | fingerprint: { 198 | prepend: 'https://cdn.example.com/' 199 | } 200 | }); 201 | ``` 202 | 203 | If you're serving the Ember application from a path other than `"/"`, the 204 | `prepend` URL must end with the mounted path: 205 | 206 | ```js 207 | var app = new EmberApp({ 208 | fingerprint: { 209 | // for an Ember application mounted to `/admin_panel/` 210 | prepend: 'https://cdn.example.com/admin_panel/', 211 | } 212 | }); 213 | ``` 214 | 215 | As long as your [CDN is configured to pull from your Rails application][dns-cdn] 216 | , your assets will be served over the CDN. 217 | 218 | [dns-cdn]: https://robots.thoughtbot.com/dns-cdn-origin 219 | 220 | ### Deployment Strategies 221 | 222 | By default, EmberCLI-Rails uses a file-based deployment strategy that depends on 223 | the output of `ember build`. 224 | 225 | Using this deployment strategy, Rails will serve the `index.html` file and other 226 | assets that `ember build` produces. 227 | 228 | These EmberCLI-generated assets are served with the same `Cache-Control` headers 229 | as Rails' other static files: 230 | 231 | ```rb 232 | # config/environments/production.rb 233 | Rails.application.configure do 234 | # serve static files with cache headers set to expire in 1 year 235 | config.static_cache_control = "public, max-age=31622400" 236 | end 237 | ``` 238 | 239 | If you need to override this behavior (for instance, if you're using 240 | [`ember-cli-deploy`'s "Lightning Fast Deployment"][lightning] strategy in 241 | `production`), you can specify the strategy's class in the initializer: 242 | 243 | ```rb 244 | EmberCli.configure do |config| 245 | config.app :frontend, deploy: { production: EmberCli::Deploy::Redis } 246 | end 247 | ``` 248 | 249 | This example configures the `frontend` Ember application to retrieve the 250 | index's HTML from an [`ember-cli-deploy-redis`][ember-cli-deploy-redis] 251 | -populated Redis entry using the 252 | [`ember-cli-rails-deploy-redis`][ember-cli-rails-deploy-redis] gem. 253 | 254 | If you're deploying HTML with a custom strategy in `development` or `test`, 255 | disable EmberCLI-Rails' build step by setting `ENV["SKIP_EMBER"] = true`. 256 | 257 | **NOTE:** 258 | 259 | Specifying a deployment strategy is only supported for applications that use the 260 | `mount_ember_app` and `render_ember_app` helpers. 261 | 262 | [ember-cli-deploy-redis]: https://github.com/ember-cli-deploy/ember-cli-deploy-redis 263 | [ember-cli-rails-deploy-redis]: https://github.com/seanpdoyle/ember-cli-rails-deploy-redis 264 | [lightning]: https://github.com/ember-cli-deploy/ember-cli-deploy-lightning-pack 265 | 266 | ### Heroku 267 | 268 | To configure your EmberCLI-Rails applications for Heroku: 269 | 270 | 1. Execute `rails generate ember:heroku`. 271 | 1. Commit the newly generated files. 272 | 1. [Add the NodeJS buildpack][buildpack] and configure NPM to include the 273 | `bower` dependency's executable file (if your build process requires 274 | `bower`). 275 | 276 | ```sh 277 | $ heroku buildpacks:clear 278 | $ heroku buildpacks:add --index 1 heroku/nodejs 279 | $ heroku buildpacks:add --index 2 heroku/ruby 280 | $ heroku config:unset SKIP_EMBER 281 | ``` 282 | 283 | You are ready to deploy: 284 | 285 | ```bash 286 | $ git push heroku master 287 | ``` 288 | 289 | EmberCLI compilation happens at deploy-time, triggered by the `asset:precompile` rake task. 290 | 291 | **NOTE** Run the generator each time you introduce additional EmberCLI 292 | applications into the project. 293 | 294 | [buildpack]: https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app#adding-a-buildpack 295 | 296 | #### Slug size 297 | 298 | [Heroku slug size is limited](https://devcenter.heroku.com/articles/slug-compiler#slug-size). The build process creates artifacts that are not necessary for the server to run, but are included in the deployed Heroku slug. 299 | 300 | Omitting these build assets can dramatically reduce slug size. 301 | 302 | A build-pack solution for this is discussed in [Issue #491][#491]. 303 | 304 | [#491]: https://github.com/tricknotes/ember-cli-rails/issues/491 305 | 306 | ### Capistrano 307 | 308 | EmberCLI-Rails executes both `npm install` and `bower install` during EmberCLI's 309 | compilation, triggered by the `asset:precompile` rake task. 310 | 311 | The `npm` and `bower` executables are required to be defined in the deployment 312 | SSH session's `$PATH`. It is not sufficient to modify the session's `$PATH` in 313 | a `.bash_profile`. 314 | 315 | To resolve this issue, prepend the Node installation's `bin` directory to the 316 | target system's `$PATH`: 317 | 318 | ```ruby 319 | #config/deploy/production.rb 320 | 321 | set :default_env, { 322 | "PATH" => "/home/deploy/.nvm/versions/node/v4.2.1/bin:$PATH" 323 | } 324 | ``` 325 | 326 | The system in this example is using `nvm` to configure the node version. If 327 | you're not using `nvm`, make sure the string you prepend to the `$PATH` variable 328 | contains the directory or directories that contain the `bower` and `npm` 329 | executables. 330 | 331 | #### For faster deployments 332 | 333 | Place the following in your `deploy/.rb` 334 | 335 | ```ruby 336 | set :linked_dirs, %w{/node_modules /bower_components} 337 | ``` 338 | 339 | to avoid rebuilding all the node modules and bower components with every deploy. 340 | Replace `` with the name of your ember app (default is 341 | `frontend`). 342 | 343 | ## Override 344 | 345 | By default, routes defined by `ember_app` will be rendered with the internal 346 | `EmberCli::EmberController`. 347 | 348 | ### Overriding the view 349 | 350 | The `EmberCli::EmberController` renders the Ember application's `index.html` and 351 | injects the Rails-generated CSRF tags into the ``. 352 | 353 | To customize the view, create `app/views/ember_cli/ember/index.html.erb`: 354 | 355 | ```erb 356 | <%= render_ember_app ember_app do |head| %> 357 | <% head.append do %> 358 | <%= csrf_meta_tags %> 359 | <% end %> 360 | <% end %> 361 | ``` 362 | 363 | The `ember_app` helper is available within the `EmberCli::EmberController`'s 364 | view, and refers to the name of the current EmberCLI application. 365 | 366 | To inject the EmberCLI generated `index.html`, use the `render_ember_app` 367 | helper in your view: 368 | 369 | ```erb 370 | 371 | <%= render_ember_app :frontend do |head, body| %> 372 | <% head.append do %> 373 | <%= csrf_meta_tags %> 374 | <% end %> 375 | 376 | <% body.append do %> 377 | <%= render partial: "my-analytics" %> 378 | <% end %> 379 | <% end %> 380 | ``` 381 | 382 | The `body` block argument and the corresponding call to `body.append` in the 383 | example are both optional, and can be omitted. 384 | 385 | ### Serving Rails-generated CSS 386 | 387 | For more information on how to work with EmberCLI-generated stylesheets, refer 388 | to the [Stylesheets section][ember-cli-css]. EmberCLI-generated CSS will be 389 | embedded in the response's HTML document by default. 390 | 391 | To serve assets generated and served by Rails, inject them into the document's 392 | ``: 393 | 394 | ```erb 395 | <%= render_ember_app :frontend do |head| %> 396 | <% head.append do %> 397 | <%= stylesheet_link_tag "application" %> 398 | <%= csrf_meta_tags %> 399 | <% end %> 400 | <% end %> 401 | ``` 402 | 403 | There are no technical limitations to sharing assets between the Ember client 404 | and the Rails server, but picking one or the other might simplify the project's 405 | organization. 406 | 407 | Sharing code during asset compilation is __not__ possible. 408 | 409 | For example, Ember's SCSS files __cannot__ use `@import` directives referencing 410 | Rails' SCSS modules. 411 | 412 | [ember-cli-css]: http://ember-cli.com/user-guide/#stylesheets 413 | 414 | ### Overriding the controller 415 | 416 | To override this behavior, you can specify [any of Rails' routing options] 417 | [route-options]. 418 | 419 | [route-options]: http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-match 420 | 421 | For the sake of this example, override the `controller` and `action` options: 422 | 423 | ```rb 424 | # config/routes.rb 425 | 426 | Rails.application.routes.draw do 427 | mount_ember_app :frontend, to: "/", controller: "application", action: "index" 428 | end 429 | ``` 430 | 431 | When serving the EmberCLI generated `index.html` with the `render_ember_app` 432 | helper, make sure the controller's `layout` is disabled, as EmberCLI generates a 433 | fully-formed HTML document: 434 | 435 | ```rb 436 | # app/controllers/application.rb 437 | class ApplicationController < ActionController::Base 438 | def index 439 | render layout: false 440 | end 441 | end 442 | ``` 443 | 444 | ### Rendering the EmberCLI generated JS and CSS 445 | 446 | Rendering EmberCLI applications with `render_ember_app` is the recommended, 447 | actively supported method of serving EmberCLI applications. 448 | 449 | However, for the sake of backwards compatibility, `ember-cli-rails` supports 450 | injecting the EmberCLI-generated assets into an existing Rails layout. 451 | 452 | Following the example above, configure the mounted EmberCLI application to be 453 | served by a custom controller (`ApplicationController`, in this case). 454 | 455 | In the corresponding view, use the asset helpers: 456 | 457 | ```erb 458 | <%= include_ember_script_tags :frontend %> 459 | <%= include_ember_stylesheet_tags :frontend %> 460 | ``` 461 | 462 | ### Mounting multiple Ember applications 463 | 464 | Rendering Ember applications to paths other than `/` requires additional 465 | configuration. 466 | 467 | Consider a scenario where you had Ember applications named `frontend` and 468 | `admin_panel`, served from `/` and `/admin_panel` respectively. 469 | 470 | First, specify the Ember applications in the initializer: 471 | 472 | ```ruby 473 | EmberCli.configure do |c| 474 | c.app :frontend 475 | c.app :admin_panel, path: "path/to/admin_ember_app" 476 | end 477 | ``` 478 | 479 | Next, mount the applications alongside the rest of Rails' routes. Note that `admin_panel` route is added before the `frontend` route because it's more specific: 480 | 481 | ```rb 482 | # /config/routes.rb 483 | Rails.application.routes.draw do 484 | mount_ember_app :admin_panel, to: "/admin_panel" 485 | mount_ember_app :frontend, to: "/" 486 | end 487 | ``` 488 | 489 | Then set each Ember application's `rootURL` to the mount point: 490 | 491 | ```javascript 492 | // frontend/config/environment.js 493 | 494 | module.exports = function(environment) { 495 | var ENV = { 496 | modulePrefix: 'frontend', 497 | environment: environment, 498 | rootURL: '/', 499 | // ... 500 | } 501 | }; 502 | 503 | // path/to/admin_ember_app/config/environment.js 504 | 505 | module.exports = function(environment) { 506 | var ENV = { 507 | modulePrefix: 'admin_panel', 508 | environment: environment, 509 | rootURL: '/admin_panel', // originally '/' 510 | // ... 511 | } 512 | }; 513 | ``` 514 | 515 | Finally, configure EmberCLI's fingerprinting to prepend the mount point to the 516 | application's assets: 517 | 518 | ```js 519 | // frontend/ember-cli-build.js 520 | 521 | module.exports = function(defaults) { 522 | var app = new EmberApp(defaults, { 523 | fingerprint: { 524 | // matches the `/` mount point 525 | prepend: 'https://cdn.example.com/', 526 | } 527 | }); 528 | }; 529 | 530 | 531 | // path/to/admin_ember_app/ember-cli-build.js 532 | 533 | module.exports = function(defaults) { 534 | var app = new EmberApp(defaults, { 535 | fingerprint: { 536 | // matches the `/admin_panel` mount point 537 | prepend: 'https://cdn.example.com/admin_panel/', 538 | } 539 | }); 540 | }; 541 | ``` 542 | 543 | When injecting the EmberCLI-generated assets with the `include_ember_script_tags` 544 | and `include_ember_stylesheet_tags` helpers to a path other than `"/"`, a 545 | `` tag must also be injected with a corresponding `href` value: 546 | 547 | ```erb 548 | 549 | <%= include_ember_script_tags :frontend %> 550 | <%= include_ember_stylesheet_tags :frontend %> 551 | 552 | 553 | <%= include_ember_script_tags :admin_panel %> 554 | <%= include_ember_stylesheet_tags :admin_panel %> 555 | ``` 556 | 557 | If you're using the `include_ember` style helpers with a single-page Ember 558 | application that defers routing to the Rails application, insert a call to 559 | `mount_ember_assets` at the bottom of your routes file to serve the 560 | EmberCLI-generated assets: 561 | 562 | ```rb 563 | # config/routes.rb 564 | Rails.application.routes.draw do 565 | mount_ember_assets :frontend, to: "/" 566 | end 567 | ``` 568 | 569 | ## CSRF Tokens 570 | 571 | Your Rails controllers, by default, expect a valid authenticity token to 572 | be submitted along with non-`GET` requests. 573 | 574 | Without the authenticity token, requests will respond with 575 | `422 Unprocessable Entity` errors (specifically 576 | `ActionController::InvalidAuthenticityToken`). 577 | 578 | To add the necessary tokens to requests, inject the `csrf_meta_tags` into 579 | the template: 580 | 581 | ```erb 582 | 583 | <%= render_ember_app :frontend do |head| %> 584 | <% head.append do %> 585 | <%= csrf_meta_tags %> 586 | <% end %> 587 | <% end %> 588 | ``` 589 | 590 | The default `EmberCli::EmberController` and the default view handle behave like 591 | this by default. 592 | 593 | If an Ember application is mounted with another controller, it should append 594 | the CSRF tags to its view's ``. 595 | 596 | [ember-cli-rails-addon][addon] configures your Ember application to make HTTP 597 | requests with the injected CSRF tokens in the `X-CSRF-TOKEN` header. 598 | 599 | ## Serving from multi-process servers in development 600 | 601 | If you're using a multi-process server ([Puma], [Unicorn], etc.) in development, 602 | make sure it's configured to run a single worker process. 603 | 604 | Without restricting the server to a single process, [it is possible for multiple 605 | EmberCLI runners to clobber each others' work][#94]. 606 | 607 | [Puma]: https://github.com/puma/puma 608 | [Unicorn]: https://rubygems.org/gems/unicorn 609 | [#94]: https://github.com/tricknotes/ember-cli-rails/issues/94#issuecomment-77627453 610 | 611 | ## `SKIP_EMBER` 612 | 613 | If set on the environment, `SKIP_EMBER` will configure `ember-cli-rails` to skip 614 | the build step entirely. This is useful if you're using an alternative 615 | deployment strategy in the `test` or `development` environment. By default, 616 | `ember-cli-rails` will skip the build step in `production`-like environments. 617 | 618 | ## `EMBER_ENV` 619 | 620 | If set on the environment, the value of `EMBER_ENV` will be passed to the 621 | `ember` process as the value of the `--environment` flag. 622 | 623 | If `EMBER_ENV` is unspecified, the current Rails environment will be passed to 624 | the `ember` process, with the exception of non-standard Rails environments, 625 | which will be replaced with `production`. 626 | 627 | ## `RAILS_ENV` 628 | 629 | While being managed by EmberCLI Rails, EmberCLI process will have 630 | access to the `RAILS_ENV` environment variable. This can be helpful to detect 631 | the Rails environment from within the EmberCLI process. 632 | 633 | This can be useful to determine whether or not EmberCLI is running in its own 634 | standalone process or being managed by Rails. 635 | 636 | For example, to enable [ember-cli-mirage][ember-cli-mirage] API responses in 637 | `development` while being run outside of Rails (while run by `ember serve`), 638 | check for the absence of the `RAILS_ENV` environment variable: 639 | 640 | ```js 641 | // config/environment.js 642 | if (environment === 'development') { 643 | ENV['ember-cli-mirage'] = { 644 | enabled: typeof process.env.RAILS_ENV === 'undefined', 645 | } 646 | } 647 | ``` 648 | 649 | `RAILS_ENV` will be absent in production builds. 650 | 651 | [ember-cli-mirage]: http://ember-cli-mirage.com/docs/latest/ 652 | 653 | ## EmberCLI support 654 | 655 | This project supports: 656 | 657 | * EmberCLI versions `>= 1.13.13` 658 | 659 | ## Ruby and Rails support 660 | 661 | This project supports: 662 | 663 | * Ruby versions `>= 2.5.0` 664 | * Rails versions `>=5.2.x`. 665 | 666 | To learn more about supported versions and upgrades, read the [upgrading guide]. 667 | 668 | [upgrading guide]: /UPGRADING.md 669 | 670 | ## Contributing 671 | 672 | See the [CONTRIBUTING] document. 673 | Thank you, [contributors]! 674 | 675 | [CONTRIBUTING]: CONTRIBUTING.md 676 | [contributors]: https://github.com/tricknotes/ember-cli-rails/graphs/contributors 677 | 678 | ## License 679 | 680 | Open source templates are Copyright (c) 2015 thoughtbot, inc. 681 | It contains free software that may be redistributed 682 | under the terms specified in the [LICENSE] file. 683 | 684 | [LICENSE]: /LICENSE.txt 685 | 686 | ## About 687 | 688 | ember-cli-rails was originally created by 689 | [Pavel Pravosud][rwz] and 690 | [Jonathan Jackson][rondale-sc]. 691 | 692 | ember-cli-rails is maintained by [Sean Doyle][seanpdoyle], [Jonathan 693 | Jackson][rondale-sc] and [Ryunosuke Sato][tricknotes]. 694 | 695 | [rwz]: https://github.com/rwz 696 | [rondale-sc]: https://github.com/rondale-sc 697 | [seanpdoyle]: https://github.com/seanpdoyle 698 | [tricknotes]: https://github.com/tricknotes 699 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing 2 | 3 | 1. Update version file accordingly. 4 | 1. Update `CHANGELOG.md` to reflect the changes since last release. 5 | 1. Commit changes. 6 | There shouldn't be code changes, 7 | and thus CI doesn't need to run, 8 | you can then add "[ci skip]" to the commit message. 9 | 1. Tag the release: `git tag vVERSION` 10 | 1. Push changes: `git push --tags` 11 | 1. Build and publish: 12 | 13 | ```bash 14 | gem build ember-cli-rails.gemspec 15 | gem push ember-cli-rails-*.gem 16 | ``` 17 | 18 | 1. Announce the new release, 19 | making sure to say "thank you" to the contributors 20 | who helped shape this version! 21 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "rubygems" 2 | require "bundler/setup" 3 | require "bundler/gem_tasks" 4 | require "rspec/core/rake_task" 5 | 6 | require "webdrivers" 7 | load "webdrivers/Rakefile" 8 | 9 | task(:default).clear 10 | task default: :spec 11 | 12 | if defined? RSpec 13 | task(:spec).clear 14 | RSpec::Core::RakeTask.new(:spec) do |t| 15 | t.verbose = false 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | # Security Policy 3 | 4 | ## Supported Versions 5 | 6 | Only the the latest version of this project is supported at a given time. If 7 | you find a security issue with an older version, please try updating to the 8 | latest version first. 9 | 10 | If for some reason you can't update to the latest version, please let us know 11 | your reasons so that we can have a better understanding of your situation. 12 | 13 | ## Reporting a Vulnerability 14 | 15 | For security inquiries or vulnerability reports, send email to 16 | . 17 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Ruby support 2 | 3 | According to [these release notes][latest-eol], Ruby versions prior to `2.5.x` 4 | has been end-of-lifed. 5 | 6 | Additionally, this codebase makes use of [(required) keyword arguments][kwargs]. 7 | 8 | From `ember-cli-rails@0.4.0` and on, we will no longer support versions of Ruby 9 | prior to `2.1.0`. 10 | 11 | `ember-cli-rails@0.8.0` adds support for Rails 5, which depends on `rack@2.0.x`, 12 | which **requires** Ruby `2.2.2` or greater. 13 | 14 | From `ember-cli-rails@0.8.0` and on, we will no longer support versions of Ruby 15 | prior to `2.2.2`. 16 | 17 | From `ember-cli-rails@0.12.0` and on, we will no longer support versions of Ruby 18 | prior to `2.5.x`. 19 | 20 | To use `ember-cli-rails` with older versions of Ruby, try the `0.3.x` series. 21 | 22 | [kwargs]: https://robots.thoughtbot.com/ruby-2-keyword-arguments 23 | [latest-eol]: https://www.ruby-lang.org/en/news/2020/04/05/support-of-ruby-2-4-has-ended/ 24 | 25 | # Rails support 26 | 27 | According to the [Rails Maintenance Policy][version-policy], Rails versions 28 | prior to `5.2.x` have been end-of-lifed. Additionally, the `4.0.x` series no 29 | longer receives bug fixes of any sort. 30 | 31 | From `ember-cli-rails@0.4.0` and on, we will no longer support versions of Rails 32 | prior to `3.2.0`, nor will we support the `4.0.x` series of releases. 33 | 34 | From `ember-cli-rails@0.12.0` and on, we will no longer support versions of 35 | Rails prior to `5.2.0`. 36 | 37 | To use `ember-cli-rails` with older versions of Rails, try the `0.3.x` series. 38 | 39 | [version-policy]: http://guides.rubyonrails.org/maintenance_policy.html 40 | -------------------------------------------------------------------------------- /app/controller/ember_cli/ember_controller.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class EmberController < ::ApplicationController 3 | unless ancestors.include? ActionController::Base 4 | ( 5 | ActionController::Base::MODULES - 6 | ActionController::API::MODULES 7 | ).each do |controller_module| 8 | include controller_module 9 | end 10 | 11 | helper EmberRailsHelper 12 | end 13 | 14 | def index 15 | render layout: false 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/helpers/ember_rails_helper.rb: -------------------------------------------------------------------------------- 1 | require "html_page/capture" 2 | 3 | module EmberRailsHelper 4 | def render_ember_app(name, &block) 5 | EmberCli[name].build 6 | 7 | markup_capturer = HtmlPage::Capture.new(self, &block) 8 | 9 | head, body = markup_capturer.capture 10 | 11 | render html: EmberCli[name].index_html(head: head, body: body).html_safe 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/views/ember_cli/ember/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= render_ember_app params[:ember_app] do |head| %> 2 | <% head.append do %> 3 | <%= csrf_meta_tags %> 4 | <% end %> 5 | <% end %> 6 | -------------------------------------------------------------------------------- /bin/clean: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | rm -rf spec/dummy/{my-app,tmp} 6 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rake' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rake', 'rake') 17 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rspec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'rspec') 17 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | echo '-- Set up Ruby dependencies via Bundler' 6 | gem install bundler --conservative 7 | bundle check || bundle install 8 | 9 | bin/rake webdrivers:chromedriver:update 10 | 11 | # Add binstubs to PATH via export PATH=".git/safe/../../bin:$PATH" in ~/.zshenv 12 | mkdir -p .git/safe 13 | 14 | if ! command -v bower > /dev/null; then 15 | npm install -g bower 16 | fi 17 | 18 | bin/setup_ember spec/dummy/my-app 19 | 20 | echo '-- Install Ember dependencies' 21 | cd spec/dummy && bundle exec rake ember:install || true 22 | -------------------------------------------------------------------------------- /bin/setup_ember: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | setup_ember() { 6 | local target="${1-spec/dummy/my-app}" 7 | 8 | if ! [ -d $target ]; then 9 | git clone -b 'v4.0.0' https://github.com/ember-cli/ember-new-output.git $target 10 | 11 | echo '-- Make router catchall routes' 12 | sed -i -e "s/'auto'/'hash'/" $target/config/environment.js 13 | 14 | echo '-- Add an image to a template' 15 | cp spec/fixtures/application.hbs $target/app/templates/application.hbs 16 | 17 | mkdir -p $target/public/assets 18 | cp spec/fixtures/logo.png $target/public/assets 19 | 20 | echo '-- Install ember-cli-rails-addon' 21 | cd $target && 22 | npm install --save-dev ember-cli-rails-addon@rondale-sc/ember-cli-rails-addon 23 | 24 | if [ -f "$target/bower.json" ]; then 25 | echo '-- Install Bower dependencies' 26 | cd $target && bower install 27 | fi 28 | 29 | echo '-- Successfully setup Ember' 30 | fi 31 | } 32 | 33 | setup_ember 34 | -------------------------------------------------------------------------------- /ember-cli-rails.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path("../lib", __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require "ember_cli/version" 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "ember-cli-rails" 8 | spec.version = EmberCli::VERSION.dup 9 | spec.authors = ["Pavel Pravosud", "Jonathan Jackson", "Sean Doyle", "Ryunosuke Sato"] 10 | spec.email = ["pavel@pravosud.com", "jonathan.jackson1@me.com", "sean.p.doyle24@gmail.com", "tricknotes.rs@gmail.com"] 11 | spec.summary = "Integration between Ember CLI and Rails" 12 | spec.homepage = "https://github.com/tricknotes/ember-cli-rails" 13 | spec.license = "MIT" 14 | spec.files = Dir["README.md", "CHANGELOG.md", "LICENSE.txt", "{lib,app,config}/**/*"] 15 | 16 | spec.required_ruby_version = ">= 2.5.0" 17 | 18 | spec.add_dependency "ember-cli-rails-assets", ">= 0.6.2", "< 1.0" 19 | spec.add_dependency "railties", ">= 4.2" 20 | spec.add_dependency "rack", ">= 2.1", "< 4.0" 21 | spec.add_dependency "terrapin", "~> 0.6.0" 22 | spec.add_dependency "html_page", "~> 0.1.0" 23 | 24 | spec.add_development_dependency "generator_spec", "~> 0.9.0" 25 | spec.add_development_dependency "rspec-rails", ">= 3.6.0", "< 7.0" 26 | 27 | spec.add_development_dependency "capybara-selenium" 28 | spec.add_development_dependency "codeclimate-test-reporter", "~> 0.6.0" 29 | end 30 | -------------------------------------------------------------------------------- /lib/ember-cli-rails.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli" 2 | 3 | EmberCLI = EmberCli 4 | -------------------------------------------------------------------------------- /lib/ember_cli.rb: -------------------------------------------------------------------------------- 1 | require "fileutils" 2 | require "ember-cli-rails-assets" 3 | require "ember_cli/engine" 4 | require "ember_cli/configuration" 5 | require "ember_cli/helpers" 6 | require "ember_cli/errors" 7 | 8 | module EmberCli 9 | extend self 10 | 11 | def configure 12 | yield configuration 13 | end 14 | 15 | def configuration 16 | Configuration.instance 17 | end 18 | 19 | def app(name) 20 | apps.fetch(name) do 21 | fail KeyError, "#{name.inspect} app is not defined" 22 | end 23 | end 24 | alias_method :[], :app 25 | 26 | def apps 27 | configuration.apps 28 | end 29 | 30 | def build(name) 31 | app(name).build 32 | end 33 | 34 | def any?(*arguments, &block) 35 | apps.values.any?(*arguments, &block) 36 | end 37 | 38 | def skip? 39 | ENV["SKIP_EMBER"].present? 40 | end 41 | 42 | def install_dependencies! 43 | each_app(&:install_dependencies) 44 | end 45 | 46 | def test! 47 | each_app(&:test) 48 | end 49 | 50 | def compile! 51 | cleanup! 52 | each_app(&:compile) 53 | end 54 | 55 | def root 56 | @root ||= Rails.root.join("tmp", "ember-cli").tap(&:mkpath) 57 | end 58 | 59 | def env 60 | @env ||= Helpers.current_environment 61 | end 62 | 63 | private 64 | 65 | def cleanup! 66 | root.children.each { |tmp_file| FileUtils.rm_rf(tmp_file) } 67 | end 68 | 69 | def each_app 70 | apps.each { |_, app| yield app } 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/ember_cli/app.rb: -------------------------------------------------------------------------------- 1 | require "html_page/renderer" 2 | require "ember_cli/path_set" 3 | require "ember_cli/shell" 4 | require "ember_cli/build_monitor" 5 | require "ember_cli/deploy/file" 6 | 7 | module EmberCli 8 | class App 9 | attr_reader :name, :options, :paths 10 | 11 | def initialize(name, **options) 12 | @name = name.to_s 13 | @options = options 14 | @paths = PathSet.new( 15 | app: self, 16 | environment: Rails.env, 17 | rails_root: Rails.root, 18 | ember_cli_root: EmberCli.root, 19 | ) 20 | @shell = Shell.new( 21 | paths: @paths, 22 | env: env_hash, 23 | options: options, 24 | ) 25 | @build = BuildMonitor.new(name, @paths) 26 | end 27 | 28 | def root_path 29 | paths.root 30 | end 31 | 32 | def dist_path 33 | paths.dist 34 | end 35 | 36 | def cached_directories 37 | paths.cached_directories 38 | end 39 | 40 | def compile 41 | @compiled ||= begin 42 | prepare 43 | exit_status = @shell.compile 44 | @build.check! 45 | 46 | exit_status.success? 47 | end 48 | end 49 | 50 | def build 51 | unless EmberCli.skip? 52 | if development? 53 | build_and_watch 54 | elsif test? 55 | compile 56 | end 57 | 58 | @build.wait! 59 | end 60 | end 61 | 62 | def index_html(head:, body:) 63 | html = HtmlPage::Renderer.new( 64 | head: head, 65 | body: body, 66 | content: deploy.index_html, 67 | ) 68 | 69 | html.render 70 | end 71 | 72 | def install_dependencies 73 | @shell.install 74 | end 75 | 76 | def test 77 | prepare 78 | 79 | @shell.test.success? 80 | end 81 | 82 | def check_for_errors! 83 | @build.check! 84 | end 85 | 86 | def mountable? 87 | deploy.mountable? 88 | end 89 | 90 | def yarn_enabled? 91 | options.fetch(:yarn, false) 92 | end 93 | 94 | def bower? 95 | paths.bower_json.exist? 96 | end 97 | 98 | def to_rack 99 | deploy.to_rack 100 | end 101 | 102 | private 103 | 104 | def development? 105 | env.to_s == "development" 106 | end 107 | 108 | def test? 109 | env.to_s == "test" 110 | end 111 | 112 | def deploy 113 | deploy_strategy.new(self) 114 | end 115 | 116 | def deploy_strategy 117 | strategy = options.fetch(:deploy, {}) 118 | 119 | if strategy.respond_to?(:fetch) 120 | strategy.fetch(rails_env, EmberCli::Deploy::File) 121 | else 122 | strategy 123 | end 124 | end 125 | 126 | def rails_env 127 | Rails.env.to_s.to_sym 128 | end 129 | 130 | def env 131 | EmberCli.env 132 | end 133 | 134 | def build_and_watch 135 | prepare 136 | @shell.build_and_watch 137 | end 138 | 139 | def prepare 140 | @prepared ||= begin 141 | @build.reset 142 | true 143 | end 144 | end 145 | 146 | def excluded_ember_deps 147 | Array.wrap(options[:exclude_ember_deps]).join("?") 148 | end 149 | 150 | def env_hash 151 | ENV.to_h.tap do |vars| 152 | vars["RAILS_ENV"] = Rails.env 153 | vars["EXCLUDE_EMBER_ASSETS"] = excluded_ember_deps 154 | vars["BUNDLE_GEMFILE"] = paths.gemfile.to_s if paths.gemfile.exist? 155 | end 156 | end 157 | end 158 | end 159 | -------------------------------------------------------------------------------- /lib/ember_cli/build_monitor.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class BuildMonitor 3 | def initialize(name, paths) 4 | @name = name 5 | @paths = paths 6 | end 7 | 8 | def check! 9 | if has_build_errors? 10 | raise_build_error! 11 | end 12 | 13 | true 14 | end 15 | 16 | def reset 17 | if error_file_exists? 18 | error_file.delete 19 | end 20 | end 21 | 22 | def wait! 23 | loop do 24 | check! 25 | break if complete? 26 | sleep 0.1 27 | end 28 | end 29 | 30 | private 31 | 32 | attr_reader :name, :paths 33 | 34 | def complete? 35 | !paths.lockfile.exist? 36 | end 37 | 38 | def error_file_exists? 39 | error_file.exist? && error_file.size? 40 | end 41 | 42 | def build_errors 43 | error_lines. 44 | reject { |line| is_blank_or_backtrace?(line) }. 45 | reject { |line| is_deprecation_warning?(line) }. 46 | reject { |line| is_building_notice?(line) } 47 | end 48 | 49 | def has_build_errors? 50 | build_errors.any? 51 | end 52 | 53 | def is_blank_or_backtrace?(line) 54 | line =~ /(^\s*$|^\s{4}at .+$)/ 55 | end 56 | 57 | def is_deprecation_warning?(line) 58 | line =~ /^(\e[^\s]+)?DEPRECATION:/ 59 | end 60 | 61 | def is_building_notice?(line) 62 | line =~ /^(\e[^\s]+)?.\s(\e[^\s]+)?Building/ 63 | end 64 | 65 | def error_lines 66 | if error_file_exists? 67 | error_file.readlines 68 | else 69 | [""] 70 | end 71 | end 72 | 73 | def error_file 74 | paths.build_error_file 75 | end 76 | 77 | def raise_build_error! 78 | backtrace = build_errors.first 79 | message = "#{name.inspect} has failed to build: #{backtrace}" 80 | 81 | error = BuildError.new(message) 82 | error.set_backtrace(backtrace) 83 | 84 | fail error 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /lib/ember_cli/command.rb: -------------------------------------------------------------------------------- 1 | require "terrapin" 2 | 3 | module EmberCli 4 | class Command 5 | def initialize(paths:, options: {}) 6 | @paths = paths 7 | @options = options 8 | end 9 | 10 | def test 11 | line = Terrapin::CommandLine.new(paths.ember, "test --environment test") 12 | 13 | line.command 14 | end 15 | 16 | def build(watch: false) 17 | ember_build(watch: watch) 18 | end 19 | 20 | private 21 | 22 | attr_reader :options, :paths 23 | 24 | def process_watcher 25 | options.fetch(:watcher) { EmberCli.configuration.watcher } 26 | end 27 | 28 | def silent? 29 | options.fetch(:silent) { false } 30 | end 31 | 32 | def ember_build(watch: false) 33 | line = Terrapin::CommandLine.new(paths.ember, [ 34 | "build", 35 | ("--watch" if watch), 36 | ("--watcher :watcher" if process_watcher), 37 | ("--silent" if silent?), 38 | "--environment :environment", 39 | "--output-path :output_path", 40 | ].compact.join(" ")) 41 | 42 | line.command( 43 | environment: build_environment, 44 | output_path: paths.dist, 45 | watcher: process_watcher, 46 | ) 47 | end 48 | 49 | def build_environment 50 | if EmberCli.env == "production" 51 | "production" 52 | else 53 | "development" 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/ember_cli/configuration.rb: -------------------------------------------------------------------------------- 1 | require "singleton" 2 | require "ember_cli/app" 3 | 4 | module EmberCli 5 | class Configuration 6 | include Singleton 7 | 8 | attr_accessor :watcher 9 | 10 | def app(name, **options) 11 | app = App.new(name, **options) 12 | apps.store(name, app) 13 | end 14 | 15 | def apps 16 | @apps ||= HashWithIndifferentAccess.new 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/ember_cli/deploy/file.rb: -------------------------------------------------------------------------------- 1 | require "rack" 2 | require "ember_cli/errors" 3 | 4 | module EmberCli 5 | module Deploy 6 | class File 7 | def initialize(app) 8 | @app = app 9 | end 10 | 11 | def mountable? 12 | true 13 | end 14 | 15 | def to_rack 16 | Rack::Files.new(app.dist_path.to_s, rack_headers) 17 | end 18 | 19 | def index_html 20 | if index_file.exist? 21 | index_file.read 22 | else 23 | check_for_error_and_raise! 24 | end 25 | end 26 | 27 | private 28 | 29 | attr_reader :app 30 | 31 | def rack_headers 32 | config = Rails.configuration 33 | 34 | if config.respond_to?(:public_file_server) && 35 | config.public_file_server && config.public_file_server.headers 36 | # Rails 5. 37 | config.public_file_server.headers 38 | elsif config.respond_to?(:static_cache_control) 39 | # Rails 4.2 and below. 40 | { 41 | "Cache-Control" => Rails.configuration.static_cache_control, 42 | } 43 | else 44 | # No specification. 45 | {} 46 | end 47 | end 48 | 49 | def check_for_error_and_raise! 50 | app.check_for_errors! 51 | 52 | raise BuildError.new <<-MSG 53 | EmberCLI failed to generate an `index.html` file. 54 | MSG 55 | end 56 | 57 | def index_file 58 | app.dist_path.join("index.html") 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/ember_cli/ember_constraint.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class EmberConstraint 3 | def matches?(request) 4 | html_request?(request) && 5 | !rails_info_request?(request) && 6 | !rails_active_storage_request?(request) 7 | end 8 | 9 | private 10 | 11 | def rails_info_request?(request) 12 | request.fullpath.start_with?("/rails/info", "/rails/mailers") 13 | end 14 | 15 | def rails_active_storage_request?(request) 16 | request.fullpath.start_with?("/rails/active_storage") 17 | end 18 | 19 | def html_request?(request) 20 | request.format.html? 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/ember_cli/engine.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class Engine < Rails::Engine 3 | initializer "ember-cli-rails.setup" do 4 | require "ember_cli/route_helpers" 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/ember_cli/errors.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class BuildError < StandardError; end 3 | class DependencyError < BuildError; end 4 | end 5 | -------------------------------------------------------------------------------- /lib/ember_cli/helpers.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | module Helpers 3 | extend self 4 | 5 | def which(cmd) 6 | exts = ENV.fetch("PATHEXT", ";").split(";", -1).uniq 7 | 8 | ENV.fetch("PATH").split(File::PATH_SEPARATOR).each do |path| 9 | exts.each do |ext| 10 | exe = File.join(path, "#{cmd}#{ext}") 11 | return exe if File.executable?(exe) && !File.directory?(exe) 12 | end 13 | end 14 | 15 | nil 16 | end 17 | 18 | def current_environment 19 | ENV.fetch("EMBER_ENV") { default_environment } 20 | end 21 | 22 | private 23 | 24 | def default_environment 25 | if Rails.env.match(/test|development/) 26 | Rails.env 27 | else 28 | "production" 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/ember_cli/path_set.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/helpers" 2 | 3 | module EmberCli 4 | class PathSet 5 | def initialize(app:, rails_root:, ember_cli_root:, environment:) 6 | @app = app 7 | @rails_root = rails_root 8 | @environment = environment 9 | @ember_cli_root = ember_cli_root 10 | end 11 | 12 | def root 13 | path = app_options.fetch(:path){ default_root } 14 | pathname = Pathname.new(path) 15 | if pathname.absolute? 16 | pathname 17 | else 18 | rails_root.join(path) 19 | end 20 | end 21 | 22 | def tmp 23 | @tmp ||= root.join("tmp").tap(&:mkpath) 24 | end 25 | 26 | def log 27 | @log ||= logs.join("ember-#{app_name}.#{environment}.log") 28 | end 29 | 30 | def dist 31 | @dist ||= ember_cli_root.join("apps", app_name).tap(&:mkpath) 32 | end 33 | 34 | def gemfile 35 | @gemfile ||= root.join("Gemfile") 36 | end 37 | 38 | def bower_json 39 | root.join("bower.json") 40 | end 41 | 42 | def ember 43 | @ember ||= begin 44 | root.join("node_modules", "ember-cli", "bin", "ember").tap do |path| 45 | unless path.executable? 46 | fail DependencyError.new <<-MSG.strip_heredoc 47 | No `ember-cli` executable found for `#{app_name}`. 48 | 49 | Install it: 50 | 51 | $ cd #{root} 52 | $ #{package_manager} install 53 | 54 | MSG 55 | end 56 | end 57 | end 58 | end 59 | 60 | def lockfile 61 | @lockfile ||= tmp.join("build.lock") 62 | end 63 | 64 | def build_error_file 65 | @build_error_file ||= tmp.join("error.txt") 66 | end 67 | 68 | def bower 69 | @bower ||= begin 70 | path_for_executable("bower").tap do |bower_path| 71 | if bower_json.exist? && (bower_path.blank? || !bower_path.executable?) 72 | fail DependencyError.new <<-MSG.strip_heredoc 73 | Bower is required by EmberCLI 74 | 75 | Install it with: 76 | 77 | $ npm install -g bower 78 | 79 | MSG 80 | end 81 | end 82 | end 83 | end 84 | 85 | def bower_components 86 | @bower_components ||= root.join("bower_components") 87 | end 88 | 89 | def npm 90 | @npm ||= path_for_executable("npm") 91 | end 92 | 93 | def yarn 94 | if yarn? 95 | @yarn ||= path_for_executable("yarn").tap do |yarn| 96 | unless File.executable?(yarn.to_s) 97 | fail DependencyError.new(<<-MSG.strip_heredoc) 98 | EmberCLI has been configured to install NodeJS dependencies with Yarn, but the Yarn executable is unavailable. 99 | 100 | Install it by following the instructions at https://yarnpkg.com/lang/en/docs/install/ 101 | 102 | MSG 103 | end 104 | end 105 | end 106 | end 107 | 108 | def node_modules 109 | @node_modules ||= root.join("node_modules") 110 | end 111 | 112 | def tee 113 | @tee ||= path_for_executable("tee") 114 | end 115 | 116 | def bundler 117 | @bundler ||= path_for_executable("bundler") 118 | end 119 | 120 | def cached_directories 121 | [ 122 | node_modules, 123 | (bower_components if bower_json.exist?), 124 | ].compact 125 | end 126 | 127 | private 128 | 129 | attr_reader :app, :ember_cli_root, :environment, :rails_root 130 | 131 | def path_for_executable(command) 132 | path = app_options.fetch("#{command}_path") { which(command) } 133 | 134 | if path.present? 135 | Pathname.new(path) 136 | end 137 | end 138 | 139 | def package_manager 140 | if yarn? 141 | "yarn" 142 | else 143 | "npm" 144 | end 145 | end 146 | 147 | def yarn? 148 | app_options[:yarn] || app_options[:yarn_path] 149 | end 150 | 151 | def app_name 152 | app.name 153 | end 154 | 155 | def app_options 156 | app.options.with_indifferent_access 157 | end 158 | 159 | def which(executable) 160 | Helpers.which(executable) 161 | end 162 | 163 | def logs 164 | rails_root.join("log").tap(&:mkpath) 165 | end 166 | 167 | def default_root 168 | rails_root.join(app_name) 169 | end 170 | end 171 | end 172 | -------------------------------------------------------------------------------- /lib/ember_cli/route_helpers.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/ember_constraint" 2 | require "ember_cli/trailing_slash_constraint" 3 | 4 | module ActionDispatch 5 | module Routing 6 | class Mapper 7 | def mount_ember_app(app_name, to:, **options) 8 | routing_options = options.deep_merge( 9 | defaults: { ember_app: app_name }, 10 | ) 11 | 12 | routing_options.reverse_merge!( 13 | controller: "ember_cli/ember", 14 | action: "index", 15 | format: :html, 16 | ) 17 | 18 | scope constraints: ::EmberCli::EmberConstraint.new do 19 | redirect_if_missing_trailing_slash = { 20 | constraints: EmberCli::TrailingSlashConstraint.new, 21 | to: redirect(-> (_, request) { 22 | File.join(request.path, "/?#{request.query_parameters.to_query}") 23 | }), 24 | } 25 | 26 | get(to, **redirect_if_missing_trailing_slash) 27 | get(File.join(to, "(*rest)"), **routing_options) 28 | end 29 | 30 | mount_ember_assets(app_name, to: to) 31 | end 32 | 33 | def mount_ember_assets(app_name, to: "/") 34 | app = ::EmberCli[app_name] 35 | 36 | if app.mountable? 37 | mount app.to_rack, at: to 38 | end 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/ember_cli/runner.rb: -------------------------------------------------------------------------------- 1 | require "open3" 2 | 3 | module EmberCli 4 | class Runner 5 | def initialize(out:, err:, env: {}, options: {}) 6 | @env = env 7 | @output_streams = Array(out) 8 | @error_streams = Array(err) 9 | @options = options 10 | @threads = [] 11 | end 12 | 13 | def run(command) 14 | Open3.popen3(env, command, options) do |stdin, stdout, stderr, process| 15 | stdin.close 16 | 17 | threads << redirect_stream_in_thread(stdout, write_to: output_streams) 18 | threads << redirect_stream_in_thread(stderr, write_to: error_streams) 19 | 20 | threads.each(&:join) 21 | process.value 22 | end 23 | end 24 | 25 | def run!(command) 26 | run(command).tap do |status| 27 | unless status.success? 28 | exit status.exitstatus 29 | end 30 | end 31 | end 32 | 33 | protected 34 | 35 | attr_reader :env, :error_streams, :options, :output_streams, :threads 36 | 37 | private 38 | 39 | def redirect_stream_in_thread(stream, write_to:) 40 | Thread.new do 41 | Thread.current.abort_on_exception = true 42 | 43 | while line = stream.gets 44 | write_to.each { |redirection_stream| redirection_stream.puts(line) } 45 | end 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/ember_cli/shell.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/command" 2 | require "ember_cli/runner" 3 | 4 | module EmberCli 5 | class Shell 6 | def initialize(paths:, env: {}, options: {}) 7 | @paths = paths 8 | @env = env 9 | @ember = Command.new( 10 | paths: paths, 11 | options: options, 12 | ) 13 | @on_exit ||= at_exit { stop } 14 | end 15 | 16 | def compile 17 | run! ember.build 18 | end 19 | 20 | def build_and_watch 21 | unless running? 22 | lock_buildfile 23 | self.pid = spawn ember.build(watch: true) 24 | detach 25 | end 26 | end 27 | 28 | def stop 29 | if pid.present? 30 | Process.kill(:INT, pid) 31 | self.pid = nil 32 | end 33 | end 34 | 35 | def install 36 | if paths.gemfile.exist? 37 | run! "#{paths.bundler} install" 38 | end 39 | 40 | if invalid_ember_dependencies? 41 | clean_ember_dependencies! 42 | end 43 | 44 | if paths.yarn 45 | run! "#{paths.yarn} install" 46 | else 47 | run! "#{paths.npm} prune && #{paths.npm} install" 48 | end 49 | 50 | if paths.bower_json.exist? 51 | run! "#{paths.bower} prune && #{paths.bower} install" 52 | end 53 | end 54 | 55 | def test 56 | run! ember.test 57 | end 58 | 59 | private 60 | 61 | attr_accessor :pid 62 | attr_reader :ember, :env, :options, :paths 63 | 64 | delegate :run, :run!, to: :runner 65 | 66 | def invalid_ember_dependencies? 67 | !run("#{paths.ember} version").success? 68 | rescue DependencyError 69 | false 70 | end 71 | 72 | def clean_ember_dependencies! 73 | ember_dependency_directories.flat_map(&:children).each(&:rmtree) 74 | end 75 | 76 | def ember_dependency_directories 77 | [ 78 | paths.node_modules, 79 | paths.bower_components, 80 | ].select(&:exist?) 81 | end 82 | 83 | def spawn(command) 84 | Kernel.spawn( 85 | env, 86 | command, 87 | chdir: paths.root.to_s, 88 | err: paths.build_error_file.to_s, 89 | ) || exit(1) 90 | end 91 | 92 | def runner 93 | Runner.new( 94 | options: { chdir: paths.root.to_s }, 95 | out: [$stdout, paths.log.open("a")], 96 | err: [$stderr], 97 | env: env, 98 | ) 99 | end 100 | 101 | def running? 102 | pid.present? && Process.getpgid(pid) 103 | rescue Errno::ESRCH 104 | false 105 | end 106 | 107 | def lock_buildfile 108 | FileUtils.touch(paths.lockfile) 109 | end 110 | 111 | def detach 112 | Process.detach pid 113 | end 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /lib/ember_cli/trailing_slash_constraint.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class TrailingSlashConstraint 3 | def matches?(request) 4 | !request.original_fullpath.to_s.split("?").first.end_with?("/") 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/ember_cli/version.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | VERSION = "0.12.2".freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/generators/ember/heroku/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Configures a project for deploying to Heroku. 3 | 4 | Once the generator is complete, execute the following: 5 | 6 | $ heroku buildpacks:clear 7 | $ heroku buildpacks:add --index 1 heroku/nodejs 8 | $ heroku buildpacks:add --index 2 heroku/ruby 9 | $ heroku config:unset SKIP_EMBER 10 | 11 | Example: 12 | rails generate ember:heroku 13 | 14 | This will install the following gems: 15 | rails_12factor 16 | 17 | This will create: 18 | package.json 19 | -------------------------------------------------------------------------------- /lib/generators/ember/heroku/heroku_generator.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class HerokuGenerator < Rails::Generators::Base 3 | source_root File.expand_path("../templates", __FILE__) 4 | 5 | namespace "ember:heroku" 6 | 7 | def copy_package_json_file 8 | template "package.json.erb", "package.json" 9 | end 10 | 11 | def identify_as_yarn_project 12 | if EmberCli.any?(&:yarn_enabled?) 13 | template "yarn.lock.erb", "yarn.lock" 14 | end 15 | end 16 | 17 | def inject_12factor_gem 18 | gem "rails_12factor", group: [:staging, :production] 19 | end 20 | 21 | private 22 | 23 | def cache_directories 24 | all_cached_directories.map do |cached_directory| 25 | cached_directory.relative_path_from(Rails.root).to_s 26 | end 27 | end 28 | 29 | def all_cached_directories 30 | app_specific_cached_directories + project_root_cached_directories 31 | end 32 | 33 | def app_specific_cached_directories 34 | apps.flat_map(&:cached_directories) 35 | end 36 | 37 | def project_root_cached_directories 38 | [Rails.root.join("node_modules")] 39 | end 40 | 41 | def app_paths 42 | EmberCli.apps.values.map do |app| 43 | app.root_path.relative_path_from(Rails.root) 44 | end 45 | end 46 | 47 | def apps 48 | EmberCli.apps.values 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/generators/ember/heroku/templates/package.json.erb: -------------------------------------------------------------------------------- 1 | { 2 | <% if EmberCli.any?(&:bower?) %> 3 | "dependencies": { 4 | "bower": "*" 5 | }, 6 | <% end %> 7 | "cacheDirectories": <%= cache_directories.to_json %> 8 | } 9 | -------------------------------------------------------------------------------- /lib/generators/ember/heroku/templates/yarn.lock.erb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/generators/ember/init/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Generates `ember.rb` initializer. 3 | 4 | Example: 5 | rails generate ember:init 6 | 7 | This will create: 8 | config/initializers/ember.rb 9 | -------------------------------------------------------------------------------- /lib/generators/ember/init/init_generator.rb: -------------------------------------------------------------------------------- 1 | module EmberCli 2 | class InitGenerator < Rails::Generators::Base 3 | source_root File.expand_path("../templates", __FILE__) 4 | 5 | namespace "ember:init" 6 | 7 | def copy_initializer_file 8 | copy_file "initializer.rb", "config/initializers/ember.rb" 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/generators/ember/init/templates/initializer.rb: -------------------------------------------------------------------------------- 1 | EmberCli.configure do |c| 2 | c.app :frontend 3 | end 4 | -------------------------------------------------------------------------------- /lib/tasks/ember-cli.rake: -------------------------------------------------------------------------------- 1 | namespace :ember do 2 | desc "Runs `ember build` for each App" 3 | task compile: :install do 4 | EmberCli.compile! 5 | end 6 | 7 | desc "Runs `ember test` for each App" 8 | task test: :environment do 9 | EmberCli.test! 10 | end 11 | 12 | desc "Installs each EmberCLI app's dependencies" 13 | task install: :environment do 14 | EmberCli.install_dependencies! 15 | end 16 | end 17 | 18 | unless EmberCli.skip? 19 | task "assets:precompile" => "ember:compile" 20 | end 21 | -------------------------------------------------------------------------------- /spec/dummy/.gitignore: -------------------------------------------------------------------------------- 1 | !.keep 2 | *.DS_Store 3 | *.swo 4 | *.swp 5 | /.bundle 6 | /.env 7 | /.foreman 8 | /coverage/* 9 | /db/*.sqlite3 10 | /log/* 11 | /public/system 12 | /public/assets 13 | /tags 14 | /tmp/* 15 | -------------------------------------------------------------------------------- /spec/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | require File.expand_path("../application", __FILE__) 2 | 3 | Rails.application.load_tasks 4 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= csrf_meta_tags %> 6 | 7 | 8 | 9 | <%= yield %> 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /spec/dummy/app/views/pages/embedded.html.erb: -------------------------------------------------------------------------------- 1 | <%= include_ember_script_tags "my-app" %> 2 | <%= include_ember_stylesheet_tags "my-app" %> 3 | -------------------------------------------------------------------------------- /spec/dummy/app/views/pages/include_index.html.erb: -------------------------------------------------------------------------------- 1 | <%= render_ember_app "my-app" %> 2 | -------------------------------------------------------------------------------- /spec/dummy/app/views/pages/include_index_empty_block.html.erb: -------------------------------------------------------------------------------- 1 | <%= render_ember_app "my-app" do %> 2 | <%= csrf_meta_tags %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /spec/dummy/app/views/pages/include_index_head_and_body.html.erb: -------------------------------------------------------------------------------- 1 | <%= render_ember_app "my-app" do |head, body| %> 2 | <% head.append do %> 3 | <%= csrf_meta_tags %> 4 | <% end %> 5 | 6 | <% body.append do %> 7 |

Hello from Rails

8 | <% end %> 9 | <% end %> 10 | -------------------------------------------------------------------------------- /spec/dummy/application.rb: -------------------------------------------------------------------------------- 1 | require "rails" 2 | 3 | require "action_controller/railtie" 4 | require "action_view/railtie" 5 | 6 | Bundler.require(*Rails.groups) 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | CACHE_CONTROL_FIVE_MINUTES = "public, max-age=300".freeze 11 | 12 | config.root = File.expand_path("..", __FILE__).freeze 13 | config.eager_load = false 14 | 15 | # Show full error reports and disable caching. 16 | config.consider_all_requests_local = true 17 | config.action_controller.perform_caching = false 18 | 19 | # Raise exceptions instead of rendering exception templates. 20 | config.action_dispatch.show_exceptions = false 21 | 22 | # Randomize the order test cases are executed. 23 | config.active_support.test_order = :random 24 | 25 | # Print deprecation notices to the stderr. 26 | config.active_support.deprecation = :stderr 27 | 28 | config.public_file_server.enabled = true 29 | config.public_file_server.headers = { 30 | "cache-control" => CACHE_CONTROL_FIVE_MINUTES 31 | } 32 | 33 | config.secret_token = "SECRET_TOKEN_IS_MIN_30_CHARS_LONG" 34 | config.secret_key_base = "SECRET_KEY_BASE" 35 | 36 | config.active_support.to_time_preserves_timezone = :zone 37 | 38 | def require_environment! 39 | initialize! 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/ember.rb: -------------------------------------------------------------------------------- 1 | EmberCli.configure do |c| 2 | c.app "my-app" 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/high_voltage.rb: -------------------------------------------------------------------------------- 1 | require "high_voltage" 2 | 3 | HighVoltage.configure do |config| 4 | config.layout = false 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | with_options controller: "high_voltage/pages", action: "show" do |app| 3 | app.mount_ember_app( 4 | "my-app", 5 | to: "/no-block", 6 | id: "include_index", 7 | as: "include_index", 8 | ) 9 | 10 | app.mount_ember_app( 11 | "my-app", 12 | to: "/empty-block", 13 | id: "include_index_empty_block", 14 | as: "include_index_empty_block", 15 | ) 16 | 17 | app.mount_ember_app( 18 | "my-app", 19 | to: "/head-and-body-block", 20 | id: "include_index_head_and_body", 21 | as: "include_index_head_and_body", 22 | ) 23 | 24 | app.mount_ember_app( 25 | "my-app", 26 | to: "/asset-helpers", 27 | id: "embedded", 28 | as: "embedded", 29 | ) 30 | end 31 | 32 | mount_ember_app( 33 | "my-app", 34 | to: "/", 35 | as: "default", 36 | ) 37 | end 38 | -------------------------------------------------------------------------------- /spec/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tricknotes/ember-cli-rails/93502eade30e1d03f249b88ddddeaed70d264ed1/spec/dummy/public/favicon.ico -------------------------------------------------------------------------------- /spec/features/user_views_ember_app_spec.rb: -------------------------------------------------------------------------------- 1 | feature "User views ember app", :js do 2 | scenario "using route helper" do 3 | visit default_path 4 | 5 | expect(page).to have_client_side_asset 6 | expect(page).to have_javascript_rendered_text 7 | expect(page).to have_csrf_tags 8 | end 9 | 10 | context "using custom controller" do 11 | scenario "rendering with asset helpers" do 12 | visit embedded_path 13 | 14 | expect(page).to have_client_side_asset 15 | expect(page).to have_javascript_rendered_text 16 | expect(page).to have_no_csrf_tags 17 | end 18 | 19 | scenario "rendering with index helper" do 20 | visit include_index_path 21 | 22 | expect(page).to have_javascript_rendered_text 23 | expect(page).to have_no_csrf_tags 24 | 25 | visit include_index_empty_block_path 26 | 27 | expect(page).to have_javascript_rendered_text 28 | expect(page).to have_csrf_tags 29 | 30 | visit include_index_head_and_body_path 31 | 32 | expect(page).to have_javascript_rendered_text 33 | expect(page).to have_csrf_tags 34 | expect(page).to have_rails_injected_text 35 | end 36 | end 37 | 38 | scenario "is redirected with trailing slash", js: false do 39 | expect(embedded_path).to eq("/asset-helpers") 40 | 41 | visit embedded_path 42 | 43 | expect(current_path).to eq("/asset-helpers/") 44 | end 45 | 46 | scenario "is redirected with trailing slash with query params", js: false do 47 | expect(embedded_path(query: "foo")).to eq("/asset-helpers?query=foo") 48 | 49 | visit embedded_path(query: "foo") 50 | 51 | expect(page).to have_current_path("/asset-helpers/?query=foo") 52 | end 53 | 54 | scenario "is not redirected with trailing slash with params", js: false do 55 | expect(embedded_path(query: "foo")).to eq("/asset-helpers?query=foo") 56 | 57 | visit "/asset-helpers/?query=foo" 58 | 59 | expect(page).to have_current_path("/asset-helpers/?query=foo") 60 | end 61 | 62 | def have_client_side_asset 63 | have_css %{img[src*="logo.png"]} 64 | end 65 | 66 | def have_rails_injected_text 67 | have_text "Hello from Rails" 68 | end 69 | 70 | def have_javascript_rendered_text 71 | have_text("Welcome to Ember") 72 | end 73 | 74 | def have_no_csrf_tags 75 | have_no_css("meta[name=csrf-param]", visible: false). 76 | and have_no_css("meta[name=csrf-token]", visible: false) 77 | end 78 | 79 | def have_csrf_tags 80 | have_css("meta[name=csrf-param]", visible: false). 81 | and have_css("meta[name=csrf-token]", visible: false) 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /spec/fixtures/application.hbs: -------------------------------------------------------------------------------- 1 |

Welcome to Ember

2 | 3 | 4 | {{outlet}} 5 | -------------------------------------------------------------------------------- /spec/fixtures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tricknotes/ember-cli-rails/93502eade30e1d03f249b88ddddeaed70d264ed1/spec/fixtures/logo.png -------------------------------------------------------------------------------- /spec/generators/ember/heroku/heroku_generator_spec.rb: -------------------------------------------------------------------------------- 1 | require "generator_spec" 2 | require "generators/ember/heroku/heroku_generator" 3 | 4 | describe EmberCli::HerokuGenerator, type: :generator do 5 | OUTPUT_DIRECTORY = Rails.root.join("tmp", "generator_test_output") 6 | destination OUTPUT_DIRECTORY 7 | 8 | context "without yarn enabled" do 9 | it "does not generate a root-level yarn.lock" do 10 | setup_destination 11 | configure_application(yarn: false) 12 | 13 | run_generator 14 | 15 | expect(destination_root).to have_structure { 16 | no_file "yarn.lock" 17 | } 18 | end 19 | end 20 | 21 | context "with yarn enabled" do 22 | it "generates a root-level yarn.lock" do 23 | setup_destination 24 | configure_application(yarn: true) 25 | 26 | run_generator 27 | 28 | expect(destination_root).to have_structure { 29 | file "yarn.lock" 30 | } 31 | end 32 | end 33 | 34 | describe "package.json" do 35 | it "includes the root directory node_modules" do 36 | setup_destination 37 | configure_application 38 | 39 | run_generator 40 | 41 | expect(cache_directories_from_package_json).to include("node_modules") 42 | end 43 | 44 | context "when no Ember application depends on bower" do 45 | it "does not include bower as a dependency" do 46 | setup_destination 47 | depend_on_bower(false) 48 | configure_application 49 | 50 | run_generator 51 | 52 | expect(package_json.keys).not_to include("dependencies") 53 | expect(cache_directories_from_package_json).not_to include_bower 54 | end 55 | end 56 | 57 | context "when an Ember application depends on bower" do 58 | it "includes bower as a dependency" do 59 | setup_destination 60 | depend_on_bower(true) 61 | configure_application 62 | 63 | run_generator 64 | 65 | expect(dependencies_from_package_json).to include("bower" => "*") 66 | expect(cache_directories_from_package_json).to include_bower 67 | end 68 | end 69 | 70 | def depend_on_bower(bower_enabled) 71 | allow_any_instance_of(EmberCli::App). 72 | to receive(:bower?).and_return(bower_enabled) 73 | 74 | allow_any_instance_of(EmberCli::App). 75 | to receive(:cached_directories).and_return( 76 | cached_directories(bower_enabled), 77 | ) 78 | end 79 | 80 | def cached_directories(bower_enabled) 81 | if bower_enabled 82 | [OUTPUT_DIRECTORY.join("bower_components")] 83 | else 84 | [] 85 | end 86 | end 87 | 88 | def include_bower 89 | include(/bower_components/) 90 | end 91 | 92 | def cache_directories_from_package_json 93 | package_json.fetch("cacheDirectories") 94 | end 95 | 96 | def dependencies_from_package_json 97 | package_json.fetch("dependencies") 98 | end 99 | 100 | def package_json 101 | JSON.parse(package_json_contents) 102 | end 103 | 104 | def package_json_contents 105 | destination_root.join("package.json").read 106 | end 107 | end 108 | 109 | def configure_application(**options) 110 | EmberCli.configure { |c| c.app("my-app", **options) } 111 | end 112 | 113 | def setup_destination 114 | prepare_destination 115 | 116 | create_empty_gemfile_for_bundler 117 | end 118 | 119 | def create_empty_gemfile_for_bundler 120 | FileUtils.touch(destination_root.join("Gemfile")) 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /spec/lib/ember-cli-rails_spec.rb: -------------------------------------------------------------------------------- 1 | describe EmberCli do 2 | describe ".any?" do 3 | it "delegates to the collection of applications" do 4 | allow(EmberCli).to receive(:apps).and_return( 5 | with_foo: { foo: true }, 6 | witout_foo: { foo: false }, 7 | ) 8 | 9 | any_with_foo = EmberCli.any? { |options| options.fetch(:foo) } 10 | 11 | expect(any_with_foo).to be true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/app_spec.rb: -------------------------------------------------------------------------------- 1 | require "ember-cli-rails" 2 | 3 | describe EmberCli::App do 4 | describe "#to_rack" do 5 | it "delegates to `#deploy`" do 6 | deploy = double(to_rack: :delegated) 7 | app = EmberCli["my-app"] 8 | allow(app).to receive(:deploy).and_return(deploy) 9 | 10 | to_rack = app.to_rack 11 | 12 | expect(to_rack).to be :delegated 13 | end 14 | end 15 | 16 | describe "#mountable?" do 17 | it "delegates to `#deploy`" do 18 | deploy = double(mountable?: :delegated) 19 | app = EmberCli["my-app"] 20 | allow(app).to receive(:deploy).and_return(deploy) 21 | 22 | mountable = app.mountable? 23 | 24 | expect(mountable).to be :delegated 25 | end 26 | end 27 | 28 | describe "yarn_enabled?" do 29 | context "when configured with yarn: true" do 30 | it "returns true" do 31 | app = EmberCli::App.new("with-yarn", yarn: true) 32 | 33 | yarn_enabled = app.yarn_enabled? 34 | 35 | expect(yarn_enabled).to be true 36 | end 37 | end 38 | 39 | context "when configured with yarn: false" do 40 | it "returns false" do 41 | app = EmberCli::App.new("without-yarn", yarn: false) 42 | 43 | yarn_enabled = app.yarn_enabled? 44 | 45 | expect(yarn_enabled).to be false 46 | end 47 | end 48 | end 49 | 50 | describe "#bower?" do 51 | context "when bower.json exists" do 52 | it "returns true" do 53 | bower_json_path = double("Pathname", exist?: true) 54 | stub_paths(bower_json: bower_json_path) 55 | app = EmberCli::App.new("with bower json") 56 | 57 | bower_required = app.bower? 58 | 59 | expect(bower_required).to be true 60 | end 61 | end 62 | 63 | context "when bower.json is absent" do 64 | it "returns false" do 65 | bower_json_path = double("Pathname", exist?: false) 66 | stub_paths(bower_json: bower_json_path) 67 | app = EmberCli::App.new("without bower json") 68 | 69 | bower_required = app.bower? 70 | 71 | expect(bower_required).to be false 72 | end 73 | end 74 | end 75 | 76 | describe "#compile" do 77 | it "exits with exit status of 0" do 78 | passed = EmberCli["my-app"].compile 79 | 80 | expect(passed).to be true 81 | end 82 | end 83 | 84 | describe "#test" do 85 | it "exits with exit status of 0" do 86 | passed = EmberCli["my-app"].test 87 | 88 | expect(passed).to be true 89 | end 90 | end 91 | 92 | describe "#root_path" do 93 | it "delegates to PathSet" do 94 | root_path = Pathname.new(".") 95 | stub_paths(root: root_path) 96 | app = EmberCli::App.new("foo") 97 | 98 | root_path = app.root_path 99 | 100 | expect(root_path).to eq root_path 101 | end 102 | end 103 | 104 | describe "#dist_path" do 105 | it "delegates to PathSet" do 106 | dist_path = Pathname.new(".") 107 | stub_paths(dist: dist_path) 108 | app = EmberCli::App.new("foo") 109 | 110 | dist_path = app.dist_path 111 | 112 | expect(dist_path).to eq dist_path 113 | end 114 | end 115 | 116 | def stub_paths(method_to_value) 117 | allow_any_instance_of(EmberCli::PathSet). 118 | to receive(method_to_value.keys.first). 119 | and_return(method_to_value.values.first) 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/build_monitor_spec.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/errors" 2 | require "ember_cli/build_monitor" 3 | 4 | describe EmberCli::BuildMonitor do 5 | BLANK_LINE = "" 6 | 7 | describe "#reset" do 8 | context "when there is a build error" do 9 | it "deletes the build file" do 10 | error_file = error_file_with_contents 11 | paths = build_paths(error_file) 12 | monitor = EmberCli::BuildMonitor.new(nil, paths) 13 | 14 | monitor.reset 15 | 16 | expect(error_file).to have_received(:delete) 17 | end 18 | end 19 | 20 | context "when there are only deprecation warnings" do 21 | it "deletes the build file" do 22 | error_file = error_file_with_contents(["DEPRECATION: A warning"]) 23 | paths = build_paths(error_file) 24 | monitor = EmberCli::BuildMonitor.new(nil, paths) 25 | 26 | monitor.reset 27 | 28 | expect(error_file).to have_received(:delete) 29 | end 30 | end 31 | 32 | context "when there is not a build error" do 33 | it "does nothing" do 34 | error_file = missing_error_file 35 | paths = build_paths(error_file) 36 | monitor = EmberCli::BuildMonitor.new(nil, paths) 37 | 38 | monitor.reset 39 | 40 | expect(error_file).not_to have_received(:delete) 41 | end 42 | end 43 | end 44 | 45 | describe "#check!" do 46 | context "when the error file has content" do 47 | it "raises a BuildError" do 48 | paths = build_paths(error_file_with_contents(["first-line"])) 49 | monitor = EmberCli::BuildMonitor.new("app-name", paths) 50 | 51 | expect { monitor.check! }. 52 | to raise_error( 53 | EmberCli::BuildError, 54 | %{"app-name" has failed to build: first-line}, 55 | ) 56 | end 57 | end 58 | 59 | context "when the error file only contains deprecation warnings" do 60 | it "does not raise a BuildError" do 61 | error_file = error_file_with_contents( 62 | [ 63 | BLANK_LINE, 64 | "DEPRECATION: A warning", 65 | " at AStackTrace", 66 | ]) 67 | paths = build_paths(error_file) 68 | monitor = EmberCli::BuildMonitor.new(nil, paths) 69 | 70 | expect(monitor.check!).to be true 71 | end 72 | end 73 | 74 | context "when the error file contains a ASCII colored deprecation" do 75 | it "does not raise a BuildError" do 76 | error_file = error_file_with_contents( 77 | [ 78 | BLANK_LINE, 79 | "\e[33mDEPRECATION: A warning", 80 | " at AStackTrace\e[39m", 81 | ]) 82 | paths = build_paths(error_file) 83 | monitor = EmberCli::BuildMonitor.new(nil, paths) 84 | 85 | expect(monitor.check!).to be true 86 | end 87 | end 88 | 89 | context "when the error file contains an ASCII colored Building notice" do 90 | it "does not raise a BuildError" do 91 | error_file = error_file_with_contents( 92 | [ 93 | "- \e[32mBuilding\e[39m" 94 | ]) 95 | paths = build_paths(error_file) 96 | monitor = EmberCli::BuildMonitor.new(nil, paths) 97 | 98 | expect(monitor.check!).to be true 99 | end 100 | end 101 | 102 | context "when the error file contains both errors & deprecation warnings" do 103 | it "raises a BuildError" do 104 | error_file = error_file_with_contents( 105 | [ 106 | BLANK_LINE, 107 | "DEPRECATION: A warning", 108 | " at AStackTrace", 109 | BLANK_LINE, 110 | "SyntaxError: things went wrong", 111 | ]) 112 | paths = build_paths(error_file) 113 | monitor = EmberCli::BuildMonitor.new("app-name", paths) 114 | 115 | expect { monitor.check! }. 116 | to raise_error( 117 | EmberCli::BuildError, 118 | %{"app-name" has failed to build: SyntaxError: things went wrong}, 119 | ) 120 | end 121 | end 122 | 123 | context "when the error file exists but is empty" do 124 | it "does not raise a BuildError" do 125 | paths = build_paths(blank_error_file) 126 | monitor = EmberCli::BuildMonitor.new(nil, paths) 127 | 128 | expect(monitor.check!).to be true 129 | end 130 | end 131 | 132 | context "when the error file is missing" do 133 | it "does not raise a BuildError" do 134 | paths = build_paths(missing_error_file) 135 | monitor = EmberCli::BuildMonitor.new(nil, paths) 136 | 137 | expect(monitor.check!).to be true 138 | end 139 | end 140 | end 141 | 142 | def build_paths(error_file) 143 | double(build_error_file: error_file) 144 | end 145 | 146 | def error_file_with_contents(contents = ["foo"]) 147 | build_error_file(exist?: true, size?: true, readlines: contents) 148 | end 149 | 150 | def blank_error_file 151 | build_error_file(exist?: true, size?: false) 152 | end 153 | 154 | def missing_error_file 155 | build_error_file(exist?: false) 156 | end 157 | 158 | def build_error_file(**options) 159 | double(**options).tap do |stub| 160 | allow(stub).to receive(:delete) 161 | end 162 | end 163 | end 164 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/command_spec.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/command" 2 | 3 | describe EmberCli::Command do 4 | describe "#test" do 5 | it "builds an `ember test` command" do 6 | paths = build_paths(ember: "path/to/ember") 7 | command = build_command(paths: paths) 8 | 9 | expect(command.test).to eq("path\/to\/ember test --environment test") 10 | end 11 | end 12 | 13 | describe "#build" do 14 | it "builds an `ember build` command" do 15 | paths = build_paths(ember: "path/to/ember") 16 | command = build_command(paths: paths) 17 | 18 | expect(command.build).to match(%r{path\/to\/ember build}) 19 | end 20 | 21 | context "when building in production" do 22 | it "includes the `--environment production` flag" do 23 | paths = build_paths 24 | command = build_command(paths: paths) 25 | allow(EmberCli).to receive(:env).and_return("production") 26 | 27 | expect(command.build).to match(/--environment 'production'/) 28 | end 29 | end 30 | 31 | context "when building in any other environment" do 32 | it "includes the `--environment development` flag" do 33 | paths = build_paths 34 | command = build_command(paths: paths) 35 | allow(EmberCli).to receive(:env).and_return("test") 36 | 37 | expect(command.build).to match(/--environment 'development'/) 38 | end 39 | end 40 | 41 | it "includes the `--output-path` flag" do 42 | paths = build_paths(dist: "path/to/dist") 43 | command = build_command(paths: paths) 44 | 45 | expect(command.build).to match(%r{--output-path 'path\/to\/dist'}) 46 | end 47 | 48 | context "when configured not to watch" do 49 | it "excludes the `--watch` flag" do 50 | paths = build_paths 51 | command = build_command(paths: paths) 52 | 53 | expect(command.build).not_to match(/--watch/) 54 | end 55 | end 56 | 57 | context "when configured not to be silent" do 58 | it "exludes the `--silent` flag" do 59 | paths = build_paths 60 | command = build_command(paths: paths) 61 | 62 | expect(command.build).not_to match(/--silent/) 63 | 64 | paths = build_paths 65 | command = build_command(paths: paths, options: { silent: false }) 66 | 67 | expect(command.build).not_to match(/--silent/) 68 | end 69 | end 70 | 71 | context "when configured to be silent" do 72 | it "includes `--silent` flag" do 73 | paths = build_paths 74 | command = build_command(paths: paths, options: { silent: true }) 75 | 76 | expect(command.build).to match(/--silent/) 77 | end 78 | end 79 | 80 | context "when configured to watch" do 81 | it "includes the `--watch` flag" do 82 | paths = build_paths 83 | command = build_command(paths: paths) 84 | 85 | expect(command.build(watch: true)).to match(/--watch/) 86 | end 87 | 88 | it "defaults to configuration for the `--watcher` flag" do 89 | paths = build_paths 90 | command = build_command(paths: paths) 91 | allow(EmberCli). 92 | to receive(:configuration). 93 | and_return(build_paths(watcher: "bar")) 94 | 95 | expect(command.build(watch: true)).to match(/--watcher 'bar'/) 96 | end 97 | 98 | context "when a watcher is configured" do 99 | it "configures the build with the value" do 100 | paths = build_paths 101 | command = build_command(paths: paths, options: { watcher: "foo" }) 102 | 103 | expect(command.build(watch: true)).to match(/--watcher 'foo'/) 104 | end 105 | end 106 | end 107 | end 108 | 109 | def build_paths(**options) 110 | double(options).as_null_object 111 | end 112 | 113 | def build_command(**options) 114 | EmberCli::Command.new(**options) 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/deploy/file_spec.rb: -------------------------------------------------------------------------------- 1 | require "tmpdir" 2 | require "ember_cli/deploy/file" 3 | 4 | describe EmberCli::Deploy::File do 5 | describe "#index_html" do 6 | context "when the file is missing" do 7 | it "raises a BuildError" do 8 | deploy = EmberCli::Deploy::File.new(build_app) 9 | 10 | expect { deploy.index_html }.to raise_error(EmberCli::BuildError) 11 | end 12 | end 13 | 14 | it "returns the contents of the app's `index_file`" do 15 | app = build_app 16 | create_index(app.dist_path, "") 17 | deploy = EmberCli::Deploy::File.new(app) 18 | 19 | index_html = deploy.index_html 20 | 21 | expect(index_html).to eq("") 22 | end 23 | end 24 | 25 | describe "#mountable?" do 26 | it "returns true" do 27 | deploy = EmberCli::Deploy::File.new(build_app) 28 | 29 | mountable = deploy.mountable? 30 | 31 | expect(mountable).to be true 32 | end 33 | end 34 | 35 | describe "#to_rack" do 36 | it "creates a Rack::Files instance" do 37 | deploy = EmberCli::Deploy::File.new(build_app) 38 | 39 | rack_app = deploy.to_rack 40 | 41 | expect(rack_app).to respond_to(:call) 42 | end 43 | end 44 | 45 | def create_index(directory, contents) 46 | directory.join("index.html").write(contents) 47 | end 48 | 49 | def build_app 50 | tmpdir = Pathname.new(Dir.mktmpdir) 51 | 52 | double(dist_path: tmpdir, check_for_errors!: false) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/ember_constraint_spec.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/ember_constraint" 2 | 3 | describe EmberCli::EmberConstraint do 4 | describe "#matches?" do 5 | context %{when the format is "html"} do 6 | context "when the request path is for a Rails active storage file" do 7 | it "returns a falsey value" do 8 | constraint = EmberCli::EmberConstraint.new 9 | request = build_html_request("/rails/active_storage") 10 | 11 | expect(constraint.matches?(request)).to be_falsey 12 | end 13 | end 14 | 15 | context "when the request path is for a Rails info page" do 16 | it "returns a falsey value" do 17 | constraint = EmberCli::EmberConstraint.new 18 | request = build_html_request("/rails/info") 19 | 20 | expect(constraint.matches?(request)).to be_falsey 21 | end 22 | end 23 | 24 | context "when the request path is not for a Rails info page" do 25 | it "returns a truthy value" do 26 | constraint = EmberCli::EmberConstraint.new 27 | request = build_html_request("/foo") 28 | 29 | expect(constraint.matches?(request)).to be_truthy 30 | end 31 | end 32 | end 33 | 34 | context %{when the format isn't "html"} do 35 | it "return false" do 36 | constraint = EmberCli::EmberConstraint.new 37 | request = build_json_request 38 | 39 | expect(constraint.matches?(request)).to be_falsey 40 | end 41 | end 42 | end 43 | 44 | def build_request(format:, fullpath: :ignored) 45 | double(format: format ? Mime::Type.new(format) : nil, fullpath: fullpath) 46 | end 47 | 48 | def build_html_request(fullpath) 49 | build_request(format: "text/html", fullpath: fullpath) 50 | end 51 | 52 | def build_json_request 53 | build_request(format: "application/json") 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/helpers_spec.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/helpers" 2 | 3 | describe EmberCli::Helpers do 4 | describe ".current_environment" do 5 | context "when EMBER_ENV is set" do 6 | it "returns the value of EMBER_ENV" do 7 | stub_env("EMBER_ENV" => "staging") 8 | 9 | current_environment = EmberCli::Helpers.current_environment 10 | 11 | expect(current_environment).to eq "staging" 12 | end 13 | end 14 | 15 | context "when test" do 16 | it "returns test" do 17 | stub_rails_env("test") 18 | 19 | current_environment = EmberCli::Helpers.current_environment 20 | 21 | expect(current_environment).to eq "test" 22 | end 23 | end 24 | 25 | context "when development" do 26 | it "returns development" do 27 | stub_rails_env("development") 28 | 29 | current_environment = EmberCli::Helpers.current_environment 30 | 31 | expect(current_environment).to eq "development" 32 | end 33 | end 34 | 35 | context "when anything else" do 36 | it "returns production" do 37 | stub_rails_env("staging") 38 | 39 | current_environment = EmberCli::Helpers.current_environment 40 | 41 | expect(current_environment).to eq "production" 42 | end 43 | end 44 | end 45 | 46 | def stub_env(key_to_value) 47 | allow(ENV). 48 | to receive(:fetch). 49 | with(key_to_value.keys.first). 50 | and_return(key_to_value.values.first) 51 | end 52 | 53 | def stub_rails_env(env) 54 | allow(Rails). 55 | to receive(:env). 56 | and_return(env.to_s) 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/path_set_spec.rb: -------------------------------------------------------------------------------- 1 | require "fileutils" 2 | require "ember_cli/path_set" 3 | 4 | describe EmberCli::PathSet do 5 | describe "#root" do 6 | it "depends on the app name" do 7 | app = build_app(name: "foo") 8 | 9 | path_set = build_path_set(app: app) 10 | 11 | expect(path_set.root).to eq rails_root.join("foo") 12 | end 13 | 14 | it "can be overridden" do 15 | app = build_app(name: "foo", options: { path: "not-foo" }) 16 | 17 | path_set = build_path_set(app: app) 18 | 19 | expect(path_set.root).to eq rails_root.join("not-foo") 20 | end 21 | end 22 | 23 | describe "#tmp" do 24 | it "is a child of #root" do 25 | app = build_app 26 | 27 | path_set = build_path_set(app: app) 28 | 29 | expect(path_set.tmp).to exist 30 | expect(path_set.tmp).to eq rails_root.join(app.name, "tmp") 31 | end 32 | end 33 | 34 | describe "#log" do 35 | it "depends on the environment" do 36 | app = build_app(name: "foo") 37 | path_set = build_path_set(app: app, environment: "bar") 38 | 39 | expect(path_set.log).to eq rails_root.join("log", "ember-foo.bar.log") 40 | expect(rails_root.join("log")).to exist 41 | end 42 | end 43 | 44 | describe "#dist" do 45 | it "depends on the app name" do 46 | app = build_app(name: "foo") 47 | 48 | path_set = build_path_set(app: app) 49 | 50 | expect(path_set.dist).to exist 51 | expect(path_set.dist).to eq ember_cli_root.join("apps", "foo") 52 | end 53 | end 54 | 55 | describe "#gemfile" do 56 | it "is a child of #root" do 57 | app = build_app(name: "foo") 58 | 59 | path_set = build_path_set(app: app) 60 | 61 | expect(path_set.gemfile).to eq rails_root.join("foo", "Gemfile") 62 | end 63 | end 64 | 65 | describe "#lockfile" do 66 | it "is a child of #tmp" do 67 | path_set = build_path_set 68 | 69 | expect(path_set.lockfile).to eq path_set.tmp.join("build.lock") 70 | end 71 | end 72 | 73 | describe "#build_error_file" do 74 | it "is a child of #tmp" do 75 | path_set = build_path_set 76 | 77 | expect(path_set.build_error_file).to eq path_set.tmp.join("error.txt") 78 | end 79 | end 80 | 81 | describe "#ember" do 82 | it "is an executable child of #node_modules" do 83 | app = build_app 84 | path_set = build_path_set(app: app) 85 | ember_path = rails_root.join(app.name, "node_modules", "ember-cli", "bin", "ember") 86 | create_executable(ember_path) 87 | 88 | ember = path_set.ember 89 | 90 | expect(ember).to eq(ember_path).and(be_executable) 91 | end 92 | 93 | it "raises a DependencyError if the file isn't executable" do 94 | path_set = build_path_set 95 | 96 | expect { path_set.ember }.to raise_error(EmberCli::DependencyError) 97 | end 98 | end 99 | 100 | describe "#bower" do 101 | it "can be overridden" do 102 | fake_bower = create_executable(ember_cli_root.join("bower")) 103 | app = build_app(options: { bower_path: fake_bower.to_s }) 104 | path_set = build_path_set(app: app) 105 | 106 | bower = path_set.bower 107 | 108 | expect(bower).to eq(fake_bower).and(be_executable) 109 | end 110 | 111 | it "can be inferred from the $PATH" do 112 | fake_bower = create_executable(ember_cli_root.join("bower")) 113 | stub_which(bower: fake_bower.to_s) 114 | path_set = build_path_set 115 | 116 | bower = path_set.bower 117 | 118 | expect(bower).to eq(fake_bower).and(be_executable) 119 | end 120 | 121 | context "when it is missing from the $PATH" do 122 | context "bower.json exists" do 123 | it "raises a helpful exception" do 124 | app = build_app 125 | create_file(app_root_for(app).join("bower.json")) 126 | stub_which(bower: nil) 127 | path_set = build_path_set 128 | 129 | expect { path_set.bower }. 130 | to raise_error(EmberCli::DependencyError, /bower is required/i) 131 | end 132 | 133 | context "bower.json is missing" do 134 | it "returns nil" do 135 | stub_which(bower: nil) 136 | path_set = build_path_set 137 | 138 | bower = path_set.bower 139 | 140 | expect(bower).to be_nil 141 | end 142 | end 143 | end 144 | end 145 | end 146 | 147 | describe "#bower_json" do 148 | it "is a child of #root" do 149 | app = build_app 150 | path_set = build_path_set(app: app) 151 | 152 | bower_json = path_set.bower_json 153 | 154 | expect(bower_json).to eq app_root_for(app).join("bower.json") 155 | end 156 | end 157 | 158 | describe "#bower_components" do 159 | it "is a child of #root" do 160 | app = build_app(name: "foo") 161 | 162 | path_set = build_path_set(app: app) 163 | 164 | expect(path_set.bower_components). 165 | to eq rails_root.join("foo", "bower_components") 166 | end 167 | end 168 | 169 | describe "#npm" do 170 | it "can be overridden" do 171 | fake_npm = create_executable(ember_cli_root.join("npm")) 172 | app = build_app(options: { npm_path: fake_npm.to_s }) 173 | path_set = build_path_set(app: app) 174 | 175 | npm = path_set.npm 176 | 177 | expect(npm).to eq(fake_npm).and(be_executable) 178 | end 179 | 180 | it "can be inferred from the $PATH" do 181 | fake_npm = create_executable(ember_cli_root.join("npm")) 182 | stub_which(npm: fake_npm.to_s) 183 | path_set = build_path_set 184 | 185 | npm = path_set.npm 186 | 187 | expect(npm).to eq(fake_npm).and(be_executable) 188 | end 189 | end 190 | 191 | describe "#yarn" do 192 | it "can be overridden" do 193 | fake_yarn = create_executable(ember_cli_root.join("yarn")) 194 | app = build_app(options: { yarn_path: fake_yarn.to_s }) 195 | path_set = build_path_set(app: app) 196 | 197 | yarn = path_set.yarn 198 | 199 | expect(yarn).to eq(fake_yarn).and(be_executable) 200 | end 201 | 202 | it "can be inferred from the $PATH" do 203 | fake_yarn = create_executable(ember_cli_root.join("yarn")) 204 | stub_which(yarn: fake_yarn.to_s) 205 | app = build_app(options: { yarn: true }) 206 | path_set = build_path_set(app: app) 207 | create_executable(fake_yarn) 208 | 209 | yarn = path_set.yarn 210 | 211 | expect(yarn).to eq(fake_yarn).and(be_executable) 212 | end 213 | 214 | context "when the executable isn't installed on the system" do 215 | context "and yarn is requested" do 216 | it "raises a DependencyError" do 217 | stub_which(yarn: nil) 218 | app = build_app(options: { yarn: true }) 219 | path_set = build_path_set(app: app) 220 | 221 | expect { path_set.yarn }.to raise_error(EmberCli::DependencyError) 222 | end 223 | end 224 | 225 | context "and yarn is not requested" do 226 | it "returns nil" do 227 | stub_which(yarn: nil) 228 | path_set = build_path_set 229 | 230 | yarn = path_set.yarn 231 | 232 | expect(yarn).to be_nil 233 | end 234 | end 235 | end 236 | end 237 | 238 | describe "#node_modules" do 239 | it "is a child of #root" do 240 | app = build_app(name: "foo") 241 | 242 | path_set = build_path_set(app: app) 243 | 244 | expect(path_set.node_modules).to eq rails_root.join("foo", "node_modules") 245 | end 246 | end 247 | 248 | describe "#tee" do 249 | it "can be overridden" do 250 | fake_tee = create_executable(rails_root.join("tee")) 251 | app = build_app(options: { tee_path: fake_tee.to_s }) 252 | path_set = build_path_set(app: app) 253 | 254 | tee = path_set.tee 255 | 256 | expect(tee).to eq(fake_tee).and(be_executable) 257 | end 258 | 259 | it "can be inferred from the $PATH" do 260 | fake_tee = create_executable(rails_root.join("tee")) 261 | stub_which(tee: fake_tee.to_s) 262 | path_set = build_path_set 263 | 264 | tee = path_set.tee 265 | 266 | expect(tee).to eq(fake_tee).and(be_executable) 267 | end 268 | end 269 | 270 | describe "#bundler" do 271 | it "can be overridden" do 272 | fake_bundler = create_executable(rails_root.join("bundler")) 273 | app = build_app(options: { bundler_path: fake_bundler.to_s }) 274 | path_set = build_path_set(app: app) 275 | 276 | bundler = path_set.bundler 277 | 278 | expect(bundler).to eq(fake_bundler).and(be_executable) 279 | end 280 | 281 | it "can be inferred from the $PATH" do 282 | fake_bundler = create_executable(rails_root.join("bundler")) 283 | stub_which(bundler: fake_bundler.to_s) 284 | path_set = build_path_set 285 | 286 | bundler = path_set.bundler 287 | 288 | expect(bundler).to eq(fake_bundler).and(be_executable) 289 | end 290 | end 291 | 292 | describe "#cached_directories" do 293 | it "includes the full path to the application's node_modules" do 294 | app_name = "foo" 295 | app = build_app(name: app_name) 296 | path_set = build_path_set(app: app) 297 | 298 | cached_directories = path_set.cached_directories 299 | 300 | expect(cached_directories).to include( 301 | rails_root.join(app_name, "node_modules"), 302 | ) 303 | end 304 | 305 | context "when bower.json exists" do 306 | it "includes the full path to bower_components" do 307 | app_name = "foo" 308 | app = build_app(name: app_name) 309 | app_root = rails_root.join(app_name) 310 | path_set = build_path_set(app: app) 311 | create_file(app_root.join("bower.json")) 312 | 313 | cached_directories = path_set.cached_directories 314 | 315 | expect(cached_directories).to include( 316 | rails_root.join(app_name, "bower_components"), 317 | ) 318 | end 319 | end 320 | 321 | context "when bower.json does not exist" do 322 | it "does not include the path to bower_components" do 323 | app_name = "foo" 324 | app = build_app(name: app_name) 325 | path_set = build_path_set(app: app) 326 | 327 | cached_directories = path_set.cached_directories 328 | 329 | expect(cached_directories).not_to include(nil) 330 | expect(cached_directories).not_to include( 331 | rails_root.join(app_name, "bower_components"), 332 | ) 333 | end 334 | end 335 | end 336 | 337 | def create_file(path) 338 | path.parent.mkpath 339 | FileUtils.touch(path) 340 | path 341 | end 342 | 343 | def create_executable(path) 344 | file = File.new(create_file(path)) 345 | file.chmod(0777) 346 | path 347 | end 348 | 349 | def build_app(**options) 350 | double( 351 | options.reverse_merge( 352 | name: "foo", 353 | options: {}, 354 | ), 355 | ) 356 | end 357 | 358 | def stub_which(program_to_path) 359 | allow(EmberCli::Helpers). 360 | to receive(:which). 361 | with(program_to_path.keys.first.to_s). 362 | and_return(program_to_path.values.last) 363 | end 364 | 365 | def build_path_set(**options) 366 | EmberCli::PathSet.new( 367 | **options.reverse_merge( 368 | app: build_app, 369 | rails_root: rails_root, 370 | ember_cli_root: ember_cli_root, 371 | environment: "test", 372 | ), 373 | ) 374 | end 375 | 376 | def app_root_for(app) 377 | rails_root.join(app.name) 378 | end 379 | 380 | def ember_cli_root 381 | Rails.root.join("tmp", "ember_cli").tap(&:mkpath) 382 | end 383 | 384 | def rails_root 385 | Rails.root.join("tmp", "rails").tap(&:mkpath) 386 | end 387 | 388 | def remove_temporary_directories 389 | [rails_root, ember_cli_root].each do |dir| 390 | if dir.exist? 391 | FileUtils.rm_rf(dir) 392 | end 393 | end 394 | end 395 | 396 | before do 397 | remove_temporary_directories 398 | end 399 | end 400 | -------------------------------------------------------------------------------- /spec/lib/ember_cli/runner_spec.rb: -------------------------------------------------------------------------------- 1 | require "ember_cli/runner" 2 | 3 | describe EmberCli::Runner do 4 | describe "#run!" do 5 | context "when the command fails" do 6 | it "writes output to `out` streams" do 7 | stdout = StringIO.new 8 | logfile = StringIO.new 9 | runner = EmberCli::Runner.new( 10 | err: [], 11 | out: [stdout, logfile], 12 | ) 13 | 14 | expect { runner.run!(command_with_error(out: "out")) }. 15 | to raise_error(SystemExit) 16 | 17 | expect(split_output_from_stream(stdout)).to eq(%w[out out]) 18 | expect(split_output_from_stream(logfile)).to eq(%w[out out]) 19 | end 20 | 21 | it "writes errors to `err` streams" do 22 | stderr = StringIO.new 23 | logfile = StringIO.new 24 | runner = EmberCli::Runner.new( 25 | err: [stderr, logfile], 26 | out: [], 27 | ) 28 | 29 | expect { runner.run!(command_with_error(err: "err")) }. 30 | to raise_error(SystemExit) 31 | 32 | expect(split_output_from_stream(stderr)).to eq(%w[err err]) 33 | expect(split_output_from_stream(logfile)).to eq(%w[err err]) 34 | end 35 | end 36 | 37 | it "executes the command" do 38 | out = StringIO.new 39 | err = StringIO.new 40 | runner = EmberCli::Runner.new(err: [err], out: [out]) 41 | 42 | status = runner.run!(command("out")) 43 | 44 | [err, out].each(&:rewind) 45 | 46 | expect(status).to be_success 47 | expect(split_output_from_stream(err)).to be_empty 48 | expect(split_output_from_stream(out)).to eq(%w[out]) 49 | end 50 | 51 | def split_output_from_stream(stream) 52 | stream.rewind 53 | 54 | stream.read.split 55 | end 56 | 57 | def command(output) 58 | "echo '#{output}'" 59 | end 60 | 61 | def command_with_error(out: "", err: "") 62 | [ 63 | "echo '#{out}'", 64 | "echo '#{err}' > /dev/stderr", 65 | "echo '#{out}'", 66 | "echo '#{err}' > /dev/stderr", 67 | "exit 1", 68 | ].join("; ") 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /spec/lib/ember_cli_spec.rb: -------------------------------------------------------------------------------- 1 | describe EmberCli do 2 | describe ".any?" do 3 | it "delegates to the collection of applications" do 4 | stub_apps( 5 | app_with_foo: { foo: true }, 6 | app_without_foo: { foo: false }, 7 | ) 8 | 9 | any_with_foo = EmberCli.any? { |app| app.fetch(:foo) } 10 | 11 | expect(any_with_foo).to be true 12 | end 13 | end 14 | 15 | def stub_apps(applications) 16 | allow(EmberCli).to receive(:apps).and_return(applications) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/requests/assets/my-app.js_spec.rb: -------------------------------------------------------------------------------- 1 | describe "GET assets/my-app.js" do 2 | it "responds with the 'Cache-Control' header from Rails" do 3 | build_ember_cli_assets 4 | 5 | get "/assets/my-app.js" 6 | 7 | expect(headers["Cache-Control"]).to eq(cache_for_five_minutes) 8 | end 9 | 10 | def build_ember_cli_assets 11 | EmberCli["my-app"].build 12 | end 13 | 14 | def cache_for_five_minutes 15 | Dummy::Application::CACHE_CONTROL_FIVE_MINUTES 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "codeclimate-test-reporter" 2 | CodeClimate::TestReporter.start 3 | 4 | ENV["RAILS_ENV"] = "test" 5 | 6 | require "dummy/application" 7 | require "rspec/rails" 8 | 9 | Dummy::Application.initialize! 10 | 11 | Dir["spec/support/**/*.rb"].sort.each { |file| require "./#{file}" } 12 | 13 | RSpec.configure do |config| 14 | config.expect_with :rspec do |expectations| 15 | expectations.syntax = :expect 16 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 17 | end 18 | 19 | config.mock_with :rspec do |mocks| 20 | mocks.syntax = :expect 21 | mocks.verify_partial_doubles = true 22 | end 23 | 24 | config.infer_spec_type_from_file_location! 25 | config.order = :random 26 | end 27 | -------------------------------------------------------------------------------- /spec/support/capybara.rb: -------------------------------------------------------------------------------- 1 | require "selenium/webdriver" 2 | 3 | Capybara.register_driver :headless_chrome do |app| 4 | Capybara::Selenium::Driver.new( 5 | app, 6 | browser: :chrome, 7 | options: Selenium::WebDriver::Chrome::Options.new( 8 | args: %w[--no-sandbox --headless], 9 | ), 10 | ) 11 | end 12 | 13 | Capybara.server = :webrick 14 | Capybara.javascript_driver = :headless_chrome 15 | --------------------------------------------------------------------------------