tailwindcss-rails 0.3.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,5 +8,8 @@ else
8
8
  say %( Add <%= stylesheet_link_tag "inter-font" %> and <%= stylesheet_link_tag "tailwind" %> within the <head> tag in your custom layout.)
9
9
  end
10
10
 
11
+ say "Removing scaffold styles"
12
+ remove_file Rails.root.join("app/assets/stylesheets/scaffolds.scss")
13
+
11
14
  say "Turn on purging of unused css classes in production"
12
15
  gsub_file Rails.root.join("config/environments/production.rb"), /^\s+#?\s+config.assets.css_compressor =.*$/, %( config.assets.css_compressor = :purger)
@@ -10,6 +10,10 @@ module Tailwindcss
10
10
  Rails.application.config.assets.precompile += %w( tailwind.css inter-font.css )
11
11
  end
12
12
 
13
+ initializer "tailwindcss.disable_generator_stylesheets" do
14
+ Rails.application.config.generators.stylesheets = false
15
+ end
16
+
13
17
  initializer "tailwindcss.disable_assets_cache" do
14
18
  Rails.application.config.assets.configure do |env|
15
19
  env.cache = ActiveSupport::Cache.lookup_store(:null_store)
@@ -1,8 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Tailwindcss::Purger
2
- CLASS_NAME_PATTERN = /([:A-Za-z0-9_-]+[\.]*[\\\/:A-Za-z0-9_-]*)/
3
- OPENING_SELECTOR_PATTERN = /\..*\{/
4
- CLOSING_SELECTOR_PATTERN = /\s*\}/
5
- NEWLINE = "\n"
4
+ CLASS_NAME_PATTERN = /[:A-Za-z0-9_-]+[\.]*[\\\/:A-Za-z0-9_-]*/
5
+
6
+ CLASS_BREAK = /(?![-_a-z0-9\\])/i # `\b` for class selectors
7
+
8
+ COMMENT = /#{Regexp.escape "/*"}.*?#{Regexp.escape "*/"}/m
9
+ COMMENTS_AND_BLANK_LINES = /\A(?:^#{COMMENT}?[ \t]*(?:\n|\z)|[ \t]*#{COMMENT})+/
10
+
11
+ AT_RULE = /@[^{]+/
12
+ CLASSLESS_SELECTOR_GROUP = /[^.{]+/
13
+ CLASSLESS_BEGINNING_OF_BLOCK = /\A\s*(?:#{AT_RULE}|#{CLASSLESS_SELECTOR_GROUP})\{\n?/
14
+
15
+ SELECTOR_GROUP = /[^{]+/
16
+ BEGINNING_OF_BLOCK = /\A#{SELECTOR_GROUP}\{\n?/
17
+
18
+ PROPERTY_NAME = /[-_a-z0-9]+/i
19
+ PROPERTY_VALUE = /(?:[^;]|;\S)+/
20
+ PROPERTIES = /\A(?:\s*#{PROPERTY_NAME}:#{PROPERTY_VALUE};\n?)+/
21
+
22
+ END_OF_BLOCK = /\A\s*\}\n?/
6
23
 
7
24
  attr_reader :keep_these_class_names
8
25
 
@@ -12,11 +29,15 @@ class Tailwindcss::Purger
12
29
  end
13
30
 
14
31
  def extract_class_names(string)
15
- string.scan(CLASS_NAME_PATTERN).flatten.uniq.sort
32
+ string.scan(CLASS_NAME_PATTERN).uniq.sort!
16
33
  end
17
34
 
18
35
  def extract_class_names_from(files)
19
- Array(files).flat_map { |file| extract_class_names(file.read) }.uniq.sort
36
+ Array(files).flat_map { |file| extract_class_names(file.read) }.uniq.sort!
37
+ end
38
+
39
+ def escape_class_selector(class_name)
40
+ class_name.gsub(/\A\d|[^-_a-z0-9]/, '\\\\\0')
20
41
  end
21
42
  end
22
43
 
@@ -25,40 +46,79 @@ class Tailwindcss::Purger
25
46
  end
26
47
 
27
48
  def purge(input)
28
- inside_kept_selector = inside_ignored_selector = false
29
- output = []
30
-
31
- input.split(NEWLINE).each do |line|
32
- case
33
- when inside_kept_selector
34
- output << line
35
- inside_kept_selector = false if line =~ CLOSING_SELECTOR_PATTERN
36
- when inside_ignored_selector
37
- inside_ignored_selector = false if line =~ CLOSING_SELECTOR_PATTERN
38
- when line =~ OPENING_SELECTOR_PATTERN
39
- if keep_these_class_names.include? class_name_in(line)
40
- output << line
41
- inside_kept_selector = true
42
- else
43
- inside_ignored_selector = true
44
- end
45
- else
46
- output << line
47
- end
49
+ conveyor = Conveyor.new(input)
50
+
51
+ until conveyor.done?
52
+ conveyor.discard(COMMENTS_AND_BLANK_LINES) \
53
+ or conveyor.conditionally_keep(PROPERTIES) { conveyor.staged_output.last != "" } \
54
+ or conveyor.conditionally_keep(END_OF_BLOCK) { not conveyor.staged_output.pop } \
55
+ or conveyor.stage_output(CLASSLESS_BEGINNING_OF_BLOCK) \
56
+ or conveyor.stage_output(BEGINNING_OF_BLOCK) { |match| purge_beginning_of_block(match.to_s) } \
57
+ or raise "infinite loop"
48
58
  end
49
59
 
50
- separated_without_empty_lines(output)
60
+ conveyor.output
51
61
  end
52
62
 
53
63
  private
54
- def class_name_in(line)
55
- CLASS_NAME_PATTERN.match(line)[1]
56
- .remove("\\")
57
- .remove(/:(focus|hover)(-within)?/)
58
- .remove("::placeholder").remove("::-moz-placeholder").remove(":-ms-input-placeholder")
64
+ def keep_these_selectors_pattern
65
+ @keep_these_selectors_pattern ||= begin
66
+ escaped_classes = @keep_these_class_names.map { |name| Regexp.escape self.class.escape_class_selector(name) }
67
+ /(?:\A|,)[^.,{]*(?:[.](?:#{escaped_classes.join("|")})#{CLASS_BREAK}[^.,{]*)*(?=[,{])/
68
+ end
69
+ end
70
+
71
+ def purge_beginning_of_block(string)
72
+ purged = string.scan(keep_these_selectors_pattern).join
73
+ unless purged.empty?
74
+ purged.sub!(/\A,\s*/, "")
75
+ purged.rstrip!
76
+ purged << " {\n"
77
+ end
78
+ purged
59
79
  end
60
80
 
61
- def separated_without_empty_lines(output)
62
- output.reject { |line| line.strip.empty? }.join(NEWLINE)
81
+ class Conveyor
82
+ attr_reader :output, :staged_output
83
+
84
+ def initialize(input, output = +"")
85
+ @input = input
86
+ @output = output
87
+ @staged_output = []
88
+ end
89
+
90
+ def consume(pattern)
91
+ match = pattern.match(@input)
92
+ @input = match.post_match if match
93
+ match
94
+ end
95
+ alias :discard :consume
96
+
97
+ def stage_output(pattern)
98
+ if match = consume(pattern)
99
+ string = block_given? ? (yield match) : match.to_s
100
+ @staged_output << string
101
+ string
102
+ end
103
+ end
104
+
105
+ def keep(pattern)
106
+ if match = consume(pattern)
107
+ string = block_given? ? (yield match) : match.to_s
108
+ @output << @staged_output.shift until @staged_output.empty?
109
+ @output << string
110
+ string
111
+ end
112
+ end
113
+
114
+ def conditionally_keep(pattern)
115
+ keep(pattern) do |match|
116
+ (yield match) ? match.to_s : (break "")
117
+ end
118
+ end
119
+
120
+ def done?
121
+ @input.empty?
122
+ end
63
123
  end
64
124
  end
@@ -1,3 +1,3 @@
1
1
  module Tailwindcss
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -1,23 +1,7 @@
1
1
  namespace :tailwindcss do
2
2
  desc "Install Tailwind CSS into the app"
3
3
  task :install do
4
- if defined?(Webpacker::Engine)
5
- Rake::Task["tailwindcss:install:webpacker"].invoke
6
- else
7
- Rake::Task["tailwindcss:install:asset_pipeline"].invoke
8
- end
9
- end
10
-
11
- namespace :install do
12
- desc "Install Tailwind CSS with the asset pipeline"
13
- task :asset_pipeline do
14
- run_install_template "tailwindcss_with_asset_pipeline"
15
- end
16
-
17
- desc "Install Tailwind CSS with webpacker"
18
- task :webpacker do
19
- run_install_template "tailwindcss_with_webpacker"
20
- end
4
+ system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../install/tailwindcss.rb", __dir__)}"
21
5
  end
22
6
 
23
7
  desc "Show the list of class names being kept in Tailwind CSS"
@@ -31,10 +15,6 @@ namespace :tailwindcss do
31
15
  end
32
16
  end
33
17
 
34
- def run_install_template(path)
35
- system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../install/#{path}.rb", __dir__)}"
36
- end
37
-
38
18
  def default_files_with_class_names
39
19
  Rails.root.glob("app/views/**/*.*") + Rails.root.glob("app/helpers/**/*.rb")
40
20
  end
@@ -42,3 +22,4 @@ end
42
22
  def tailwind_css
43
23
  Pathname.new(__FILE__).join("../../../app/assets/stylesheets/tailwind.css").read
44
24
  end
25
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tailwindcss-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-19 00:00:00.000000000 Z
11
+ date: 2021-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 6.0.0
27
- description:
27
+ description:
28
28
  email: david@loudthinking.com
29
29
  executables: []
30
30
  extensions: []
@@ -51,9 +51,7 @@ files:
51
51
  - app/assets/fonts/Inter-roman.vietnamese.var.woff2
52
52
  - app/assets/stylesheets/inter-font.css.erb
53
53
  - app/assets/stylesheets/tailwind.css
54
- - lib/install/stylesheets/application.scss
55
- - lib/install/tailwindcss_with_asset_pipeline.rb
56
- - lib/install/tailwindcss_with_webpacker.rb
54
+ - lib/install/tailwindcss.rb
57
55
  - lib/tailwindcss-rails.rb
58
56
  - lib/tailwindcss/compressor.rb
59
57
  - lib/tailwindcss/engine.rb
@@ -65,7 +63,7 @@ licenses:
65
63
  - MIT
66
64
  metadata:
67
65
  homepage_uri: https://github.com/rails/tailwindcss-rails
68
- post_install_message:
66
+ post_install_message:
69
67
  rdoc_options: []
70
68
  require_paths:
71
69
  - lib
@@ -80,8 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
78
  - !ruby/object:Gem::Version
81
79
  version: '0'
82
80
  requirements: []
83
- rubygems_version: 3.1.2
84
- signing_key:
81
+ rubygems_version: 3.1.4
82
+ signing_key:
85
83
  specification_version: 4
86
84
  summary: Integrate Tailwind CSS with the asset pipeline in Rails.
87
85
  test_files: []
@@ -1,3 +0,0 @@
1
- @import "tailwindcss/base";
2
- @import "tailwindcss/components";
3
- @import "tailwindcss/utilities";
@@ -1,24 +0,0 @@
1
- LATEST_WEBPACKER = "\"@rails\/webpacker\": \"rails\/webpacker#b6c2180\","
2
- WEBPACK_STYLESHEETS_PATH = "#{Webpacker.config.source_path}/stylesheets"
3
- APPLICATION_LAYOUT_PATH = Rails.root.join("app/views/layouts/application.html.erb")
4
-
5
- # Current webpacker version relies on an older version of PostCSS
6
- # which the latest TailwindCSS version is not compatible with
7
- gsub_file("package.json", /\"@rails\/webpacker\".*/) { |matched_line| matched_line = LATEST_WEBPACKER }
8
-
9
- say "Adding latest Tailwind CSS and postCSS"
10
- run "yarn add tailwindcss@latest postcss@latest autoprefixer@latest"
11
- insert_into_file "#{Webpacker.config.source_entry_path}/application.js", "\nrequire(\"stylesheets/application.scss\")\n"
12
-
13
- say "Adding minimal configuration for Tailwind CSS to work properly"
14
- directory Pathname.new(__dir__).join("stylesheets"), Webpacker.config.source_path.join("stylesheets")
15
-
16
- insert_into_file "postcss.config.js", "require('tailwindcss'),\n\t", before: "require('postcss-import')"
17
-
18
- if APPLICATION_LAYOUT_PATH.exist?
19
- say "Add Tailwindcss include tags in application layout"
20
- insert_into_file Rails.root.join("app/views/layouts/application.html.erb").to_s, %(\n <%= stylesheet_pack_tag "application", "data-turbo-track": "reload" %>), before: /\s*<\/head>/
21
- else
22
- say "Default application.html.erb is missing!", :red
23
- say %( Add <%= stylesheet_pack_tag "application", "data-turbo-track": "reload" %> within the <head> tag in your custom layout.)
24
- end