From eb367afeed2905d1036f46940aa6c91323f7faab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 24 Sep 2011 01:56:49 +0200 Subject: [PATCH] `rake assets:precompile` loads the application but does not initialize it. To the app developer, this means configuration add in config/initializers/* will not be executed. Plugins developers need to special case their initializers that are meant to be run in the assets group by adding :group => :assets. Conflicts: railties/CHANGELOG railties/test/application/assets_test.rb --- actionpack/lib/sprockets/assets.rake | 3 +- actionpack/lib/sprockets/bootstrap.rb | 65 ++++++++++++ actionpack/lib/sprockets/railtie.rb | 59 +---------- railties/CHANGELOG | 12 +++ railties/lib/rails/application.rb | 5 +- railties/lib/rails/application/bootstrap.rb | 16 +-- railties/lib/rails/engine.rb | 4 +- railties/lib/rails/initializable.rb | 8 +- railties/test/application/assets_test.rb | 110 +++++++++++++------- railties/test/initializable_test.rb | 2 +- railties/test/isolation/abstract_unit.rb | 9 ++ 11 files changed, 183 insertions(+), 110 deletions(-) create mode 100644 actionpack/lib/sprockets/bootstrap.rb diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 7241671db0155..5dd48fea9869a 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -11,8 +11,9 @@ namespace :assets do ENV["RAILS_ENV"] ||= "production" Kernel.exec $0, *ARGV else - Rake::Task["environment"].invoke Rake::Task["tmp:cache:clear"].invoke + Rails.application.initialize!(:assets) + Sprockets::Bootstrap.new(Rails.application).run # Ensure that action view is loaded and the appropriate sprockets hooks get executed ActionView::Base diff --git a/actionpack/lib/sprockets/bootstrap.rb b/actionpack/lib/sprockets/bootstrap.rb new file mode 100644 index 0000000000000..ed1ed09374b5e --- /dev/null +++ b/actionpack/lib/sprockets/bootstrap.rb @@ -0,0 +1,65 @@ +module Sprockets + class Bootstrap + def initialize(app) + @app = app + end + + # TODO: Get rid of config.assets.enabled + def run + app, config = @app, @app.config + return unless app.assets + + config.assets.paths.each { |path| app.assets.append_path(path) } + + if config.assets.compress + # temporarily hardcode default JS compressor to uglify. Soon, it will work + # the same as SCSS, where a default plugin sets the default. + unless config.assets.js_compressor == false + app.assets.js_compressor = LazyCompressor.new { expand_js_compressor(config.assets.js_compressor || :uglifier) } + end + + unless config.assets.css_compressor == false + app.assets.css_compressor = LazyCompressor.new { expand_css_compressor(config.assets.css_compressor) } + end + end + + if config.assets.compile + app.routes.prepend do + mount app.assets => config.assets.prefix + end + end + + if config.assets.digest + app.assets = app.assets.index + end + end + + protected + + def expand_js_compressor(sym) + case sym + when :closure + require 'closure-compiler' + Closure::Compiler.new + when :uglifier + require 'uglifier' + Uglifier.new + when :yui + require 'yui/compressor' + YUI::JavaScriptCompressor.new + else + sym + end + end + + def expand_css_compressor(sym) + case sym + when :yui + require 'yui/compressor' + YUI::CssCompressor.new + else + sym + end + end + end +end \ No newline at end of file diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 9b31604dbec52..edcd4c1113a1c 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -1,5 +1,6 @@ module Sprockets - autoload :Helpers, "sprockets/helpers" + autoload :Bootstrap, "sprockets/bootstrap" + autoload :Helpers, "sprockets/helpers" autoload :LazyCompressor, "sprockets/compressors" autoload :NullCompressor, "sprockets/compressors" autoload :StaticCompiler, "sprockets/static_compiler" @@ -12,7 +13,7 @@ class Railtie < ::Rails::Railtie load "sprockets/assets.rake" end - initializer "sprockets.environment" do |app| + initializer "sprockets.environment", :group => :assets do |app| config = app.config next unless config.assets.enabled @@ -51,59 +52,7 @@ class Railtie < ::Rails::Railtie # are compiled, and so that other Railties have an opportunity to # register compressors. config.after_initialize do |app| - next unless app.assets - config = app.config - - config.assets.paths.each { |path| app.assets.append_path(path) } - - if config.assets.compress - # temporarily hardcode default JS compressor to uglify. Soon, it will work - # the same as SCSS, where a default plugin sets the default. - unless config.assets.js_compressor == false - app.assets.js_compressor = LazyCompressor.new { expand_js_compressor(config.assets.js_compressor || :uglifier) } - end - - unless config.assets.css_compressor == false - app.assets.css_compressor = LazyCompressor.new { expand_css_compressor(config.assets.css_compressor) } - end - end - - if config.assets.compile - app.routes.prepend do - mount app.assets => config.assets.prefix - end - end - - if config.assets.digest - app.assets = app.assets.index - end + Sprockets::Bootstrap.new(app).run end - - protected - def expand_js_compressor(sym) - case sym - when :closure - require 'closure-compiler' - Closure::Compiler.new - when :uglifier - require 'uglifier' - Uglifier.new - when :yui - require 'yui/compressor' - YUI::JavaScriptCompressor.new - else - sym - end - end - - def expand_css_compressor(sym) - case sym - when :yui - require 'yui/compressor' - YUI::CssCompressor.new - else - sym - end - end end end diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 72e5921d6d422..54eef0473cf8f 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -10,6 +10,18 @@ * Removed old 'config.paths.app.controller' API in favor of 'config.paths["app/controller"]' API. [Guillermo Iguaran] + +*Rails 3.1.1 + +* `rake assets:precompile` loads the application but does not initialize it. + + To the app developer, this means configuration add in + config/initializers/* will not be executed. + + Plugins developers need to special case their initializers that are + meant to be run in the assets group by adding :group => :assets. + + *Rails 3.1.0 (August 30, 2011)* * The default database schema file is written as UTF-8. [Aaron Patterson] diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 528c96ef3ee43..90d7d27af1fee 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -83,7 +83,6 @@ def require_environment! #:nodoc: require environment if environment end - def reload_routes! routes_reloader.reload! end @@ -92,9 +91,9 @@ def routes_reloader @routes_reloader ||= RoutesReloader.new end - def initialize! + def initialize!(group=nil) raise "Application has been already initialized." if @initialized - run_initializers(self) + run_initializers(group, self) @initialized = true self end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index c9b147d0754ff..0aff05b681b79 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -7,21 +7,21 @@ class Application module Bootstrap include Initializable - initializer :load_environment_hook do end + initializer :load_environment_hook, :group => :all do end - initializer :load_active_support do + initializer :load_active_support, :group => :all do require "active_support/all" unless config.active_support.bare end # Preload all frameworks specified by the Configuration#frameworks. # Used by Passenger to ensure everything's loaded before forking and # to avoid autoload race conditions in JRuby. - initializer :preload_frameworks do + initializer :preload_frameworks, :group => :all do ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks end # Initialize the logger early in the stack in case we need to log some deprecation. - initializer :initialize_logger do + initializer :initialize_logger, :group => :all do Rails.logger ||= config.logger || begin path = config.paths["log"].first logger = ActiveSupport::BufferedLogger.new(path) @@ -41,7 +41,7 @@ module Bootstrap end # Initialize cache early in the stack so railties can make use of it. - initializer :initialize_cache do + initializer :initialize_cache, :group => :all do unless defined?(RAILS_CACHE) silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(config.cache_store) } @@ -51,7 +51,7 @@ module Bootstrap end end - initializer :set_clear_dependencies_hook do + initializer :set_clear_dependencies_hook, :group => :all do ActionDispatch::Reloader.to_cleanup do ActiveSupport::DescendantsTracker.clear ActiveSupport::Dependencies.clear @@ -60,11 +60,11 @@ module Bootstrap # Sets the dependency loading mechanism. # TODO: Remove files from the $" and always use require. - initializer :initialize_dependency_mechanism do + initializer :initialize_dependency_mechanism, :group => :all do ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load end - initializer :bootstrap_hook do |app| + initializer :bootstrap_hook, :group => :all do |app| ActiveSupport.run_load_hooks(:before_initialize, app) end end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 89b151beb668d..0e1e719596688 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -537,12 +537,12 @@ def load_seed end end - initializer :load_environment_config, :before => :load_environment_hook do + initializer :load_environment_config, :before => :load_environment_hook, :group => :all do environment = paths["config/environments"].existent.first require environment if environment end - initializer :append_assets_path do |app| + initializer :append_assets_path, :group => :assets do |app| app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories) app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories) app.config.assets.paths.unshift(*paths["app/assets"].existent_directories) diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 686a2dc0cbc28..4c1da0a5a5684 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -21,6 +21,10 @@ def after @options[:after] end + def belongs_to?(group) + @options[:group] == group || @options[:group] == :all + end + def run(*args) @context.instance_exec(*args, &block) end @@ -44,10 +48,10 @@ def +(other) end end - def run_initializers(*args) + def run_initializers(group=nil, *args) return if instance_variable_defined?(:@ran) initializers.tsort.each do |initializer| - initializer.run(*args) + initializer.run(*args) if group.nil? || initializer.belongs_to?(group) end @ran = true end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index c4a24f0f73c9f..fb570d8f472ac 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -21,6 +21,12 @@ def app @app ||= Rails.application end + def precompile! + capture(:stdout) do + Dir.chdir(app_path){ `bundle exec rake assets:precompile` } + end + end + test "assets routes have higher priority" do app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" @@ -38,7 +44,7 @@ def app test "assets do not require compressors until it is used" do app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" - app_file "config/initializers/compile.rb", "Rails.application.config.assets.compile = true" + add_to_env_config "production", "config.assets.compile = true" ENV["RAILS_ENV"] = "production" require "#{app_path}/config/environment" @@ -54,9 +60,8 @@ def app app_file "app/assets/javascripts/foo/application.js", "alert();" ENV["RAILS_ENV"] = nil - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! + files = Dir["#{app_path}/public/assets/application-*.js"] files << Dir["#{app_path}/public/assets/foo/application-*.js"].first files.each do |file| @@ -80,13 +85,12 @@ def app "happy.happy.face.png", "happy", "happy.face", "-happyface", "-happy.png", "-happy.face.png", "_happyface", "_happy.face.png", "_happy.png"] + images_should_compile.each do |filename| app_file "app/assets/images/#{filename}", "happy" end - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! images_should_compile.each do |filename| assert File.exists?("#{app_path}/public/assets/#{filename}") @@ -103,11 +107,12 @@ def app end test "precompile sets flag notifying rails its precompiling" do - compile = < :assets do + raise "ENV RAILS_ASSETS_PRECOMPILE not set" unless ENV["RAILS_ASSETS_PRECOMPILE"] + end + RUBY + precompile! assert $?.success? end @@ -127,9 +132,7 @@ def app # digest is default in false, we must enable it for test environment add_to_config "config.assets.digest = true" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! manifest = "#{app_path}/public/assets/manifest.yml" @@ -146,9 +149,7 @@ def app add_to_config "config.assets.manifest = '#{app_path}/shared'" FileUtils.mkdir "#{app_path}/shared" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! manifest = "#{app_path}/shared/manifest.yml" @@ -164,9 +165,7 @@ def app add_to_config "config.assets.digest = true" add_to_config "config.assets.prefix = '/x'" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! manifest = "#{app_path}/public/x/manifest.yml" assets = YAML.load_file(manifest) @@ -178,9 +177,7 @@ def app app_file "app/assets/javascripts/application.js", "alert();" add_to_config "config.assets.digest = false" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! assert File.exists?("#{app_path}/public/assets/application.js") assert File.exists?("#{app_path}/public/assets/application.css") @@ -194,12 +191,11 @@ def app test "assets do not require any assets group gem when manifest file is present" do app_file "app/assets/javascripts/application.js", "alert();" - app_file "config/initializers/serve_static_assets.rb", "Rails.application.config.serve_static_assets = true" + add_to_env_config "production", "config.serve_static_assets = true" ENV["RAILS_ENV"] = "production" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! + manifest = "#{app_path}/public/assets/manifest.yml" assets = YAML.load_file(manifest) asset_path = assets["application.js"] @@ -223,9 +219,7 @@ def app RUBY ENV["RAILS_ENV"] = "production" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! # Create file after of precompile app_file "app/assets/javascripts/app.js", "alert();" @@ -249,9 +243,7 @@ class ::PostsController < ActionController::Base ; end RUBY ENV["RAILS_ENV"] = "development" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + precompile! # Create file after of precompile app_file "app/assets/javascripts/app.js", "alert();" @@ -292,10 +284,7 @@ class ::PostsController < ActionController::Base ; end app_file "app/assets/images/レイルズ.png", "not a image really" add_to_config "config.assets.precompile = [ /\.png$$/, /application.(css|js)$/ ]" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end - + precompile! assert File.exists?("#{app_path}/public/assets/レイルズ.png") manifest = "#{app_path}/public/assets/manifest.yml" @@ -367,5 +356,50 @@ def index assert_match "alert();", last_response.body assert_equal 200, last_response.status end + + test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do + app_with_assets_in_view + + # config.assets.debug and config.assets.compile are false for production environment + ENV["RAILS_ENV"] = "production" + precompile! + + require "#{app_path}/config/environment" + + class ::PostsController < ActionController::Base ; end + + # the debug_assets params isn't used if compile is off + get '/posts?debug_assets=true' + assert_match(/