diff --git a/AssetFile b/AssetFile index a16da069..e94097df 100644 --- a/AssetFile +++ b/AssetFile @@ -1,25 +1,18 @@ $: << 'lib' require 'rake-pipeline-web-filters' -require 'rake-pipeline/travis' +require 'travis/assets' require 'compass' -ROOTS ||= [Pathname.new(File.expand_path('.'))] - -paths = %w(styles scripts images static vendor).inject({}) do |paths, type| - paths.merge(type.to_sym => ROOTS.map { |root| root.join("assets/#{type}").to_s }) -end - -Compass.configuration.images_path = paths[:images].first -Compass.configuration.add_import_path paths[:styles].first - -Travis::Version.update +assets ||= Travis::Assets.new +assets.setup_compass +assets.update_version output 'public/scripts' -input paths[:scripts] do +input assets.scripts do match '**/*.hbs' do - travis_handlebars - concat 'app/templates.js' + handlebars :precompile => assets.production? + concat 'templates.js' end match '**/*.coffee' do @@ -27,38 +20,29 @@ input paths[:scripts] do end match 'vendor/**/*.js' do - precedence = %w(jquery.min minispade handlebars ember).map { |name| "vendor/#{name}.js" } - safe_concat precedence, 'vendor.js' + safe_concat assets.vendor_order, 'vendor.js' + end + + match %r(^(?!vendor).*\.js$) do + modules = proc { |input| input.path.gsub(%r((^app/|lib/|\.js$)), '') } + minispade(string: assets.development?, rewrite_requires: true, module_id_generator: modules) end match '**/*.js' do - copy { |path| ["dev/#{path}", "min/#{path}"] } + concat ['vendor.js'], ['app.js', 'min/app.js'] end - match %r(^dev/(?!vendor).*\.js$) do - modules = proc { |input| input.path.gsub(%r((^dev/|app/|lib/|\.js$)), '') } - minispade(string: true, rewrite_requires: true, module_id_generator: modules) - end - - match 'dev/**/*.js' do - concat ['dev/vendor.js'], 'app.js' - end - - match %r(^min/(?!vendor).*\.js$) do - modules = proc { |input| input.path.gsub(%r((^min/|app/|lib/|\.js$)), '') } - minispade(string: false, rewrite_requires: true, module_id_generator: modules) - end - - match 'min/**/*.js' do - concat ['min/vendor.js'], 'min/app.js' - strip_debug - uglify squeeze: true, max_line_length: 200 - copy 'app.min.js' + if assets.production? + match 'min/app.js' do + strip_debug + uglify squeeze: true + concat 'app.min.js' + end end end output 'public/styles' -input paths[:styles] do +input assets.styles do match '**/*.{scss,sass}' do sass concat [], 'app.css' @@ -66,7 +50,7 @@ input paths[:styles] do end output 'public/images' -input paths[:images] do +input assets.images do skip %r(^ui/) match '**/*' do copy @@ -74,7 +58,7 @@ input paths[:images] do end output 'public' -input paths[:static] do +input assets.static do match '**/*' do copy end diff --git a/Gemfile b/Gemfile index c268bbb0..61b908bb 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,7 @@ group :development do gem 'newrelic_rpm', '~> 3.3.0' gem 'hubble', github: 'roidrage/hubble' - gem 'rake-pipeline', github: 'livingsocial/rake-pipeline' + gem 'rake-pipeline', github: 'livingsocial/rake-pipeline', ref: '3465e0e3e1' gem 'rake-pipeline-web-filters', github: 'wycats/rake-pipeline-web-filters' gem 'coffee-script' diff --git a/Gemfile.lock b/Gemfile.lock index 0c5bd3b9..005a437b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,9 @@ GIT remote: git://github.com/livingsocial/rake-pipeline.git - revision: 3914452278165b7eb3a79071d3b63b46fee59a2f + revision: 3465e0e3e134bf52ddf5d138e8c8262412080095 + ref: 3465e0e3e1 specs: rake-pipeline (0.6.0) - json rake (~> 0.9.0) thor diff --git a/README.md b/README.md index 84fe0745..8e8c30b8 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This is a static html/js app so you shouldn't need to install anything. Running locally with a local API server: - bundle exec rackup + RUN_API=1 bundle exec rackup -p 3000 Running against existing API endpoint: @@ -24,6 +24,7 @@ Run locally, one on `ci.dev` and one on `api.dev`: ### Compiling assets manually bundle exec rakep + ENV=production bundle exec rakep ### Compiling assets on change diff --git a/lib/guard/assets.rb b/lib/guard/assets.rb index 74df3679..de7c67ac 100644 --- a/lib/guard/assets.rb +++ b/lib/guard/assets.rb @@ -26,7 +26,10 @@ module Guard private def run + started = Time.now + print 'Compiling ... ' system 'bundle exec rakep' + puts "done (#{(Time.now - started).round(2)}s)." end end end diff --git a/lib/rake-pipeline/travis.rb b/lib/rake-pipeline/travis.rb deleted file mode 100644 index 21a9ef13..00000000 --- a/lib/rake-pipeline/travis.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'rake-pipeline' - -module Rake::Pipeline::Travis - autoload :Filters, 'rake-pipeline/travis/filters' - autoload :Helpers, 'rake-pipeline/travis/helpers' - autoload :Version, 'rake-pipeline/travis/version' -end - -Rake::Pipeline::DSL::PipelineDSL.send(:include, Rake::Pipeline::Travis::Helpers) diff --git a/lib/rake-pipeline/travis/version.rb b/lib/rake-pipeline/travis/version.rb deleted file mode 100644 index 386a6f28..00000000 --- a/lib/rake-pipeline/travis/version.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'pathname' -require 'digest/md5' - -module Rake::Pipeline::Travis - class Version - FILE_NAME = 'public/version' - SOURCES = %w(AssetFile Gemfile.lock assets) - - def self.update - new.update - end - - attr_reader :root - - def initialize(root = nil) - @root = Pathname.new(root || File.expand_path('.')) - end - - def read - file.read - end - - def update - @hash = nil - write(hash) - hash - end - - protected - - def file - root.join(FILE_NAME) - end - - def write(version) - file.open('w+') { |f| f.write(version) } - end - - def hash - @hash ||= digest.to_s[0..7] - end - - def digest - Digest::MD5.new << `ls -lAR #{sources.join(' ')} | awk '{print $5, $6, $7, $9}'` - end - - def sources - SOURCES.map do |source| - source = root.join(source) - source.to_s if source.exist? - end.compact - end - end -end diff --git a/lib/travis/assets.rb b/lib/travis/assets.rb new file mode 100644 index 00000000..5f8e3358 --- /dev/null +++ b/lib/travis/assets.rb @@ -0,0 +1,52 @@ +require 'rake-pipeline' + +module Travis + class Assets + autoload :Filters, 'travis/assets/filters' + autoload :Helpers, 'travis/assets/helpers' + autoload :Version, 'travis/assets/version' + + TYPES = [:styles, :scripts, :images, :static, :vendor] + VENDOR_ORDER = %w(jquery.min minispade handlebars ember) + + attr_reader :roots, :env + + def initialize(roots = '.') + @roots = Array(roots).map { |root| Pathname.new(File.expand_path(root)) } + @env = ENV['ENV'] + end + + def production? + env == 'production' + end + + def development? + !production? + end + + def vendor_order + VENDOR_ORDER.map { |name| "vendor/#{name}.js" } + end + + def setup_compass + Compass.configuration.images_path = images.first + styles.each do |path| + Compass.configuration.add_import_path(path) + end + end + + def update_version + Travis::Assets::Version.new.update + end + + TYPES.each { |type| define_method(type) { paths[type] } } + + def paths + @paths ||= TYPES.inject({}) do |paths, type| + paths.merge(type.to_sym => roots.map { |root| root.join("assets/#{type}").to_s }) + end + end + end +end + +Rake::Pipeline::DSL::PipelineDSL.send(:include, Travis::Assets::Helpers) diff --git a/lib/rake-pipeline/travis/filters.rb b/lib/travis/assets/filters.rb similarity index 71% rename from lib/rake-pipeline/travis/filters.rb rename to lib/travis/assets/filters.rb index 200b66b1..f07c08be 100644 --- a/lib/rake-pipeline/travis/filters.rb +++ b/lib/travis/assets/filters.rb @@ -1,19 +1,18 @@ require 'rake-pipeline' - require 'execjs' require 'uglifier' require 'pathname' -class Rake::Pipeline - module Travis +module Travis + class Assets module Filters - class Drop < Matcher + class Drop < Rake::Pipeline::Matcher def output_files input_files.reject { |f| f.path =~ @pattern } end end - class Handlebars < Filter + class Handlebars < Rake::Pipeline::Filter class << self def source [ @@ -30,22 +29,35 @@ class Rake::Pipeline def context @@context ||= ExecJS.compile(source) end + end - def compile(source) - context.call('compileHandlebarsTemplate', source + "\n") - end + attr_reader :options + + def initialize(*args, &block) + @options = args.last.is_a?(Hash) ? args.pop : {} + super end def generate_output(inputs, output) inputs.each do |input| - source = self.class.compile(input.read) + source = input.read + source = options[:precompile] ? compile(source) : escape(source) source = wrap(name(input.path), source) output.write source end end + def compile(source) + self.class.context.call('compileHandlebarsTemplate', source + "\n") + end + + def escape(source) + source.to_json + end + def wrap(name, source) - "\nEmber.TEMPLATES['#{name}'] = Ember.Handlebars.template(#{source});\n" + method = options[:precompile] ? 'template' : 'compile' + "\nEmber.TEMPLATES['#{name}'] = Ember.Handlebars.#{method}(#{source});\n" end def name(path) @@ -53,7 +65,7 @@ class Rake::Pipeline end end - class SafeConcat < ConcatFilter + class SafeConcat < Rake::Pipeline::ConcatFilter def generate_output(inputs, output) inputs.each do |input| output.write File.read(input.fullpath) + ";" @@ -76,7 +88,7 @@ class Rake::Pipeline end end - class StripDebug < Filter + class StripDebug < Rake::Pipeline::Filter def generate_output(inputs, output) inputs.each do |input| source = File.read(input.fullpath) diff --git a/lib/rake-pipeline/travis/helpers.rb b/lib/travis/assets/helpers.rb similarity index 89% rename from lib/rake-pipeline/travis/helpers.rb rename to lib/travis/assets/helpers.rb index bb13918c..b4ea4517 100644 --- a/lib/rake-pipeline/travis/helpers.rb +++ b/lib/travis/assets/helpers.rb @@ -1,9 +1,9 @@ require 'rake-pipeline/dsl' -class Rake::Pipeline - module Travis +module Travis + class Assets module Helpers - def travis_handlebars(*args, &block) + def handlebars(*args, &block) filter(Filters::Handlebars, *args, &block) end diff --git a/lib/travis/assets/version.rb b/lib/travis/assets/version.rb new file mode 100644 index 00000000..616d1f81 --- /dev/null +++ b/lib/travis/assets/version.rb @@ -0,0 +1,56 @@ +require 'pathname' +require 'digest/md5' + +module Travis + class Assets + class Version + FILE_NAME = 'public/version' + SOURCES = %w(AssetFile Gemfile.lock assets) + + def self.update + new.update + end + + attr_reader :root + + def initialize(root = nil) + @root = Pathname.new(root || File.expand_path('.')) + end + + def read + file.read + end + + def update + @hash = nil + write(hash) + hash + end + + protected + + def file + root.join(FILE_NAME) + end + + def write(version) + file.open('w+') { |f| f.write(version) } + end + + def hash + @hash ||= digest.to_s[0..7] + end + + def digest + Digest::MD5.new << `ls -lAR #{sources.join(' ')} | awk '{print $5, $6, $7, $9}'` + end + + def sources + SOURCES.map do |source| + source = root.join(source) + source.to_s if source.exist? + end.compact + end + end + end +end diff --git a/public/scripts/app.js b/public/scripts/app.js index a2fe9d22..4409f633 100644 --- a/public/scripts/app.js +++ b/public/scripts/app.js @@ -29619,4 +29619,5248 @@ var _require=function(){function c(a,c){document.addEventListener?a.addEventList ++g&&setTimeout(c,0)})}}(); (function(){!window.WebSocket&&window.MozWebSocket&&(window.WebSocket=window.MozWebSocket);if(window.WebSocket)Pusher.Transport=window.WebSocket,Pusher.TransportType="native";var c=(document.location.protocol=="http:"?Pusher.cdn_http:Pusher.cdn_https)+Pusher.VERSION,a=[];window.JSON||a.push(c+"/json2"+Pusher.dependency_suffix+".js");if(!window.WebSocket)window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION=!0,a.push(c+"/flashfallback"+Pusher.dependency_suffix+".js");var b=function(){return window.WebSocket?function(){Pusher.ready()}: function(){window.WebSocket?(Pusher.Transport=window.WebSocket,Pusher.TransportType="flash",window.WEB_SOCKET_SWF_LOCATION=c+"/WebSocketMain.swf",WebSocket.__addTask(function(){Pusher.ready()}),WebSocket.__initialize()):(Pusher.Transport=null,Pusher.TransportType="none",Pusher.ready())}}(),e=function(a){var b=function(){document.body?a():setTimeout(b,0)};b()},g=function(){e(b)};a.length>0?_require(a,g):g()})(); -;minispade.register('app', "(function() {(function() {\nminispade.require('auth');\nminispade.require('controllers');\nminispade.require('helpers');\nminispade.require('models');\nminispade.require('pusher');\nminispade.require('routes');\nminispade.require('slider');\nminispade.require('store');\nminispade.require('tailing');\nminispade.require('templates');\nminispade.require('views');\nminispade.require('config/locales');\nminispade.require('data/sponsors');\n\n Travis.reopen({\n App: Em.Application.extend({\n autoinit: false,\n currentUserBinding: 'auth.user',\n authStateBinding: 'auth.state',\n init: function() {\n this._super.apply(this, arguments);\n this.store = Travis.Store.create();\n this.store.loadMany(Travis.Sponsor, Travis.SPONSORS);\n this.set('auth', Travis.Auth.create({\n store: this.store,\n endpoint: Travis.config.api_endpoint\n }));\n this.slider = new Travis.Slider();\n this.pusher = new Travis.Pusher(Travis.config.pusher);\n return this.tailing = new Travis.Tailing();\n },\n signIn: function() {\n return this.get('auth').signIn();\n },\n signOut: function() {\n this.get('auth').signOut();\n return this.get('router').send('goToRoot');\n },\n receive: function() {\n return this.store.receive.apply(this.store, arguments);\n },\n toggleSidebar: function() {\n var element;\n $('body').toggleClass('maximized');\n element = $('');\n $('#top .profile').append(element);\n Em.run.later((function() {\n return element.remove();\n }), 10);\n element = $('');\n $('#repository').append(element);\n return Em.run.later((function() {\n return element.remove();\n }), 10);\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=app");minispade.register('auth', "(function() {(function() {\n\n this.Travis.Auth = Ember.Object.extend({\n iframe: $('