Skip to content

Commit

Permalink
Use latest EmberCLI-generated asset files
Browse files Browse the repository at this point in the history
Closes [#298]

Use Sprockets-generated manifest to detect which files are the most up
to date versions of EmberCLI-generated assets.

No longer support Sprockets-based helpers for Rails 3.2, given the
difference in how the Asset Pipeline works post-4.0.

[#298]: #298
  • Loading branch information
seanpdoyle committed Dec 3, 2015
1 parent 7dabfa5 commit 692623b
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
master
------

* Use latest EmberCLI-generated asset files. [#316]
* Delete previous build output on application boot instead of on process exit.
[#308]

[#316]: https://github.com/thoughtbot/ember-cli-rails/pull/316
[#308]: https://github.com/thoughtbot/ember-cli-rails/pull/308

0.5.6
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ In addition to rendering the EmberCLI generated `index.html`, you can inject the
<%= include_ember_stylesheet_tags :frontend %>
```

**NOTE**

These helpers are only available for Rails versions `>= 4.0`.

### Multiple Ember CLI apps

In the initializer you may specify multiple Ember CLI apps, each of which can be
Expand Down Expand Up @@ -519,10 +523,14 @@ jQuery and Handlebars are the main use cases for this flag.
This project supports:

* Ruby versions `>= 2.1.0`
* Rails `3.2.x` and `>=4.1.x`.
* Rails versions `3.2.x` and `>=4.1.x`.

[Rendering EmberCLI-generated assets through Sprockets](asset-helpers) is
**NOT** supported for Rails `3.2.x`.

To learn more about supported versions and upgrades, read the [upgrading guide].

[asset-helpers]: #rendering-the-embercli-generated-js-and-css
[upgrading guide]: /UPGRADING.md

## Contributing
Expand Down
44 changes: 37 additions & 7 deletions app/helpers/ember_rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

module EmberRailsHelper
def include_ember_index_html(name, &block)
warn <<-MSG.strip_heredoc
The `include_ember_index_html` helper has been deprecated.
Rename all invocations to `render_ember_app`
MSG
Warnings.warn_include_index_html

render_ember_app(name, &block)
end
Expand All @@ -20,10 +16,44 @@ def render_ember_app(name, &block)
end

def include_ember_script_tags(name, **options)
javascript_include_tag(*EmberCli[name].sprockets.assets, options)
Warnings.warn_asset_helper

javascript_include_tag(*EmberCli[name].sprockets.javascript_assets, options)
end

def include_ember_stylesheet_tags(name, **options)
stylesheet_link_tag(*EmberCli[name].sprockets.assets, options)
Warnings.warn_asset_helper

stylesheet_link_tag(*EmberCli[name].sprockets.stylesheet_assets, options)
end

module Warnings
def self.warn_include_index_html
warn <<-MSG.strip_heredoc
The `include_ember_index_html` helper has been deprecated.
Rename all invocations to `render_ember_app`
MSG
end

def self.warn_asset_helper
if Rails::VERSION::MAJOR < 4
warn <<-MSG.strip_heredoc
`ember-cli-rails` no longer supports Sprockets-based helpers for Rails
versions below 4.0.
Replace usage of
* `include_ember_script_tags`
* `include_ember_stylesheet_tags`
with `render_ember_app` invocations.
To learn more, please read:
* https://github.com/thoughtbot/ember-cli-rails#configuring-the-ember-controller
* https://github.com/thoughtbot/ember-cli-rails/pull/316
MSG
end
end
end
end
57 changes: 57 additions & 0 deletions lib/ember_cli/assets.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module EmberCli
class Assets
def initialize(app_name:, ember_app_name:, manifest:, prefix:)
@app_name = app_name
@ember_app_name = ember_app_name
@prefix = prefix
@manifest = manifest
end

def javascripts
if empty_manifest?
fallback_assets
else
[
latest_matching(%r{#{app_name}/assets/vendor(.*)\.js\z}),
latest_matching(%r{#{app_name}/assets/#{ember_app_name}(.*)\.js\z}),
]
end
end

def stylesheets
if empty_manifest?
fallback_assets
else
[
latest_matching(%r{#{app_name}/assets/vendor(.*)\.css\z}),
latest_matching(%r{#{app_name}/assets/#{ember_app_name}(.*)\.css\z}),
]
end
end

private

attr_reader :app_name, :ember_app_name, :manifest, :prefix

def fallback_assets
["#{app_name}/assets/vendor", "#{app_name}/assets/#{ember_app_name}"]
end

def empty_manifest?
files.empty?
end

def latest_matching(regex)
file, = files.
select { |key, _| key =~ regex }.
sort_by { |_, data| data["mtime"] }.
last

[prefix, file].join("/")
end

def files
manifest.files
end
end
end
11 changes: 11 additions & 0 deletions lib/ember_cli/missing_manifest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module EmberCli
class MissingManifest
def files
{}
end

def assets
{}
end
end
end
35 changes: 32 additions & 3 deletions lib/ember_cli/sprockets.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
require "sprockets"
require "ember_cli/errors"
require "non-stupid-digest-assets"
require "ember_cli/html_page"
require "ember_cli/missing_manifest"
require "ember_cli/assets"

module EmberCli
class Sprockets
class AssetPipelineError < BuildError; end

def initialize(app)
@app = app
end

def register!
register_or_raise!(Rails.configuration.assets.precompile)
register_or_raise!(asset_config.precompile)
register_or_raise!(NonStupidDigestAssets.whitelist)
end

Expand All @@ -24,14 +28,27 @@ def index_html(head:, body:)
html_page.render
end

def assets
["#{app.name}/assets/vendor", "#{app.name}/assets/#{ember_app_name}"]
def javascript_assets
assets.javascripts
end

def stylesheet_assets
assets.stylesheets
end

private

attr_reader :app

def assets
Assets.new(
app_name: app.name,
ember_app_name: ember_app_name,
manifest: rails_manifest,
prefix: asset_config.prefix,
)
end

def ember_app_name
@ember_app_name ||= app.options.fetch(:name) { package_json.fetch(:name) }
end
Expand All @@ -41,6 +58,18 @@ def package_json
JSON.parse(app.paths.package_json_file.read).with_indifferent_access
end

def rails_manifest
if Rails.application.respond_to?(:assets_manifest)
Rails.application.assets_manifest
else
MissingManifest.new
end
end

def asset_config
Rails.configuration.assets
end

def asset_matcher
%r{\A#{app.name}/}
end
Expand Down
10 changes: 9 additions & 1 deletion spec/lib/ember_cli/app_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
require "ember-cli-rails"

describe EmberCli::App do
describe "#compile" do
it "exits with exit status of 0" do
passed = EmberCli["my-app"].compile

expect(passed).to be true
end
end

describe "#test" do
it "exits with exit status of 0" do
passed = silence_stream(STDOUT) { EmberCli["my-app"].test }
passed = EmberCli["my-app"].test

expect(passed).to be true
end
Expand Down
103 changes: 103 additions & 0 deletions spec/lib/ember_cli/assets_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
require "ember_cli/assets"

describe EmberCli::Assets do
describe "#javascripts" do
it "includes the most recent javascript build artifacts" do
manifest = build_manifest(
files: {
"not-a-match" => {},
"foo/assets/bar-abc123.js" => { "mtime" => 1.day.ago.iso8601 },
"foo/assets/bar-def456.js" => { "mtime" => 2.days.ago.iso8601 },
"foo/assets/vendor-def456.js" => { "mtime" => 2.days.ago.iso8601 },
"foo/assets/vendor-abc123.js" => { "mtime" => 1.day.ago.iso8601 },
},
)
assets = build_assets(
app_name: "foo",
ember_app_name: "bar",
manifest: manifest,
prefix: "assets",
)

javascripts = assets.javascripts

expect(javascripts).to match_array([
"assets/foo/assets/bar-abc123.js",
"assets/foo/assets/vendor-abc123.js",
])
end

context "when the manifest is empty" do
it "falls back to the default assets" do
assets = build_assets(
manifest: build_empty_manifest,
app_name: "foo",
ember_app_name: "bar",
)

javascripts = assets.javascripts

expect(javascripts).to match_array([
"foo/assets/vendor",
"foo/assets/bar",
])
end
end
end

describe "#stylesheets" do
it "includes the most recent stylesheet build artifacts" do
manifest = build_manifest(
files: {
"not-a-match" => {},
"foo/assets/bar-def456.css" => { "mtime" => 2.days.ago.iso8601 },
"foo/assets/bar-abc123.css" => { "mtime" => 1.day.ago.iso8601 },
"foo/assets/vendor-abc123.css" => { "mtime" => 1.day.ago.iso8601 },
"foo/assets/vendor-def456.css" => { "mtime" => 2.days.ago.iso8601 },
},
)
assets = build_assets(
app_name: "foo",
ember_app_name: "bar",
manifest: manifest,
prefix: "assets",
)

stylesheets = assets.stylesheets

expect(stylesheets).to match_array([
"assets/foo/assets/bar-abc123.css",
"assets/foo/assets/vendor-abc123.css",
])
end

context "when the manifest is empty" do
it "falls back to the default assets" do
assets = build_assets(
manifest: build_empty_manifest,
app_name: "foo",
ember_app_name: "bar",
)

stylesheets = assets.stylesheets

expect(stylesheets).to match_array([
"foo/assets/vendor",
"foo/assets/bar",
])
end
end
end
end

def build_assets(manifest: build_manifest, prefix: "assets", **options)
EmberCli::Assets.new(options.merge(manifest: manifest, prefix: prefix))
end

def build_manifest(files: {})
double(files: files)
end

def build_empty_manifest
build_manifest
end

0 comments on commit 692623b

Please sign in to comment.