Skip to content

Commit

Permalink
Merge EmberCLI-generated Manifest with Sprockets'
Browse files Browse the repository at this point in the history
Closes [#298]

Expose Ember's fingerprinted assets to Sprockets.

[#298]: #298
  • Loading branch information
seanpdoyle committed Dec 1, 2015
1 parent 14775a5 commit 1e786b2
Show file tree
Hide file tree
Showing 11 changed files with 366 additions and 5 deletions.
4 changes: 2 additions & 2 deletions app/helpers/ember_rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ def render_ember_app(name, &block)
end

def include_ember_script_tags(name, **options)
javascript_include_tag(*EmberCli[name].sprockets.assets, options)
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)
stylesheet_link_tag(*EmberCli[name].sprockets.stylesheet_assets, options)
end
end
1 change: 0 additions & 1 deletion gemfiles/3.2.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
source "https://rubygems.org"

gem "appraisal"
gem "test-unit", "~> 3.0"
gem "rails", :git => "https://github.com/rails/rails.git", :branch => "3-2-stable"
gem "pry"

Expand Down
2 changes: 2 additions & 0 deletions lib/ember_cli/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def compile
@shell.compile
@build.check!
copy_index_html_file
sprockets.update_manifest!
true
end
end
Expand Down Expand Up @@ -82,6 +83,7 @@ def build_and_watch
prepare
@shell.build_and_watch
copy_index_html_file
sprockets.update_manifest!
end

def prepare
Expand Down
97 changes: 97 additions & 0 deletions lib/ember_cli/assets.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
module EmberCli
class Assets
def initialize(app_name:, ember_app_name:, manifest:)
@app_name = app_name
@ember_app_name = ember_app_name
@manifest = manifest
end

def javascripts
if empty_manifest?
fallback_assets
else
[latest_vendor_js, latest_app_js]
end
end

def stylesheets
if empty_manifest?
fallback_assets
else
[latest_vendor_css, latest_app_css]
end
end

private

attr_reader :app_name, :ember_app_name, :environment, :manifest

def vendor_js_files
regex = %r{#{app_name}/assets/vendor(.*)\.js\z}
files.select { |key| key =~ regex }
end

def latest_vendor_js
asset_name, _ = vendor_js_files.
sort_by { |_, data| data["mtime"] }.
reverse.
first

asset_name
end

def app_js_files
regex = %r{#{app_name}/assets/#{ember_app_name}(.*)\.js\z}
files.select { |key| key =~ regex }
end

def latest_app_js
asset_name, _ = app_js_files.
sort_by { |_, data| data["mtime"] }.
reverse.
first

asset_name
end

def vendor_css_files
regex = %r{#{app_name}/assets/vendor(.*)\.css\z}
files.select { |key| key =~ regex }
end

def latest_vendor_css
asset_name, _ = vendor_css_files.
sort_by { |_, data| data["mtime"] }.
reverse.
first

asset_name
end

def app_css_files
regex = %r{#{app_name}/assets/#{ember_app_name}(.*)\.css\z}
files.select { |key| key =~ regex }
end

def latest_app_css
asset_name, _ = app_css_files.
sort_by { |_, data| data["mtime"] }.
reverse.
first

asset_name
end

def files
manifest.files
end

def empty_manifest?
files.empty?
end

def fallback_assets
["#{app_name}/assets/vendor", "#{app_name}/assets/#{ember_app_name}"]
end
end
end
14 changes: 14 additions & 0 deletions lib/ember_cli/manifest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require "sprockets"

module EmberCli
class Manifest
def initialize(environment, path)
@manifest = ::Sprockets::Manifest.new(environment, path)
end

def merge_into!(other)
other.assets.merge!(@manifest.assets)
other.files.merge!(@manifest.files)
end
end
end
8 changes: 8 additions & 0 deletions lib/ember_cli/path_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ def build_error_file
@build_error_file ||= tmp.join("error.txt")
end

def manifest
manifests.first
end

def bower
@bower ||= begin
bower_path = app_options.fetch(:bower_path) { configuration.bower_path }
Expand Down Expand Up @@ -109,6 +113,10 @@ def bundler

delegate :name, :options, to: :app, prefix: true

def manifests
Pathname.glob(app_assets.join("assets", "manifest*.json"))
end

def default_root
rails_root.join(app_name)
end
Expand Down
30 changes: 28 additions & 2 deletions lib/ember_cli/sprockets.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require "ember_cli/errors"
require "non-stupid-digest-assets"
require "ember_cli/html_page"
require "ember_cli/manifest"
require "ember_cli/assets"

module EmberCli
class Sprockets
Expand All @@ -14,6 +16,10 @@ def register!
register_or_raise!(NonStupidDigestAssets.whitelist)
end

def update_manifest!
ember_manifest.merge_into!(rails_manifest)
end

def index_html(head:, body:)
html_page = HtmlPage.new(
content: app.index_file.read,
Expand All @@ -24,14 +30,26 @@ 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,
)
end

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

def ember_manifest
@ember_manifest ||= Manifest.new(Rails.env, app.paths.manifest)
end

def rails_manifest
Rails.application.assets_manifest
end

def asset_matcher
%r{\A#{app.name}/}
end
Expand Down
125 changes: 125 additions & 0 deletions spec/lib/ember_cli/assets_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
require "ember_cli/assets"

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

javascripts = assets.javascripts

expect(javascripts).to match_array([
"foo/assets/bar-abc123.js",
"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: {
"foo/assets/bar-abc123.css" => {
"logical_path" => "vendor.css",
"mtime" => 1.day.ago.iso8601,
},
"foo/assets/bar-def456.css" => {
"logical_path" => "vendor.css",
"mtime" => 2.days.ago.iso8601,
},
"foo/assets/vendor-abc123.css" => {
"logical_path" => "vendor.css",
"mtime" => 1.day.ago.iso8601,
},
"foo/assets/vendor-def456.css" => {
"logical_path" => "vendor.css",
"mtime" => 2.days.ago.iso8601,
},
"not-a-match" => {},
}
)
assets = build_assets(
app_name: "foo",
ember_app_name: "bar",
manifest: manifest,
)

stylesheets = assets.stylesheets

expect(stylesheets).to match_array([
"foo/assets/bar-abc123.css",
"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, **options)
EmberCli::Assets.new(options.merge(manifest: manifest))
end

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

def build_empty_manifest
build_manifest
end
31 changes: 31 additions & 0 deletions spec/lib/ember_cli/manifest_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require "ember_cli/manifest"

describe EmberCli::Manifest do
describe "#merge_into!" do
it "merges the manifest into the provided manifest" do
manifest_file = create_json_file(
"assets" => {
"asset" => "path/to/asset.js",
},
"files" => {
"file" => "path/to/file.js",
},
)
manifest = EmberCli::Manifest.new("test", manifest_file.path)
rails_manifest = OpenStruct.new(assets: {}, files: {})

manifest.merge_into!(rails_manifest)

expect(rails_manifest.assets).to eq("asset" => "path/to/asset.js")
expect(rails_manifest.files).to eq("file" => "path/to/file.js")
end
end

def create_json_file(json)
tempfile = Tempfile.new("json")
tempfile.write(JSON.dump(json))
tempfile.close

tempfile
end
end
Loading

0 comments on commit 1e786b2

Please sign in to comment.