diff --git a/.travis.yml b/.travis.yml index f21f396..f09ded4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ +sudo: false language: ruby bundler_args: --without development rvm: - "1.9.3" - - "2.1.1" \ No newline at end of file + - "2.1" + - "2.2" +gemfile: + - "Gemfile" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e81b980..cd411e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +# 0.4.6 + +* [fix] Implement new engine interface for future sprockets versions #70 +* [bugfix] Fix issue where helper is not a defined method on controller (e.g. ActionController::API:Class) #65 + +# 0.4.5 + +* [bugfix] fix sprockets engine registering for older sprocket-rails versions #68 + +# 0.4.4 + +* [bugfix] fix compatibility with with sprockts-rails version 3.x, see #62 + +# 0.4.3 + +* [bugfix] for media queries with whitespace in front of them #57 + +# 0.4.2 + +* [bugfix] correctly split stylesheets even if @keyframes are directly on the rule limit #55 by [@rubenswieringa](https://github.com/rubenswieringa) + +# 0.4.1 + +* [Improvement] All `*_splitN.css` files default to `debug: false` in development to prevent empty file bug. + # 0.4.0 * **Breaking changes!** diff --git a/Gemfile b/Gemfile index 8a91985..74fab5c 100644 --- a/Gemfile +++ b/Gemfile @@ -13,11 +13,3 @@ gem "rails" gem "sass-rails" gem "jquery-rails" gem "uglifier" - -# Declare any dependencies that are still in development here instead of in -# your gemspec. These might include edge Rails or gems from your path or -# Git. Remember to move these dependencies to your gemspec before releasing -# your gem to rubygems.org. - -# To use debugger -# gem 'debugger' diff --git a/README.md b/README.md index a847dfe..d1b3805 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ Gem for splitting up stylesheets that go beyond the IE limit of 4096 selectors, for Rails 3.1+ apps using the Asset Pipeline. You can read this [blogpost](http://railslove.com/blog/2013/03/08/overcoming-ies-4096-selector-limit-using-the-css-splitter-gem) for an explanation of this gem's background story. +### Development status + +Fortunately, the problem of too large CSS files is long gone. This repo is unmaintained. +It remains as an artefact of dark times in the history of web browsers. ## Installation @@ -85,15 +89,23 @@ If you have more questions about how it works, look at the code or contact us. Note that if you used versions below `0.4.0` of this gem, the naming and contents of the split files have changed. Split files no longer need to have the `.split2` extension and now use the `require` directive rather than the `include` directive. The previous prohibition against using `require_tree .` and `require_self` directives also no longer applies. For more details see the [CHANGELOG.md](CHANGELOG.md#040) +#### Empty *_split2.css file + +Since 0.4.1 in development split stylesheets have `debug: false` option by default. This prevents the empty `*_split2.css` file issue. You can always explicitly go one way or the other setting `debug` option directly in the `split_stylesheet_link_tag` like this: + +``` +<%= split_stylesheet_link_tag "application", debug: false %> +``` + ## Credits & License -This is a joint project by the two German Rails shops [Zweitag](http://zweitag.de) and [Railslove](http://railslove.com), therefore the GitHub name "Zweilove". +This is a joint project by the two German Rails shops [Zweitag](https://zweitag.de) and [Railslove](https://railslove.com), therefore the GitHub name "Zweilove". -The original code was written by [Christian Peters](mailto:christian.peters@zweitag.de) and [Thomas Hollstegge](mailto:thomas.hollstegge@zweitag.de) (see this [Gist](https://gist.github.com/2398394)) and turned into a gem by [Jakob Hilden](mailto:jakobhilden@gmail.com). +The original code was written by Christian Peters and Thomas Hollstegge (see this [Gist](https://gist.github.com/2398394)) and turned into a gem by Jakob Hilden. **Major Contributors** * [@Umofomia](https://github.com/Umofomia) +* [@kruszczynski](https://github.com/kruszczynski) -This project rocks and uses MIT-LICENSE. - +This project uses MIT-LICENSE. diff --git a/app/helpers/css_splitter/application_helper.rb b/app/helpers/css_splitter/application_helper.rb index af5061d..ecfd2ef 100644 --- a/app/helpers/css_splitter/application_helper.rb +++ b/app/helpers/css_splitter/application_helper.rb @@ -6,7 +6,11 @@ def split_stylesheet_link_tag(*sources) sources.map do |source| split_sources = (2..split_count).map { |index| "#{source}_split#{index}" } - split_sources << options + split_options = options.dup + if Rails.env == 'development' && !split_options.key?(:debug) + split_options[:debug] = false + end + split_sources << split_options [ stylesheet_link_tag(source, options), @@ -17,4 +21,4 @@ def split_stylesheet_link_tag(*sources) end.flatten.join("\n").html_safe end end -end \ No newline at end of file +end diff --git a/lib/css_splitter/engine.rb b/lib/css_splitter/engine.rb index c51574e..05a1fae 100644 --- a/lib/css_splitter/engine.rb +++ b/lib/css_splitter/engine.rb @@ -1,14 +1,19 @@ module CssSplitter class Engine < ::Rails::Engine - isolate_namespace CssSplitter - initializer 'css_splitter.sprockets_engine', after: 'sprockets.environment', group: :all do |app| - app.assets.register_bundle_processor 'text/css', CssSplitter::SprocketsEngine + if app.config.assets.public_methods.include? :configure + app.config.assets.configure do |assets| + assets.register_bundle_processor 'text/css', CssSplitter::SprocketsEngine + end + else + app.assets.register_bundle_processor 'text/css', CssSplitter::SprocketsEngine + end end initializer 'css_splitter.action_controller' do |app| ActiveSupport.on_load :action_controller do - helper CssSplitter::ApplicationHelper + # Not all controllers use helpers (such as API based controllers) + helper CssSplitter::ApplicationHelper if respond_to?(:helper) end end end diff --git a/lib/css_splitter/splitter.rb b/lib/css_splitter/splitter.rb index fdb0f7c..f5f6a25 100644 --- a/lib/css_splitter/splitter.rb +++ b/lib/css_splitter/splitter.rb @@ -12,7 +12,28 @@ def self.split_string(css_string, split = 1, max_selectors = MAX_SELECTORS_DEFAU # splits string into array of rules (also strips comments) def self.split_string_into_rules(css_string) - strip_comments(css_string).chomp.scan /[^}]*}/ + partial_rules = strip_comments(css_string).chomp.scan /[^}]*}/ + whole_rules = [] + bracket_balance = 0 + in_media_query = false + + partial_rules.each do |rule| + if rule =~ /^\s*@media/ + in_media_query = true + elsif bracket_balance == 0 + in_media_query = false + end + + if bracket_balance == 0 || in_media_query + whole_rules << rule + else + whole_rules.last << rule + end + + bracket_balance += get_rule_bracket_balance rule + end + + whole_rules end # extracts the specified part of an overlong CSS string @@ -107,6 +128,10 @@ def self.strip_comments(s) s.gsub(/\/\*.*?\*\//m, "") end + def self.get_rule_bracket_balance ( rule ) + rule.scan( /}/ ).size - rule.scan( /{/ ).size + end + end end diff --git a/lib/css_splitter/sprockets_engine.rb b/lib/css_splitter/sprockets_engine.rb index f6ae2a8..551af8c 100644 --- a/lib/css_splitter/sprockets_engine.rb +++ b/lib/css_splitter/sprockets_engine.rb @@ -10,6 +10,22 @@ def self.engine_initialized? def prepare end + def self.call(input) + data_in = input[:data] + + # Instantiate Sprockets::Context to pass along helper methods for Tilt + # processors + context = input[:environment].context_class.new(input) + + # Pass the asset file contents as a block to the template engine, + # then get the results of the engine rendering + engine = self.new { data_in } + rendered_data = engine.render(context, {}) + + # Return the data and any metadata (ie file dependencies, etc) + context.metadata.merge(data: rendered_data.to_str) + end + def evaluate(scope, locals, &block) # Evaluate the split if the asset is named with a trailing _split2, _split3, etc. if scope.logical_path =~ /_split(\d+)$/ diff --git a/lib/css_splitter/version.rb b/lib/css_splitter/version.rb index 1c14b2c..57859d1 100644 --- a/lib/css_splitter/version.rb +++ b/lib/css_splitter/version.rb @@ -1,3 +1,3 @@ module CssSplitter - VERSION = "0.4.0" + VERSION = "0.4.6" end diff --git a/test/css_splitter_test.rb b/test/css_splitter_test.rb index 5090a3d..012cf89 100644 --- a/test/css_splitter_test.rb +++ b/test/css_splitter_test.rb @@ -13,18 +13,17 @@ class CssSplitterTest < ActiveSupport::TestCase part2 = "#test{background-color:green}" * CssSplitter::Splitter::MAX_SELECTORS_DEFAULT part3 = "#test{background-color:blue}" - assert_equal "#{part1}#{part2}#{part3}\n", assets["erb_stylesheet"].to_s - assert_equal "#{part2}\n", assets["erb_stylesheet_split2"].to_s - assert_equal "#{part3}\n", assets["erb_stylesheet_split3"].to_s + assert_equal "#{part1}#{part2}#{part3}", assets["erb_stylesheet"].to_s.gsub(/\s/, '') + assert_equal "#{part2}", assets["erb_stylesheet_split2"].to_s.gsub(/\s/, '') + assert_equal "#{part3}", assets["erb_stylesheet_split3"].to_s.gsub(/\s/, '') end test "asset pipeline stylesheet splitting on stylesheet combined using requires" do red = "#test{background-color:red}" * 100 green = "#test{background-color:green}" * CssSplitter::Splitter::MAX_SELECTORS_DEFAULT blue = "#test{background-color:blue}" - - assert_equal "#{red}#{green}#{blue}\n", assets["combined"].to_s - assert_equal "#{"#test{background-color:green}" * 100}#{blue}\n", assets["combined_split2"].to_s + assert_equal "#{red}#{green}#{blue}", assets["combined"].to_s.gsub(/\s/, '') + assert_equal "#{"#test{background-color:green}" * 100}#{blue}", assets["combined_split2"].to_s.gsub(/\s/, '') end private diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb index 9fa37cd..f9e8544 100644 --- a/test/dummy/app/views/layouts/application.html.erb +++ b/test/dummy/app/views/layouts/application.html.erb @@ -5,7 +5,7 @@ <%= stylesheet_link_tag "application", :media => "all" %> - <%= split_stylesheet_link_tag "too_big_stylesheet", :media => "all" %> + <%= split_stylesheet_link_tag "too_big_stylesheet", :media => "all", :debug => true %> <%= csrf_meta_tags %> diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 6a0af91..7a5b60e 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -38,7 +38,8 @@ class Application < Rails::Application # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] - + config.sass.line_comments = false + config.assets.compress = true # Enable escaping HTML in JSON. config.active_support.escape_html_entities_in_json = true @@ -55,9 +56,6 @@ class Application < Rails::Application # Enable the asset pipeline config.assets.enabled = true - - # Version of your assets, change this if you want to expire all your assets - config.assets.version = '1.0' end end diff --git a/test/dummy/config/environments/production.rb b/test/dummy/config/environments/production.rb index 5f2d7d7..d92c150 100644 --- a/test/dummy/config/environments/production.rb +++ b/test/dummy/config/environments/production.rb @@ -9,7 +9,7 @@ config.action_controller.perform_caching = true # Disable Rails's static asset server (Apache or nginx will already do this) - config.serve_static_assets = false + config.serve_static_files = false # Compress JavaScripts and CSS config.assets.compress = true @@ -31,7 +31,7 @@ # config.force_ssl = true # See everything in the log (default is :info) - # config.log_level = :debug + config.log_level = :debug # Prepend all log lines with the following tags # config.log_tags = [ :subdomain, :uuid ] @@ -45,9 +45,6 @@ # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" - # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) - config.assets.precompile += %w( too_big_stylesheet.css too_big_stylesheet_split2.css test_stylesheet_with_media_queries.css test_stylesheet_with_media_queries_split2.css ) - # Disable delivery errors, bad email addresses will be ignored # config.action_mailer.raise_delivery_errors = false diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb index 284daa5..3171e7c 100644 --- a/test/dummy/config/environments/test.rb +++ b/test/dummy/config/environments/test.rb @@ -8,7 +8,7 @@ config.cache_classes = true # Configure static asset server for tests with Cache-Control for performance - config.serve_static_assets = true + config.serve_static_files = true config.static_cache_control = "public, max-age=3600" # Log error messages when you accidentally call methods on nil @@ -29,6 +29,9 @@ # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test + # run tests in a random order + config.active_support.test_order = :random + # Raise exception on mass assignment protection for Active Record models # config.active_record.mass_assignment_sanitizer = :strict diff --git a/test/dummy/config/initializers/assets.rb b/test/dummy/config/initializers/assets.rb new file mode 100644 index 0000000..91073da --- /dev/null +++ b/test/dummy/config/initializers/assets.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. +Rails.application.config.assets.precompile += %w( too_big_stylesheet.css too_big_stylesheet_split2.css test_stylesheet_with_media_queries.css test_stylesheet_with_media_queries_split2.css ) \ No newline at end of file diff --git a/test/dummy/config/secrets.yml b/test/dummy/config/secrets.yml new file mode 100644 index 0000000..5dc368e --- /dev/null +++ b/test/dummy/config/secrets.yml @@ -0,0 +1,4 @@ +test: + secret_key_base: c2a98602cc1537b2e38d4f279f20d24db66ff86fe523ab5197529f2ea907b6d70e2dca2fa3da50dcc9cad7bb1b861f0c45b6920fc576cc3e170d8c1ded61887f +development: + secret_key_base: c2a98602cc1537b2e38d4f279f20d24db66ff86fe523ab5197529f2ea907b6d70e2dca2fa3da50dcc9cad7bb1b861f0c45b6920fc576cc3e170d8c1ded61887f \ No newline at end of file diff --git a/test/unit/helpers/css_splitter/application_helper_test.rb b/test/unit/helpers/css_splitter/application_helper_test.rb index e42a401..4dc8d39 100644 --- a/test/unit/helpers/css_splitter/application_helper_test.rb +++ b/test/unit/helpers/css_splitter/application_helper_test.rb @@ -5,18 +5,41 @@ class ApplicationHelperTest < ActionView::TestCase test "should work w/out options" do output = split_stylesheet_link_tag("too_big_stylesheet") - assert_equal "\n", output + assert_equal "\n", output end test "should work with options and multiple stylesheets" do output = split_stylesheet_link_tag("too_big_stylesheet", "foo", media: "print") - assert_equal "\n\n\n", output + assert_equal "\n\n\n", output end test "should work with split_count option" do output = split_stylesheet_link_tag("too_big_stylesheet", split_count: 3) - assert_equal "\n", output + assert_equal "\n", output end + class RailsEnvDefault < ActionView::TestCase + setup do + Rails.env = 'development' + end + + teardown do + Rails.env = 'test' + end + + test "should default to false on splits" do + output = split_stylesheet_link_tag("too_big_stylesheet") + assert_equal "\n", output + end + + test "should respect the debug=true option" do + output = split_stylesheet_link_tag("too_big_stylesheet", debug: true) + assert_equal "\n", output + end + test "should respect the debug=false option" do + output = split_stylesheet_link_tag("too_big_stylesheet", debug: false) + assert_equal "\n", output + end + end end end diff --git a/test/unit/splitter_test.rb b/test/unit/splitter_test.rb index b5c4b59..f9713ea 100644 --- a/test/unit/splitter_test.rb +++ b/test/unit/splitter_test.rb @@ -40,6 +40,16 @@ class CssSplitterTest < ActiveSupport::TestCase assert_equal ["a{foo:bar;}", "@media print{b{baz:qux;}", "c{quux:corge;}", "}", "d{grault:garply;}"], CssSplitter::Splitter.split_string_into_rules(has_media) end + test '#split_string_into_rules containing media queries with leading whitespace' do + has_media = "a{foo:bar;}\n @media print{b{baz:qux;}c{quux:corge;}}d{grault:garply;}" + assert_equal ["a{foo:bar;}", "\n @media print{b{baz:qux;}", "c{quux:corge;}", "}", "d{grault:garply;}"], CssSplitter::Splitter.split_string_into_rules(has_media) + end + + test "#split_string_into_rules containing keyframes" do + has_keyframes = "a{foo:bar;}@keyframes rubes{from{baz:qux;}50%{quux:corge;}}d{grault:garply;}" + assert_equal ["a{foo:bar;}", "@keyframes rubes{from{baz:qux;}50%{quux:corge;}}", "d{grault:garply;}"], CssSplitter::Splitter.split_string_into_rules(has_keyframes) + end + # --- extract_charset --- test '#extract_charset with no charset' do