Skip to content

Commit fa95991

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 fa95991

File tree

4 files changed

+127
-20
lines changed

4 files changed

+127
-20
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
## next / unreleased
33

44
* Update to [Tailwind CSS v3.3.0](https://github.com/tailwindlabs/tailwindcss/releases/tag/v3.3.0) by @tysongach
5+
* Users can use a locally-installed `tailwindcss` executable by setting a `TAILWINDCSS_INSTALL_DIR` environment variable. (#224, #226) by @flavorjones
56

67

78
## v2.0.25 / 2023-03-14

Diff for: README.md

+22-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,28 @@ With Rails 7 you can generate a new application preconfigured with Tailwind by u
99
1. Run `./bin/bundle add tailwindcss-rails`
1010
2. Run `./bin/rails tailwindcss:install`
1111

12-
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.)
12+
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.
13+
14+
Supported platforms are:
15+
16+
- arm64-darwin (macos-arm64)
17+
- x64-mingw32 (windows-x64)
18+
- x64-mingw-ucr (windows-x64)
19+
- x86_64-darwin (macos-x64)
20+
- x86_64-linux (linux-x64)
21+
- aarch64-linux (linux-arm64)
22+
- arm-linux (linux-armv7)
23+
24+
25+
### Using a local installation of `tailwindcss`
26+
27+
If you are not able to use the vendored standalone executables (for example, if you're on an unsupported platform), you can use a local installation of the `tailwindcss` executable by setting an environment variable named `TAILWINDCSS_INSTALL_DIR` to the directory containing the executable.
28+
29+
For example, if you've installed `tailwindcss` so that the executable is found at `/path/to/node_modules/bin/tailwindcss`, then you should set your environment variable like so:
30+
31+
``` sh
32+
TAILWINDCSS_INSTALL_DIR=/path/to/node_modules/bin
33+
```
1334

1435

1536
## Developing with Tailwindcss

Diff for: lib/tailwindcss/commands.rb

+31-14
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
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+
if exe_file.nil? || !File.exist?(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)

Diff for: test/lib/tailwindcss/commands_test.rb

+73-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
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))
@@ -18,6 +13,19 @@ def mock_exe_directory(platform)
1813
end
1914
end
2015

16+
def mock_local_tailwindcss_install
17+
Dir.mktmpdir do |dir|
18+
path = File.join(dir, "tailwindcss")
19+
FileUtils.touch(path)
20+
yield(dir, path)
21+
end
22+
end
23+
24+
test ".platform is a string containing just the cpu and os (not the version)" do
25+
expected = "#{Gem::Platform.local.cpu}-#{Gem::Platform.local.os}"
26+
assert_equal(expected, Tailwindcss::Commands.platform)
27+
end
28+
2129
test ".executable returns the absolute path to the binary" do
2230
mock_exe_directory("sparc-solaris2.8") do |dir, executable|
2331
expected = File.expand_path(File.join(dir, "sparc-solaris2.8", "tailwindcss"))
@@ -42,6 +50,66 @@ def mock_exe_directory(platform)
4250
end
4351
end
4452

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

0 commit comments

Comments
 (0)