Skip to content

Commit 30bf340

Browse files
committed
use a local tailwindcss binary by setting TAILWINDCSS_INSTALL_DIR
this will work for both the vanilla "ruby" platform as well as override the behavior of the native platform gem.
1 parent c2fced8 commit 30bf340

File tree

3 files changed

+117
-19
lines changed

3 files changed

+117
-19
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ With Rails 7 you can generate a new application preconfigured with Tailwind by u
1212
This gem wraps [the standalone executable version](https://tailwindcss.com/blog/standalone-cli) of the Tailwind CSS v3 framework. These executables are platform specific, so there are actually separate underlying gems per platform, but the correct gem will automatically be picked for your platform. Supported platforms are Linux x64, macOS arm64, macOS x64, and Windows x64. (Note that due to this setup, you must install the actual gems – you can't pin your gem to the github repo.)
1313

1414

15+
### Using a local installation of `tailwindcss`
16+
17+
If you are not able to use the vendored upstream executables (for example, if you're on a BSD platform), you can force `tailwindcss-rails` to use a local installation of the `tailwindcss` executable by setting an environment variable named `TAILWINDCSS_INSTALL_DIR` to the directory containing the executable.
18+
19+
For example, if you've installed `tailwindcss` so that the executable is found at `/nix/store/asdfasdf-tailwindcss-3.3.0/bin/tailwindcss`, then you should set your environment variable like so:
20+
21+
``` sh
22+
TAILWINDCSS_INSTALL_DIR=/nix/store/asdfasdf-tailwindcss-3.3.0/bin
23+
```
24+
25+
1526
## Developing with Tailwindcss
1627

1728
### Configuration

lib/tailwindcss/commands.rb

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
module Tailwindcss
44
module Commands
5+
DEFAULT_DIR = File.expand_path(File.join(__dir__, "..", "..", "exe"))
6+
57
# raised when the host platform is not supported by upstream tailwindcss's binary releases
68
class UnsupportedPlatformException < StandardError
79
end
@@ -10,26 +12,41 @@ class UnsupportedPlatformException < StandardError
1012
class ExecutableNotFoundException < StandardError
1113
end
1214

15+
# raised when TAILWINDCSS_INSTALL_DIR does not exist
16+
class DirectoryNotFoundException < StandardError
17+
end
18+
1319
class << self
1420
def platform
1521
[:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-")
1622
end
1723

18-
def executable(
19-
exe_path: File.expand_path(File.join(__dir__, "..", "..", "exe"))
20-
)
21-
if Tailwindcss::Upstream::NATIVE_PLATFORMS.keys.none? { |p| Gem::Platform.match(Gem::Platform.new(p)) }
22-
raise UnsupportedPlatformException, <<~MESSAGE
23-
tailwindcss-rails does not support the #{platform} platform
24-
Please install tailwindcss following instructions at https://tailwindcss.com/docs/installation
25-
MESSAGE
26-
end
27-
28-
exe_path = Dir.glob(File.expand_path(File.join(exe_path, "*", "tailwindcss"))).find do |f|
29-
Gem::Platform.match(Gem::Platform.new(File.basename(File.dirname(f))))
24+
def executable(exe_path: DEFAULT_DIR)
25+
tailwindcss_install_dir = ENV["TAILWINDCSS_INSTALL_DIR"]
26+
if tailwindcss_install_dir.present?
27+
if File.directory?(tailwindcss_install_dir)
28+
warn "NOTE: using TAILWINDCSS_INSTALL_DIR to find tailwindcss executable: #{tailwindcss_install_dir}"
29+
exe_path = tailwindcss_install_dir
30+
exe_file = File.expand_path(File.join(tailwindcss_install_dir, "tailwindcss"))
31+
else
32+
raise DirectoryNotFoundException, <<~MESSAGE
33+
TAILWINDCSS_INSTALL_DIR is set to #{tailwindcss_install_dir}, but that directory does not exist.
34+
MESSAGE
35+
end
36+
else
37+
if Tailwindcss::Upstream::NATIVE_PLATFORMS.keys.none? { |p| Gem::Platform.match(Gem::Platform.new(p)) }
38+
raise UnsupportedPlatformException, <<~MESSAGE
39+
tailwindcss-rails does not support the #{platform} platform
40+
Please install tailwindcss following instructions at https://tailwindcss.com/docs/installation
41+
MESSAGE
42+
end
43+
44+
exe_file = Dir.glob(File.expand_path(File.join(exe_path, "*", "tailwindcss"))).find do |f|
45+
Gem::Platform.match(Gem::Platform.new(File.basename(File.dirname(f))))
46+
end
3047
end
3148

32-
if exe_path.nil?
49+
unless exe_file.present? && File.exist?(exe_file) && File.executable?(exe_file)
3350
raise ExecutableNotFoundException, <<~MESSAGE
3451
Cannot find the tailwindcss executable for #{platform} in #{exe_path}
3552
@@ -52,7 +69,7 @@ def executable(
5269
MESSAGE
5370
end
5471

55-
exe_path
72+
exe_file
5673
end
5774

5875
def compile_command(debug: false, **kwargs)

test/lib/tailwindcss/commands_test.rb

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,32 @@
22
require "minitest/mock"
33

44
class Tailwindcss::CommandsTest < ActiveSupport::TestCase
5-
test ".platform is a string containing just the cpu and os (not the version)" do
6-
expected = "#{Gem::Platform.local.cpu}-#{Gem::Platform.local.os}"
7-
assert_equal(expected, Tailwindcss::Commands.platform)
8-
end
9-
105
def mock_exe_directory(platform)
116
Dir.mktmpdir do |dir|
127
FileUtils.mkdir(File.join(dir, platform))
138
path = File.join(dir, platform, "tailwindcss")
149
FileUtils.touch(path)
10+
FileUtils.chmod("ugo+x", path)
1511
Gem::Platform.stub(:match, true) do
1612
yield(dir, path)
1713
end
1814
end
1915
end
2016

17+
def mock_local_tailwindcss_install
18+
Dir.mktmpdir do |dir|
19+
path = File.join(dir, "tailwindcss")
20+
FileUtils.touch(path)
21+
FileUtils.chmod("ugo+x", path)
22+
yield(dir, path)
23+
end
24+
end
25+
26+
test ".platform is a string containing just the cpu and os (not the version)" do
27+
expected = "#{Gem::Platform.local.cpu}-#{Gem::Platform.local.os}"
28+
assert_equal(expected, Tailwindcss::Commands.platform)
29+
end
30+
2131
test ".executable returns the absolute path to the binary" do
2232
mock_exe_directory("sparc-solaris2.8") do |dir, executable|
2333
expected = File.expand_path(File.join(dir, "sparc-solaris2.8", "tailwindcss"))
@@ -42,6 +52,66 @@ def mock_exe_directory(platform)
4252
end
4353
end
4454

55+
test ".executable returns the executable in TAILWINDCSS_INSTALL_DIR when no packaged binary exists" do
56+
mock_local_tailwindcss_install do |local_install_dir, expected|
57+
result = nil
58+
begin
59+
ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir
60+
assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do
61+
result = Tailwindcss::Commands.executable(exe_path: "/does/not/exist")
62+
end
63+
ensure
64+
ENV["TAILWINDCSS_INSTALL_DIR"] = nil
65+
end
66+
assert_equal(expected, result)
67+
end
68+
end
69+
70+
test ".executable returns the executable in TAILWINDCSS_INSTALL_DIR when we're not on a supported platform" do
71+
Gem::Platform.stub(:match, false) do # nothing is supported
72+
mock_local_tailwindcss_install do |local_install_dir, expected|
73+
result = nil
74+
begin
75+
ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir
76+
assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do
77+
result = Tailwindcss::Commands.executable
78+
end
79+
ensure
80+
ENV["TAILWINDCSS_INSTALL_DIR"] = nil
81+
end
82+
assert_equal(expected, result)
83+
end
84+
end
85+
end
86+
87+
test ".executable returns the executable in TAILWINDCSS_INSTALL_DIR even when a packaged binary exists" do
88+
mock_exe_directory("sparc-solaris2.8") do |dir, _executable|
89+
mock_local_tailwindcss_install do |local_install_dir, expected|
90+
result = nil
91+
begin
92+
ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir
93+
assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do
94+
result = Tailwindcss::Commands.executable(exe_path: dir)
95+
end
96+
ensure
97+
ENV["TAILWINDCSS_INSTALL_DIR"] = nil
98+
end
99+
assert_equal(expected, result)
100+
end
101+
end
102+
end
103+
104+
test ".executable raises ExecutableNotFoundException is TAILWINDCSS_INSTALL_DIR is set to a nonexistent dir" do
105+
begin
106+
ENV["TAILWINDCSS_INSTALL_DIR"] = "/does/not/exist"
107+
assert_raises(Tailwindcss::Commands::DirectoryNotFoundException) do
108+
Tailwindcss::Commands.executable
109+
end
110+
ensure
111+
ENV["TAILWINDCSS_INSTALL_DIR"] = nil
112+
end
113+
end
114+
45115
test ".compile_command" do
46116
mock_exe_directory("sparc-solaris2.8") do |dir, executable|
47117
Rails.stub(:root, File) do # Rails.root won't work in this test suite

0 commit comments

Comments
 (0)