rails_critical_css 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bd4b7e4c280804bf93b6dd1d53781ded82f99b53ecd91e745eed3720c1c8673a
4
+ data.tar.gz: 98a1ba570526be8b716cd23ee96e081e598b16a477d8cb5940631dffddf4327c
5
+ SHA512:
6
+ metadata.gz: a38d5c49bf15e78494cf3c19973aa87b3e5f7db39cb6316a74d0d80c97278106f290a4ab6a5b8dfec3effa022489410e6fafedb306bdaef31715cbe18a5fd0f3
7
+ data.tar.gz: 8a8843bd2855cf7b04a88c44a97d9a08f8c3216bcf72201ca1a69999e65373e45c85187c8dc929a616d85870679723b0492dc98a6eb4ee14ef0688e1510d6191
data/.gitignore ADDED
@@ -0,0 +1,67 @@
1
+ *.rbc
2
+ capybara-*.html
3
+ .rspec
4
+ /db/*.sqlite3
5
+ /db/*.sqlite3-journal
6
+ /db/*.sqlite3-[0-9]*
7
+ /public/system
8
+ /coverage/
9
+ /spec/tmp
10
+ *.orig
11
+ rerun.txt
12
+ pickle-email-*.html
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*
16
+ /tmp/*
17
+ !/log/.keep
18
+ !/tmp/.keep
19
+
20
+ # TODO Comment out this rule if you are OK with secrets being uploaded to the repo
21
+ config/initializers/secret_token.rb
22
+ config/master.key
23
+
24
+ # Only include if you have production secrets in this file, which is no longer a Rails default
25
+ # config/secrets.yml
26
+
27
+ # dotenv
28
+ # TODO Comment out this rule if environment variables can be committed
29
+ .env
30
+
31
+ ## Environment normalization:
32
+ /.bundle
33
+ /vendor/bundle
34
+
35
+ # these should all be checked in to normalize the environment:
36
+ # Gemfile.lock, .ruby-version, .ruby-gemset
37
+
38
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
39
+ .rvmrc
40
+
41
+ # if using bower-rails ignore default bower_components path bower.json files
42
+ /vendor/assets/bower_components
43
+ *.bowerrc
44
+ bower.json
45
+
46
+ # Ignore pow environment settings
47
+ .powenv
48
+
49
+ # Ignore Byebug command history file.
50
+ .byebug_history
51
+
52
+ # Ignore node_modules
53
+ node_modules/
54
+
55
+ # Ignore precompiled javascript packs
56
+ /public/packs
57
+ /public/packs-test
58
+ /public/assets
59
+
60
+ # Ignore yarn files
61
+ /yarn-error.log
62
+ yarn-debug.log*
63
+ .yarn-integrity
64
+
65
+ # Ignore uploaded files in development
66
+ /storage/*
67
+ !/storage/.keep
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ source 'https://rubygems.org'
data/Gemfile.lock ADDED
@@ -0,0 +1,11 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+
5
+ PLATFORMS
6
+ x86_64-linux
7
+
8
+ DEPENDENCIES
9
+
10
+ BUNDLED WITH
11
+ 2.2.21
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Mateusz Bagiński
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # rails-critical-css
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
4
+ ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/mati365/rails-critical-css?style=flat-square)
5
+ ![GitHub issues](https://img.shields.io/github/issues/mati365/rails-critical-css?style=flat-square)
6
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
7
+
8
+ Generate on demand critical css for component actions with minimum effort.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ gem 'rails_critical_css'
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ Install `penthouse` NPM package in your project. Be sure that node_modules/ directory is present on production builds.
19
+
20
+ In initializer:
21
+
22
+ ```ruby
23
+ CriticalCssGenerator.config do |c|
24
+ c.keep_larger_media_queries = true
25
+ c.height = 19999 # prevent CLS on for example footer
26
+ end
27
+ ```
28
+
29
+ In controller:
30
+
31
+ ```ruby
32
+ class ExampleController < ApplicationController
33
+ action_critical_css :show, cache_key: :critical_css_cache_key
34
+ # or
35
+ action_critical_css :show, cache_key: -> { 'cache_key' }
36
+ # or
37
+ action_critical_css :show, cache_key: 'cache_key'
38
+
39
+ ...
40
+
41
+ def critical_css_cache_key
42
+ "some-dynamic-key-#{random_variable}"
43
+ end
44
+ end
45
+ ```
46
+
47
+ In template:
48
+
49
+ ```slim
50
+ = critical_css_asset file: 'some-file-to-be-prepended-to-criticals', critical: true
51
+ = critical_css_tags
52
+ link rel="stylesheet" href="css/vendors.css" rel='stylesheet' type='text/css'
53
+ link rel="stylesheet" href="css/app.css" rel='stylesheet' type='text/css'
54
+ ```
55
+
56
+ ## Testing
57
+
58
+ Enable redis caching on localhost and precompile locally assets. Critical CSS are generated using background job so they are injected to HTML after next requests (it takes around 3s)
59
+
60
+ ## License
61
+
62
+ The MIT License (MIT)
63
+ Copyright (c) 2021 Mateusz Bagiński
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
68
+
69
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ task :gem => :build
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator::Actions
4
+ class AfterRender
5
+ include CriticalCssGenerator::Actions::Helpers
6
+
7
+ def initialize(filter_options)
8
+ @packed_options = filter_options.slice(
9
+ :css, :cache_key, :cache_store, :cache_prefix
10
+ )
11
+ end
12
+
13
+ def after(controller)
14
+ return if controller.critical_css_cache.present?
15
+
16
+ @controller = controller
17
+ options = eval_options(controller, @packed_options)
18
+ cache_path = gen_critical_css_cache_path(options, options[:cache_key])
19
+
20
+ return if cache_path == false
21
+
22
+ CriticalCssGenerator::Jobs::Extractor.perform_if_semaphore_is_released(
23
+ html: controller.full_html_response,
24
+ cache: {
25
+ path: cache_path,
26
+ store: options[:cache_store],
27
+ },
28
+ css: {
29
+ assets: assets_mapped_paths,
30
+ },
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ def assets_mapped_paths
37
+ items = group_assets_by_type(@controller.critical_css_assets)
38
+ output = items[:inline] || []
39
+
40
+ if items[:files]
41
+ output += items[:files].map do |i|
42
+ file = Rails.env.development? ? i[:file] : Rails.application.assets_manifest.assets["#{i[:file]}.css"]
43
+
44
+ {
45
+ critical: i[:critical],
46
+ file: absolute_asset_file_path(@controller, file, 'css')
47
+ }
48
+ end
49
+ end
50
+
51
+ output
52
+ rescue
53
+ []
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator::Actions
4
+ class BeforeRender
5
+ include CriticalCssGenerator::Actions::Helpers
6
+
7
+ def initialize(filter_options)
8
+ @packed_options = filter_options.slice(:css, :cache_key, :cache_prefix)
9
+ end
10
+
11
+ def around(controller)
12
+ @controller = controller
13
+
14
+ options = eval_options(controller, @packed_options)
15
+ cache_path = gen_critical_css_cache_path(options, options[:cache_key])
16
+
17
+ # load already compiled css from cache
18
+ critical_css_cache = cache_path.presence && Rails.cache.read(cache_path)
19
+ controller.critical_css_cache = critical_css_cache
20
+ controller.critical_css_enabled = true
21
+
22
+ yield
23
+ return unless css_extracting_allowed?
24
+
25
+ if critical_css_cache.present? && critical_css_cache[:lazy_css_blocks].present?
26
+ controller.response.body = inject_lazy_css_to_footer(critical_css_cache[:lazy_css_blocks])
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def css_extracting_allowed?
33
+ @controller.request.get? \
34
+ && @controller.response.status == 200 \
35
+ && @controller.full_html_response.present?
36
+ end
37
+
38
+ def inject_lazy_css_to_footer(css)
39
+ html = @controller.full_html_response
40
+ lazy_css_injection_index = html.index('</body>')
41
+
42
+ [
43
+ html[0..lazy_css_injection_index - 1],
44
+ css,
45
+ html[lazy_css_injection_index..-1],
46
+ ].join('')
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator::Actions::Helpers
4
+ def group_assets_by_type(assets)
5
+ return [] unless assets.present?
6
+
7
+ assets.group_by do |item|
8
+ item[:file].present? ? :files : :inline
9
+ end
10
+ end
11
+
12
+ def eval_options(controller, packed_options)
13
+ packed_options.transform_values do |option|
14
+ eval_option(controller, option)
15
+ end
16
+ end
17
+
18
+ def eval_option(controller, option)
19
+ option = option.to_proc if option.is_a?(Symbol)
20
+
21
+ if option.is_a?(Proc)
22
+ case option.arity
23
+ when -2, -1, 1
24
+ controller.instance_exec(controller, &option)
25
+ when 0
26
+ controller.instance_exec(&option)
27
+ end
28
+ elsif option.respond_to?(:call)
29
+ option.call(controller)
30
+ else
31
+ option
32
+ end
33
+ end
34
+
35
+ def absolute_asset_file_path(controller, asset, extension = nil)
36
+ return nil unless asset.present?
37
+
38
+ suffix = extension ? ".#{extension}" : ''
39
+ suffixed_asset_name = asset.include?('.') ? asset : asset + suffix
40
+
41
+ if Rails.env.development?
42
+ filename = controller.view_context.asset_path(suffixed_asset_name)
43
+ File.join(Rails.public_path, filename)
44
+ else
45
+ File.join(Rails.public_path, Rails.application.config.assets.prefix, suffixed_asset_name)
46
+ end
47
+ end
48
+
49
+ def gen_critical_css_cache_path(options, path)
50
+ return nil unless path
51
+
52
+ controller, action = @controller.request.path_parameters.values_at(:controller, :action)
53
+ path = eval_option(controller, path)
54
+
55
+ "#{options[:cache_prefix]}-#{controller}##{action}#{path}"
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator::Actions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include CriticalCssGenerator::Helpers
8
+
9
+ attr_accessor :lazy_css_blocks,
10
+ :critical_css_assets,
11
+ :critical_css_cache,
12
+ :critical_css_enabled
13
+
14
+ helper_method :append_critical_css_asset,
15
+ :append_css_tags_assets
16
+ end
17
+
18
+ def extract_assets_from_css_tags(str)
19
+ return [] unless str.present?
20
+
21
+ str
22
+ .scan(/assets\/([^?"]*)-[^?-]+.css/)
23
+ .flatten
24
+ .map { |i| i.sub('.self', '') }
25
+ end
26
+
27
+ def append_critical_css_asset(file:, critical: false)
28
+ (@critical_css_assets ||= []) << {
29
+ file: file,
30
+ critical: critical,
31
+ }
32
+ end
33
+
34
+ def append_css_tags_assets(str)
35
+ extract_assets_from_css_tags(str).each do |asset|
36
+ append_critical_css_asset file: asset
37
+ end
38
+ end
39
+
40
+ def full_html_response
41
+ response.body
42
+ end
43
+
44
+ class_methods do
45
+ def action_critical_css(*actions)
46
+ options = actions.extract_options!
47
+ return unless cache_configured?
48
+
49
+ options[:unless] ||= -> { request.query_string.present? }
50
+ options[:cache_prefix] ||= 'critical-css'
51
+
52
+ filter_options = options.extract!(:if, :unless).merge(only: actions)
53
+ around_action CriticalCssGenerator::Actions::BeforeRender.new(options), filter_options
54
+ after_action CriticalCssGenerator::Actions::AfterRender.new(options), filter_options
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator
4
+ class Config
5
+ class << self
6
+ attr_writer :width, :height, :keep_larger_media_queries,
7
+ :render_wait_time, :penthouse_options
8
+
9
+ def width
10
+ @width ||= 1200
11
+ end
12
+
13
+ def height
14
+ @height ||= 900
15
+ end
16
+
17
+ def render_wait_time
18
+ @render_wait_time ||= 2000
19
+ end
20
+
21
+ def keep_larger_media_queries
22
+ @keep_larger_media_queries ||= false
23
+ end
24
+
25
+ def as_json_config(props = {})
26
+ {
27
+ width: width,
28
+ height: height,
29
+ keepLargerMediaQueries: keep_larger_media_queries,
30
+ renderWaitTime: render_wait_time,
31
+ }
32
+ .merge!(@penthouse_options || {})
33
+ .merge!(props)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator
4
+ class Extractor
5
+ include CriticalCssGenerator::Actions::Helpers
6
+
7
+ def initialize(options)
8
+ @html, @css = options.values_at(:html, :css)
9
+ end
10
+
11
+ def try_extract
12
+ tmp_html_file = tmp_extractor_file(@html, extension: 'html')
13
+ tmp_css_file = tmp_concat_assets_array(@css[:assets], extension: 'css')
14
+ return nil unless tmp_html_file.present? && tmp_css_file.present?
15
+
16
+ stdout, stderr = Open3.capture2e(
17
+ 'node lib/critical_css_generator/js/css-extractor.js',
18
+ stdin_data: Extractor.extractor_process_input(
19
+ html_path: tmp_html_file.path,
20
+ css_path: tmp_css_file.path,
21
+ )
22
+ )
23
+
24
+ if stderr.try(:success?) && !stdout.try(:include?, 'UnhandledPromiseRejectionWarning')
25
+ [
26
+ extract_critical_assets(@css[:assets]),
27
+ stdout.try(:gsub, /src:[^;]+;/, ''),
28
+ ].join(' ')
29
+ else
30
+ nil
31
+ end
32
+ rescue
33
+ nil
34
+ ensure
35
+ tmp_html_file&.delete
36
+ tmp_css_file&.delete
37
+ end
38
+
39
+ def self.extractor_process_input(html_path:, css_path:)
40
+ config = ::CriticalCssGenerator::Config.as_json_config({
41
+ url: "file://#{html_path}",
42
+ css: css_path,
43
+ })
44
+
45
+ JSON.generate(config)
46
+ end
47
+
48
+ private
49
+
50
+ def extract_critical_assets(assets)
51
+ return '' unless assets.present?
52
+
53
+ critical_assets = assets.filter { |item| item[:critical] }
54
+ critical_assets
55
+ .map { |asset| File.read(asset[:file]) }
56
+ .compact
57
+ .join(' ')
58
+ end
59
+
60
+ def tmp_dir
61
+ File.join(Rails.root, 'tmp')
62
+ end
63
+
64
+ def tmp_extractor_file(content = nil, extension: nil)
65
+ f = Tempfile.new(['critical-css-tmp', ".#{extension || 'bin'}"], tmp_dir, encoding: 'utf-8')
66
+ if content.present?
67
+ f.write(content)
68
+ f.rewind
69
+ end
70
+
71
+ f.close
72
+ f
73
+ end
74
+
75
+ def tmp_concat_assets_array(assets, extension: nil)
76
+ return nil unless assets.present?
77
+
78
+ items = group_assets_by_type(assets)
79
+ file = tmp_extractor_file(
80
+ (items[:inline] || []).join('\n'),
81
+ extension: extension
82
+ )
83
+
84
+ paths = (items[:files] || []).map { |asset| asset[:file] }.compact
85
+ unless paths.empty?
86
+ Open3.pipeline_w(['cat', *paths], out: file.path)
87
+ end
88
+
89
+ file
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator::Helpers
4
+ def critical_css
5
+ @critical_css_cache.try(:[], :css)
6
+ end
7
+
8
+ def critical_css_enabled?
9
+ @critical_css_enabled
10
+ end
11
+
12
+ def critical_css?
13
+ critical_css.present? && critical_css.instance_of?(String)
14
+ end
15
+
16
+ def critical_css_asset(attrs)
17
+ append_critical_css_asset(attrs)
18
+ nil
19
+ end
20
+
21
+ def critical_css_tags(preserve_content: true, &block)
22
+ content = capture(&block)
23
+
24
+ if critical_css_enabled? && critical_css?
25
+ css_tags = content_tag(:style, critical_css.html_safe, type: 'text/css')
26
+ css_tags = "#{css_tags}#{content}".html_safe if preserve_content
27
+ css_tags.html_safe
28
+ else
29
+ append_css_tags_assets(content)
30
+ content
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CriticalCssGenerator::Jobs
4
+ class Extractor < ActiveJob::Base
5
+ class << self
6
+ def semaphore_key(cache_path)
7
+ "semaphore-#{cache_path}"
8
+ end
9
+
10
+ def perform_if_semaphore_is_released(attrs)
11
+ semaphore = semaphore_key(attrs[:cache][:path])
12
+ return if Rails.cache.exist?(semaphore)
13
+
14
+ Rails.cache.write(semaphore, '1', { expires_in: 15.minutes })
15
+ perform_later(attrs)
16
+ end
17
+ end
18
+
19
+ def perform(cache:, css:, html:)
20
+ semaphore = self.class.semaphore_key(cache[:path])
21
+ critical_css = ::CriticalCssGenerator::Extractor.new(css: css, html: html).try_extract
22
+
23
+ # store it as wrapped css, do not regenerate for
24
+ # each request critical_css if something go wrong
25
+ # with css-extractor
26
+ Rails.cache.write(
27
+ cache[:path],
28
+ {
29
+ css: critical_css,
30
+ },
31
+ cache[:store]
32
+ )
33
+
34
+ Rails.cache.delete(semaphore)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'critical_css_generator/config'
5
+ require 'critical_css_generator/actions'
6
+ require 'critical_css_generator/actions/helpers'
7
+ require 'critical_css_generator/extractor'
8
+ require 'critical_css_generator/jobs/extractor'
9
+ require 'critical_css_generator/actions/after_render'
10
+ require 'critical_css_generator/actions/before_render'
11
+ require 'critical_css_generator/helpers'
12
+
13
+ module CriticalCssGenerator
14
+ def self.config
15
+ yield CriticalCssGenerator::Config
16
+ end
17
+ end
18
+
19
+ ActionController::Base.send(:include, CriticalCssGenerator::Actions)
20
+ ActionView::Base.send(:include, CriticalCssGenerator::Helpers)
@@ -0,0 +1,20 @@
1
+ const penthouse = require('penthouse');
2
+ const process = require('process');
3
+ const fs = require('fs');
4
+
5
+ const FD = {
6
+ STDIN: 0,
7
+ STDOUT: 1,
8
+ STDERR: 2,
9
+ };
10
+
11
+ const config = JSON.parse(fs.readFileSync(FD.STDIN, 'utf-8'));
12
+
13
+ penthouse(config)
14
+ .then((criticalCss) => {
15
+ fs.writeSync(FD.STDOUT, criticalCss);
16
+ })
17
+ .catch((err) => {
18
+ fs.writeSync(FD.STDERR, err);
19
+ process.exit(1);
20
+ })
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rails_critical_css'
3
+ s.version = '0.1.0'
4
+ s.summary = 'Critical CSS rails generator'
5
+ s.authors = ['Mateusz Bagiński']
6
+
7
+ s.license = 'MIT'
8
+ s.email = 'cziken58@gmail.com'
9
+ s.homepage = 'https://github.com/Mati365/rails-critical-css'
10
+ s.files = `git ls-files`.split($/)
11
+
12
+ s.require_paths << 'lib'
13
+ s.required_ruby_version = '>= 2.4.0'
14
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_critical_css
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mateusz Bagiński
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-10-31 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: cziken58@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - Gemfile
21
+ - Gemfile.lock
22
+ - LICENSE
23
+ - README.md
24
+ - Rakefile
25
+ - lib/critical_css_generator.rb
26
+ - lib/critical_css_generator/actions.rb
27
+ - lib/critical_css_generator/actions/after_render.rb
28
+ - lib/critical_css_generator/actions/before_render.rb
29
+ - lib/critical_css_generator/actions/helpers.rb
30
+ - lib/critical_css_generator/config.rb
31
+ - lib/critical_css_generator/extractor.rb
32
+ - lib/critical_css_generator/helpers.rb
33
+ - lib/critical_css_generator/jobs/extractor.rb
34
+ - lib/js/css-extractor.js
35
+ - rails_critical_css.gemspec
36
+ homepage: https://github.com/Mati365/rails-critical-css
37
+ licenses:
38
+ - MIT
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 2.4.0
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubygems_version: 3.2.5
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Critical CSS rails generator
60
+ test_files: []