tailwindcss-rails 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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