tailwindcss-rails 0.3.3 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -13
- data/app/assets/stylesheets/tailwind.css +172198 -158668
- data/lib/install/tailwindcss.rb +17 -0
- data/lib/tailwindcss/purger.rb +94 -34
- data/lib/tailwindcss/version.rb +1 -1
- data/lib/tasks/tailwindcss_tasks.rake +2 -21
- metadata +4 -6
- data/lib/install/stylesheets/application.scss +0 -3
- data/lib/install/tailwindcss_with_asset_pipeline.rb +0 -12
- data/lib/install/tailwindcss_with_webpacker.rb +0 -22
@@ -0,0 +1,17 @@
|
|
1
|
+
APPLICATION_LAYOUT_PATH = Rails.root.join("app/views/layouts/application.html.erb")
|
2
|
+
|
3
|
+
if APPLICATION_LAYOUT_PATH.exist?
|
4
|
+
say "Add Tailwindcss include tags in application layout"
|
5
|
+
insert_into_file Rails.root.join("app/views/layouts/application.html.erb").to_s, %(\n <%= stylesheet_link_tag "inter-font", "data-turbo-track": "reload" %>\n <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>), before: /^\s*<%= stylesheet_link_tag/
|
6
|
+
else
|
7
|
+
say "Default application.html.erb is missing!", :red
|
8
|
+
say %( Add <%= stylesheet_link_tag "inter-font", "data-turbo-track": "reload" %> and <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %> within the <head> tag in your custom layout.)
|
9
|
+
end
|
10
|
+
|
11
|
+
# No longer included by default in Rails 7, but for earlier versions of Rails
|
12
|
+
if (scaffolds_css_path = Rails.root.join("app/assets/stylesheets/scaffolds.scss")).exist?
|
13
|
+
remove_file scaffolds_css_path
|
14
|
+
end
|
15
|
+
|
16
|
+
say "Turn on purging of unused css classes in production"
|
17
|
+
gsub_file Rails.root.join("config/environments/production.rb"), /^\s+#?\s+config.assets.css_compressor =.*$/, %( config.assets.css_compressor = :purger)
|
data/lib/tailwindcss/purger.rb
CHANGED
@@ -1,8 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Tailwindcss::Purger
|
2
|
-
CLASS_NAME_PATTERN
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
CLASS_NAME_PATTERN = /((?:[:A-Za-z0-9_-]+[\\\/:A-Za-z0-9_-]*[0-3][\\.]*5)|(?:[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).flatten.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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
60
|
+
conveyor.output
|
51
61
|
end
|
52
62
|
|
53
63
|
private
|
54
|
-
def
|
55
|
-
|
56
|
-
.
|
57
|
-
.
|
58
|
-
|
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
|
-
|
62
|
-
output
|
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
|
data/lib/tailwindcss/version.rb
CHANGED
@@ -1,23 +1,7 @@
|
|
1
1
|
namespace :tailwindcss do
|
2
2
|
desc "Install Tailwind CSS into the app"
|
3
3
|
task :install do
|
4
|
-
|
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.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -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/
|
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
|
@@ -80,7 +78,7 @@ 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.
|
81
|
+
rubygems_version: 3.1.4
|
84
82
|
signing_key:
|
85
83
|
specification_version: 4
|
86
84
|
summary: Integrate Tailwind CSS with the asset pipeline in Rails.
|
@@ -1,12 +0,0 @@
|
|
1
|
-
APPLICATION_LAYOUT_PATH = Rails.root.join("app/views/layouts/application.html.erb")
|
2
|
-
|
3
|
-
if APPLICATION_LAYOUT_PATH.exist?
|
4
|
-
say "Add Tailwindcss include tags in application layout"
|
5
|
-
insert_into_file Rails.root.join("app/views/layouts/application.html.erb").to_s, %(\n <%= stylesheet_link_tag "inter-font" %>\n <%= stylesheet_link_tag "tailwind" %>), before: /^\s*<%= stylesheet_link_tag/
|
6
|
-
else
|
7
|
-
say "Default application.html.erb is missing!", :red
|
8
|
-
say %( Add <%= stylesheet_link_tag "inter-font" %> and <%= stylesheet_link_tag "tailwind" %> within the <head> tag in your custom layout.)
|
9
|
-
end
|
10
|
-
|
11
|
-
say "Turn on purging of unused css classes in production"
|
12
|
-
gsub_file Rails.root.join("config/environments/production.rb"), /^\s+#?\s+config.assets.css_compressor =.*$/, %( config.assets.css_compressor = :purger)
|
@@ -1,22 +0,0 @@
|
|
1
|
-
WEBPACK_STYLESHEETS_PATH = "#{Webpacker.config.source_path}/stylesheets"
|
2
|
-
APPLICATION_LAYOUT_PATH = Rails.root.join("app/views/layouts/application.html.erb")
|
3
|
-
|
4
|
-
say "Installing Tailwind CSS"
|
5
|
-
run "yarn add tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9"
|
6
|
-
insert_into_file "#{Webpacker.config.source_entry_path}/application.js", "\nimport \"stylesheets/application\"\n"
|
7
|
-
|
8
|
-
say "Configuring Tailwind CSS"
|
9
|
-
directory Pathname.new(__dir__).join("stylesheets"), Webpacker.config.source_path.join("stylesheets")
|
10
|
-
Dir.chdir(WEBPACK_STYLESHEETS_PATH) { run "npx tailwindcss init" }
|
11
|
-
|
12
|
-
insert_into_file "postcss.config.js", "require('tailwindcss')(\"./app/javascript/stylesheets/tailwind.config.js\"),\n ",
|
13
|
-
before: "require('postcss-import')"
|
14
|
-
|
15
|
-
|
16
|
-
if APPLICATION_LAYOUT_PATH.exist?
|
17
|
-
say "Add Tailwindcss include tags in application layout"
|
18
|
-
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>/
|
19
|
-
else
|
20
|
-
say "Default application.html.erb is missing!", :red
|
21
|
-
say %( Add <%= stylesheet_pack_tag "application", "data-turbo-track": "reload" %> within the <head> tag in your custom layout.)
|
22
|
-
end
|