├── .github └── workflows │ ├── ci.yml │ └── downstream.yml ├── .gitignore ├── .standard.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── LICENSE-DEPENDENCIES ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── bump-upstream ├── console └── setup ├── exe └── tailwindcss ├── lib └── tailwindcss │ ├── ruby.rb │ └── ruby │ ├── upstream.rb │ └── version.rb ├── rakelib └── package.rake ├── tailwindcss-ruby.gemspec └── test ├── tailwindcss └── test_ruby.rb └── test_helper.rb /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | concurrency: 3 | group: "${{github.workflow}}-${{github.ref}}" 4 | cancel-in-progress: true 5 | on: 6 | workflow_dispatch: 7 | push: 8 | branches: 9 | - main 10 | tags: 11 | - v*.*.* 12 | pull_request: 13 | types: [opened, synchronize] 14 | branches: 15 | - '*' 16 | 17 | jobs: 18 | test: 19 | runs-on: ubuntu-latest 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | ruby: ["3.0", "3.1", "3.2", "3.3", "3.4", "head"] 24 | steps: 25 | - uses: actions/checkout@v4 26 | - run: rm Gemfile.lock 27 | - uses: ruby/setup-ruby@v1 28 | with: 29 | ruby-version: ${{matrix.ruby}} 30 | bundler: latest 31 | bundler-cache: true 32 | - name: Run tests 33 | run: bundle exec rake test 34 | 35 | package: 36 | needs: [ "test" ] 37 | name: "package (${{ matrix.platform }})" 38 | strategy: 39 | fail-fast: false 40 | matrix: 41 | platform: 42 | - "ruby" 43 | - "aarch64-linux-gnu" 44 | - "aarch64-linux-musl" 45 | - "arm64-darwin" 46 | - "x64-mingw-ucrt" 47 | - "x64-mingw32" 48 | - "x86_64-darwin" 49 | - "x86_64-linux-gnu" 50 | - "x86_64-linux-musl" 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v4 54 | - run: rm Gemfile.lock 55 | - uses: ruby/setup-ruby@v1 56 | with: 57 | ruby-version: "3.2" 58 | bundler: latest 59 | bundler-cache: true 60 | - run: "bundle exec rake gem:${{matrix.platform}}" 61 | - uses: actions/upload-artifact@v4 62 | with: 63 | name: gem-${{matrix.platform}} 64 | path: pkg 65 | retention-days: 1 66 | 67 | install-ruby: 68 | name: "install (ruby)" 69 | needs: [ "package" ] 70 | runs-on: ubuntu-latest 71 | steps: 72 | - uses: ruby/setup-ruby@v1 73 | with: 74 | ruby-version: "3.2" 75 | - uses: actions/download-artifact@v4 76 | with: 77 | name: gem-ruby 78 | path: pkg 79 | - run: "gem install pkg/tailwindcss-ruby-*.gem" 80 | - run: "tailwindcss 2>&1 | fgrep 'ERROR: Cannot find the tailwindcss executable'" 81 | 82 | install-native: 83 | name: "install (${{ matrix.platform }})" 84 | needs: [ "package" ] 85 | strategy: 86 | fail-fast: false 87 | matrix: 88 | ruby: [ "3.4" ] 89 | platform: 90 | - "aarch64-linux-gnu" 91 | - "aarch64-linux-musl" 92 | - "arm64-darwin" 93 | - "x64-mingw-ucrt" 94 | # - "x64-mingw32" # because it's on a different version of ruby, we just add it in an "include" below 95 | - "x86_64-darwin" 96 | - "x86_64-linux-gnu" 97 | - "x86_64-linux-musl" 98 | include: 99 | - { platform: aarch64-linux-gnu, docker_platform: "--platform=linux/arm64/v8" } 100 | - { platform: aarch64-linux-musl, docker_tag: "-alpine", docker_platform: "--platform=linux/arm64/v8", bootstrap: "apk add build-base &&" } 101 | - { platform: arm64-darwin, runs_on: macos-14 } 102 | - { platform: x64-mingw-ucrt, runs_on: windows-latest } 103 | - { platform: x64-mingw32, runs_on: windows-latest, ruby: "3.0" } 104 | - { platform: x86_64-darwin, runs_on: macos-13 } 105 | - { platform: x86_64-linux-musl, docker_tag: "-alpine", bootstrap: "apk add build-base &&" } 106 | runs-on: ${{ matrix.runs_on || 'ubuntu-latest' }} 107 | steps: 108 | - uses: actions/download-artifact@v4 109 | with: 110 | name: gem-${{ matrix.platform }} 111 | path: pkg 112 | - if: ${{ matrix.runs_on }} 113 | uses: ruby/setup-ruby@v1 114 | with: 115 | ruby-version: ${{ matrix.ruby }} 116 | - if: ${{ matrix.runs_on }} 117 | run: "gem install pkg/tailwindcss-ruby-*.gem" 118 | - if: ${{ matrix.runs_on }} 119 | run: "tailwindcss --help" 120 | - if: ${{ (! matrix.runs_on) && matrix.docker_platform }} 121 | run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes 122 | - if: ${{ ! matrix.runs_on }} 123 | run: | 124 | docker run --rm -v $PWD:/tailwindcss-ruby -w /tailwindcss-ruby \ 125 | ${{ matrix.docker_platform }} ruby:${{ matrix.ruby }}${{ matrix.docker_tag }} \ 126 | sh -c " 127 | ${{ matrix.bootstrap }} 128 | gem install pkg/tailwindcss-ruby-*.gem 129 | tailwindcss --help 130 | " 131 | -------------------------------------------------------------------------------- /.github/workflows/downstream.yml: -------------------------------------------------------------------------------- 1 | name: downstream 2 | concurrency: 3 | group: "${{github.workflow}}-${{github.ref}}" 4 | cancel-in-progress: true 5 | on: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: "0 8 * * 1,3,5" # At 08:00 on Monday, Wednesday, and Friday # https://crontab.guru/#0_8_*_*_1,3,5 9 | push: 10 | branches: 11 | - main 12 | tags: 13 | - v*.*.* 14 | pull_request: 15 | types: [opened, synchronize] 16 | branches: 17 | - '*' 18 | 19 | jobs: 20 | downstream: 21 | name: downstream-${{matrix.name}} 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | include: 26 | - url: https://github.com/rails/tailwindcss-rails 27 | name: rails-unit 28 | command: "bin/test" 29 | ruby: "3.4" 30 | - url: https://github.com/rails/tailwindcss-rails 31 | name: rails-install 32 | command: "env TAILWINDCSSOPTS=--path=../../.. test/integration/user_install_test.sh" 33 | ruby: "3.4" 34 | - url: https://github.com/rails/tailwindcss-rails 35 | name: rails-upgrade 36 | command: "env TAILWINDCSSOPTS=--path=../../.. test/integration/user_upgrade_test.sh" 37 | ruby: "3.4" 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v4 41 | - uses: ruby/setup-ruby@v1 42 | with: 43 | ruby-version: ${{matrix.ruby}} 44 | - run: bundle install --local || bundle install 45 | - run: bundle exec rake download 46 | - run: git clone --depth=1 ${{matrix.url}} ${{matrix.name}} 47 | - name: ${{matrix.name}} test suite 48 | working-directory: ${{matrix.name}} 49 | run: | 50 | rm -f Gemfile.lock 51 | bundle remove tailwindcss-ruby || true 52 | bundle add tailwindcss-ruby --path=".." 53 | bundle install --local || bundle install 54 | ${{matrix.command}} 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /exe/*/tailwindcss 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | -------------------------------------------------------------------------------- /.standard.yml: -------------------------------------------------------------------------------- 1 | # For available configuration options, see: 2 | # https://github.com/standardrb/standard 3 | ruby_version: 3.0 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # tailwindcss-ruby changelog 2 | 3 | ## v4.1.8 4 | 5 | * Update to [Tailwind CSS v4.1.8](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.1.8) @flavorjones 6 | 7 | 8 | ## v4.1.7 9 | 10 | * Update to [Tailwind CSS v4.1.7](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.1.7) @flavorjones 11 | 12 | 13 | ## v4.1.6 14 | 15 | * Update to [Tailwind CSS v4.1.6](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.1.6) @flavorjones 16 | 17 | 18 | ## v4.1.5 19 | 20 | * Update to [Tailwind CSS v4.1.5](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.1.5) @flavorjones 21 | 22 | 23 | ## v4.1.4 24 | 25 | * Update to [Tailwind CSS v4.1.4](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.1.4) @flavorjones 26 | 27 | 28 | ## v4.1.3 29 | 30 | * Update to [Tailwind CSS v4.1.3](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.1.3) @flavorjones 31 | 32 | 33 | ## v4.0.17 34 | 35 | * Update to [Tailwind CSS v4.0.17](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.17) @flavorjones 36 | 37 | 38 | ## v4.0.16 39 | 40 | * Update to [Tailwind CSS v4.0.16](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.16) @flavorjones 41 | 42 | 43 | ## v4.0.15 44 | 45 | * Update to [Tailwind CSS v4.0.15](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.15) @flavorjones 46 | 47 | 48 | ## v4.0.14 49 | 50 | * Update to [Tailwind CSS v4.0.14](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.14) @flavorjones 51 | 52 | 53 | ## v4.0.12 54 | 55 | * Update to [Tailwind CSS v4.0.12](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.12) @flavorjones 56 | 57 | 58 | ## v4.0.9 59 | 60 | * Update to [Tailwind CSS v4.0.9](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.9) @flavorjones 61 | 62 | 63 | ## v4.0.8 64 | 65 | * Update to [Tailwind CSS v4.0.8](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.8) @flavorjones 66 | 67 | 68 | ## v4.0.7 69 | 70 | * Update to [Tailwind CSS v4.0.7](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.7) @flavorjones 71 | 72 | 73 | ## v4.0.6 74 | 75 | * Update to [Tailwind CSS v4.0.6](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.6) @flavorjones 76 | 77 | Upgrade guide at https://tailwindcss.com/docs/upgrade-guide 78 | 79 | 80 | ## v4.0.5 81 | 82 | * Update to [Tailwind CSS v4.0.5](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.5) @flavorjones 83 | 84 | Upgrade guide at https://tailwindcss.com/docs/upgrade-guide 85 | 86 | 87 | ## v4.0.4 88 | 89 | * Update to [Tailwind CSS v4.0.4](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.4) @flavorjones 90 | 91 | Upgrade guide at https://tailwindcss.com/docs/upgrade-guide 92 | 93 | 94 | ## v4.0.3 95 | 96 | * Update to [Tailwind CSS v4.0.3](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.3) @flavorjones 97 | 98 | Upgrade guide at https://tailwindcss.com/docs/upgrade-guide 99 | 100 | 101 | ## v4.0.2 102 | 103 | * Update to [Tailwind CSS v4.0.2](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.2) @flavorjones 104 | 105 | Upgrade guide at https://tailwindcss.com/docs/upgrade-guide 106 | 107 | 108 | ## v4.0.1 109 | 110 | * Update to [Tailwind CSS v4.0.1](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.1) @flavorjones 111 | 112 | Upgrade guide at https://tailwindcss.com/docs/upgrade-guide 113 | 114 | 115 | ## v4.0.0 116 | 117 | * Update to [Tailwind CSS v4.0.0](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0) @flavorjones 118 | 119 | The upstream upgrade guide is at https://tailwindcss.com/docs/upgrade-guide. 120 | 121 | For Rails users, if you want to upgrade you may want to check out [TailwindCSS v4 - upgrade experience report · rails/tailwindcss-rails · Discussion #450](https://github.com/rails/tailwindcss-rails/discussions/450). If you're not ready to upgrade, then pin your project to the 3.x releases: 122 | 123 | ```ruby 124 | # If you're not ready to upgrade yet! 125 | gem "tailwindcss-ruby", "~> 3.4" 126 | ``` 127 | 128 | 129 | ## v4.0.0.beta.10 130 | 131 | * Update to [Tailwind CSS v4.0.0-beta.10](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.10) @excid3 132 | 133 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 134 | 135 | Note that this upstream release finally includes linux-musl binaries, and so the native gem platforms are now specialized to `{x86_64,aarch64}-linux-{gnu,musl}`. You may need to update the platforms in your Gemfile.lock using `bundle lock --add-platform`. 136 | 137 | However, there are still no upstream armv7 binaries. 138 | 139 | ## v4.0.0.beta.9 140 | 141 | * Update to [Tailwind CSS v4.0.0-beta.9](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.9) @flavorjones 142 | 143 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 144 | 145 | Note that this upstream release finally includes linux-musl binaries, and so the native gem platforms are now specialized to `{x86_64,aarch64}-linux-{gnu,musl}`. You may need to update the platforms in your Gemfile.lock using `bundle lock --add-platform`. 146 | 147 | However, there are still no upstream armv7 binaries. 148 | 149 | 150 | ## v4.0.0.beta.8 151 | 152 | * Update to [Tailwind CSS v4.0.0-beta.8](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.8) @flavorjones 153 | 154 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 155 | 156 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 157 | 158 | 159 | ## v4.0.0.beta.6 160 | 161 | * Update to [Tailwind CSS v4.0.0-beta.6](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.6) @flavorjones 162 | 163 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 164 | 165 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 166 | 167 | 168 | ## v4.0.0.beta.5 169 | 170 | * Update to [Tailwind CSS v4.0.0-beta.5](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.5) @flavorjones 171 | 172 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 173 | 174 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 175 | 176 | 177 | ## v4.0.0.beta.4 178 | 179 | * Update to [Tailwind CSS v4.0.0-beta.4](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.4) @flavorjones 180 | 181 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 182 | 183 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 184 | 185 | 186 | ## v4.0.0.beta.3 187 | 188 | * Update to [Tailwind CSS v4.0.0-beta.3](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.3) @flavorjones 189 | 190 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 191 | 192 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 193 | 194 | 195 | ## v4.0.0.beta.2 196 | 197 | * Update to [Tailwind CSS v4.0.0-beta.2](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.2) @flavorjones 198 | 199 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 200 | 201 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 202 | 203 | 204 | ## v4.0.0.beta.1 205 | 206 | * Update to [Tailwind CSS v4.0.0-beta.1](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-beta.1) (#26) @flavorjones 207 | 208 | Prerelease documentation at https://tailwindcss.com/docs/v4-beta 209 | 210 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 211 | 212 | 213 | ## v4.0.0.alpha.36 214 | 215 | * Update to [Tailwind CSS v4.0.0-alpha.36](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.36). Also see release notes for [Tailwind CSS v4.0.0-alpha.35](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.35) (#25) @flavorjones 216 | 217 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 218 | 219 | 220 | ## v4.0.0.alpha.34 221 | 222 | * Update to [Tailwind CSS v4.0.0-alpha.34](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.34) (#18) @flavorjones 223 | 224 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 225 | 226 | 227 | ## v4.0.0.alpha.33 228 | 229 | * Update to [Tailwind CSS v4.0.0-alpha.33](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.33). Also see release notes for [Tailwind CSS v4.0.0-alpha.32](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.32) (#17) @flavorjones 230 | 231 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 232 | 233 | 234 | ## v4.0.0.alpha.31 235 | 236 | * Update to [Tailwind CSS v4.0.0-alpha.31](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.31) (#16) @flavorjones 237 | 238 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 239 | 240 | 241 | ## v4.0.0.alpha.30 242 | 243 | * Update to [Tailwind CSS v4.0.0-alpha.30](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.30) (#15) @flavorjones 244 | 245 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 246 | 247 | 248 | ## v4.0.0.alpha.29 249 | 250 | * Update to [Tailwind CSS v4.0.0-alpha.29](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.29) (#14) @flavorjones 251 | 252 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 253 | 254 | 255 | ## v4.0.0.alpha.28 256 | 257 | * Update to [Tailwind CSS v4.0.0-alpha.28](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.28) (#10) @flavorjones 258 | 259 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 260 | 261 | 262 | ## v4.0.0.alpha.27 263 | 264 | * Update to [Tailwind CSS v4.0.0-alpha.27](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.27) (#9) @flavorjones 265 | 266 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 267 | 268 | 269 | ## v4.0.0.alpha.26 / 2024-10-03 270 | 271 | * Update to [Tailwind CSS v4.0.0-alpha.26](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.26) @flavorjones 272 | 273 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 274 | 275 | 276 | ## v4.0.0.alpha.25 / 2024-09-26 277 | 278 | * Update to [Tailwind CSS v4.0.0-alpha.25](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0-alpha.25) @flavorjones 279 | 280 | Note that this upstream release does not provide an armv7 release, nor a musl-compatible binary. 281 | 282 | 283 | ## v3.4.13 / 2023-09-26 284 | 285 | * This gem was extracted from `tailwindcss-rails`. 286 | 287 | In advance of the upcoming TailwindCSS v4 release, we are decoupling the `tailwindcss` executable 288 | from the Rails integration. This will allow users to upgrade TailwindCSS at a time of their 289 | choosing, and allow early adopters to start using the beta releases. 290 | 291 | It should also make it easier for non-Rails Ruby projects to use tailwindcss (e.g., Jekyll and 292 | other web frameworks). 293 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official email address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [INSERT CONTACT METHOD]. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to tailwindcss-ruby 2 | 3 | This doc is a brief introduction on modifying and maintaining this gem. 4 | 5 | ## Updating to the latest upstream tailwindcss version 6 | 7 | Please don't submit PRs to the maintainer with an upstream bump. 8 | 9 | - [ ] run `bin/bump-upstream` 10 | - [ ] push the branch, create a PR 11 | 12 | ## Cutting a release of tailwindcss-ruby 13 | 14 | - if it's just bumping the upstream: 15 | - [ ] follow the steps above 16 | - [ ] when the PR is green, merge the PR 17 | - [ ] create a git tag (after updating local `main`) 18 | - else if the gem is being changed in some other way: 19 | - [ ] update `lib/tailwindcss/ruby/version.rb` 20 | - [ ] update `CHANGELOG.md` 21 | - [ ] `git commit` 22 | - [ ] `git tag` 23 | - build the native gems: 24 | - [ ] `bundle exec rake clobber` (if needed to clean up old tailwindcss executables) 25 | - [ ] `bundle exec rake package` 26 | - push source and gems: 27 | - [ ] `for g in pkg/*.gem ; do gem push $g ; done` 28 | - [ ] `git push && git push --tags` 29 | - announce 30 | - [ ] create a release at https://github.com/flavorjones/tailwindcss-ruby/releases 31 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # Specify your gem's dependencies in tailwindcss-ruby.gemspec 6 | gemspec 7 | 8 | gem "rake", "~> 13.0" 9 | 10 | gem "minitest", "~> 5.16" 11 | 12 | gem "standard", "~> 1.3" 13 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | tailwindcss-ruby (4.1.8) 5 | 6 | GEM 7 | remote: https://rubygems.org/ 8 | specs: 9 | ast (2.4.2) 10 | json (2.10.2) 11 | language_server-protocol (3.17.0.4) 12 | lint_roller (1.1.0) 13 | minitest (5.25.4) 14 | parallel (1.26.3) 15 | parser (3.3.7.1) 16 | ast (~> 2.4.1) 17 | racc 18 | racc (1.8.1) 19 | rainbow (3.1.1) 20 | rake (13.2.1) 21 | regexp_parser (2.10.0) 22 | rubocop (1.71.2) 23 | json (~> 2.3) 24 | language_server-protocol (>= 3.17.0) 25 | parallel (~> 1.10) 26 | parser (>= 3.3.0.2) 27 | rainbow (>= 2.2.2, < 4.0) 28 | regexp_parser (>= 2.9.3, < 3.0) 29 | rubocop-ast (>= 1.38.0, < 2.0) 30 | ruby-progressbar (~> 1.7) 31 | unicode-display_width (>= 2.4.0, < 4.0) 32 | rubocop-ast (1.38.0) 33 | parser (>= 3.3.1.0) 34 | rubocop-performance (1.23.1) 35 | rubocop (>= 1.48.1, < 2.0) 36 | rubocop-ast (>= 1.31.1, < 2.0) 37 | ruby-progressbar (1.13.0) 38 | standard (1.45.0) 39 | language_server-protocol (~> 3.17.0.2) 40 | lint_roller (~> 1.0) 41 | rubocop (~> 1.71.0) 42 | standard-custom (~> 1.0.0) 43 | standard-performance (~> 1.6) 44 | standard-custom (1.0.2) 45 | lint_roller (~> 1.0) 46 | rubocop (~> 1.50) 47 | standard-performance (1.6.0) 48 | lint_roller (~> 1.1) 49 | rubocop-performance (~> 1.23.0) 50 | unicode-display_width (3.1.4) 51 | unicode-emoji (~> 4.0, >= 4.0.4) 52 | unicode-emoji (4.0.4) 53 | 54 | PLATFORMS 55 | ruby 56 | x86_64-linux 57 | 58 | DEPENDENCIES 59 | minitest (~> 5.16) 60 | rake (~> 13.0) 61 | standard (~> 1.3) 62 | tailwindcss-ruby! 63 | 64 | BUNDLED WITH 65 | 2.5.19 66 | -------------------------------------------------------------------------------- /LICENSE-DEPENDENCIES: -------------------------------------------------------------------------------- 1 | tailwindcss-ruby may redistribute executables from the https://github.com/tailwindlabs/tailwindcss project 2 | 3 | The license for that software can be found at https://github.com/tailwindlabs/tailwindcss/blob/master/LICENSE which is reproduced here for your convenience: 4 | 5 | MIT License 6 | 7 | Copyright (c) Adam Wathan 8 | Copyright (c) Jonathan Reinink 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2024 Mike Dalessio, David Heinemeier Hansson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tailwindcss::Ruby 2 | 3 | A self-contained `tailwindcss` executable, wrapped up in a ruby gem. That's it. Nothing else. 4 | 5 | If you're looking to leverage tailwindcss in your Rails project, please see https://github.com/rails/tailwindcss-rails for integration that is supported by the Rails team. 6 | 7 | 8 | ## ⚠ Upgrade note ⚠ 9 | 10 | To upgrade an existing application from v3 to v4, I strongly urge you to read the upstream upgrade guide: https://tailwindcss.com/docs/upgrade-guide. 11 | 12 | For Rails users, if you want to upgrade you may want to check out [TailwindCSS v4 - upgrade experience report · rails/tailwindcss-rails · Discussion #450](https://github.com/rails/tailwindcss-rails/discussions/450). 13 | 14 | In any case, if you're not ready to upgrade to v4, then pin your project to the 3.x releases: 15 | 16 | ```ruby 17 | # If you're not ready to upgrade yet! 18 | gem "tailwindcss-ruby", "~> 3.4" 19 | ``` 20 | 21 | 22 | ## Installation 23 | 24 | This gem wraps [the standalone executable version](https://tailwindcss.com/blog/standalone-cli) of the Tailwind CSS v4 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. 25 | 26 | Supported platforms are: 27 | 28 | - arm64-darwin (macos-arm64) 29 | - x64-mingw32 (windows-x64) 30 | - x64-mingw-ucr (windows-x64) 31 | - x86_64-darwin (macos-x64) 32 | - x86_64-linux (linux-x64) 33 | - aarch64-linux (linux-arm64) 34 | - arm-linux (linux-armv7) 35 | 36 | Install the gem and add to the application's Gemfile by executing: 37 | 38 | ```bash 39 | bundle add tailwindcss-ruby 40 | ``` 41 | 42 | If bundler is not being used to manage dependencies, install the gem by executing: 43 | 44 | ```bash 45 | gem install tailwindcss-ruby 46 | ``` 47 | 48 | ### Using a local installation of `tailwindcss` 49 | 50 | 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](https://tailwindcss.com/docs/installation) of the `tailwindcss` executable by setting an environment variable named `TAILWINDCSS_INSTALL_DIR` to the directory path containing the executable. 51 | 52 | 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: 53 | 54 | ``` sh 55 | TAILWINDCSS_INSTALL_DIR=/path/to/node_modules/bin 56 | ``` 57 | 58 | or, for relative paths like `./node_modules/.bin/tailwindcss`: 59 | 60 | ``` sh 61 | TAILWINDCSS_INSTALL_DIR=node_modules/.bin 62 | ``` 63 | 64 | 65 | ## Versioning 66 | 67 | This gem will always have the same version number as the underlying TailwindCSS release. For example, the gem with version v3.4.13 will package upstream TailwindCSS v3.4.13. 68 | 69 | If there ever needs to be multiple releases for the same version of TailwindCSS, the version will contain an additional digit. For example, if we re-released TailwindCSS v3.4.13, it might be shipped in gem version v3.4.13.1 or v3.4.13.2. 70 | 71 | 72 | ## Usage 73 | 74 | ### Ruby 75 | 76 | The gem makes available `Tailwindcss::Ruby.executable` which is the path to the vendored standalone executable. 77 | 78 | ``` ruby 79 | require "tailwindcss/ruby" 80 | Tailwindcss::Ruby.executable 81 | # => "/path/to/installs/ruby/3.3.5/lib/ruby/gems/3.3.0/gems/tailwindcss-ruby-0.1.0-x86_64-linux/exe/x86_64-linux/tailwindcss" 82 | ``` 83 | 84 | 85 | ### Command line 86 | 87 | This gem provides an executable `tailwindcss` shim that will run the vendored standalone executable. 88 | 89 | ``` bash 90 | # where is the shim? 91 | $ bundle exec which tailwindcss 92 | /path/to/installs/ruby/3.3/bin/tailwindcss 93 | 94 | # run the actual executable through the shim 95 | $ bundle exec tailwindcss --help 96 | ["/path/to/installs/installs/ruby/3.4.2/lib/ruby/gems/3.4.0/gems/tailwindcss-ruby-4.0.12-x86_64-linux-gnu/exe/x86_64-linux-gnu/tailwindcss", "--help"] 97 | ≈ tailwindcss v4.0.12 98 | 99 | Usage: 100 | tailwindcss [--input input.css] [--output output.css] [--watch] [options…] 101 | 102 | Options: 103 | -i, --input ··········· Input file 104 | -o, --output ·········· Output file [default: `-`] 105 | -w, --watch ··········· Watch for changes and rebuild as needed 106 | -m, --minify ·········· Optimize and minify the output 107 | --optimize ········ Optimize the output without minifying 108 | --cwd ············· The current working directory [default: `.`] 109 | -h, --help ············ Display usage information 110 | ``` 111 | 112 | 113 | ## Troubleshooting 114 | 115 | ### `ERROR: Cannot find the tailwindcss executable` for supported platform 116 | 117 | Some users are reporting this error even when running on one of the supported native platforms: 118 | 119 | - arm64-darwin 120 | - x64-mingw32 121 | - x64-mingw-ucrt 122 | - x86_64-darwin 123 | - x86_64-linux 124 | - aarch64-linux 125 | 126 | #### Check Bundler PLATFORMS 127 | 128 | A possible cause of this is that Bundler has not been told to include native gems for your current platform. Please check your `Gemfile.lock` file to see whether your native platform is included in the `PLATFORMS` section. If necessary, run: 129 | 130 | ``` sh 131 | bundle lock --add-platform 132 | ``` 133 | 134 | and re-bundle. 135 | 136 | 137 | #### Check BUNDLE_FORCE_RUBY_PLATFORM 138 | 139 | Another common cause of this is that bundler is configured to always use the "ruby" platform via the 140 | `BUNDLE_FORCE_RUBY_PLATFORM` config parameter being set to `true`. Please remove this configuration: 141 | 142 | ``` sh 143 | bundle config unset force_ruby_platform 144 | # or 145 | bundle config set --local force_ruby_platform false 146 | ``` 147 | 148 | and re-bundle. 149 | 150 | See https://bundler.io/man/bundle-config.1.html for more information. 151 | 152 | 153 | ## Contributing 154 | 155 | Bug reports and pull requests are welcome on GitHub at https://github.com/flavorjones/tailwindcss-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/flavorjones/tailwindcss-ruby/blob/main/CODE_OF_CONDUCT.md). 156 | 157 | ## License 158 | 159 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 160 | 161 | Tailwind CSS is [released under the MIT License](https://github.com/tailwindlabs/tailwindcss/blob/next/LICENSE). 162 | 163 | ## Code of Conduct 164 | 165 | Everyone interacting in the Tailwindcss::Ruby project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/flavorjones/tailwindcss-ruby/blob/main/CODE_OF_CONDUCT.md). 166 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | require "minitest/test_task" 5 | 6 | Minitest::TestTask.create 7 | 8 | require "standard/rake" 9 | 10 | task default: %i[test standard] 11 | -------------------------------------------------------------------------------- /bin/bump-upstream: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | if [[ $# -lt 1 ]] ; then 7 | echo "Usage: $(basename $0) " 8 | echo 9 | echo "Where is the tag name of the Tailwind CSS release." 10 | exit 1 11 | fi 12 | 13 | PAGER="" # we don't want gh to use a pager 14 | git_cmd=$(command -v git) 15 | gh_cmd=$(command -v gh) 16 | sed_cmd=$(command -v sed) 17 | 18 | fail() { 19 | echo "Error: $*" >&2 20 | exit 1 21 | } 22 | 23 | upstream_tag=$1 24 | gem_version=$(echo $upstream_tag | $sed_cmd -E 's/^v//' | sed -E 's/-/./') 25 | gem_tag="v${gem_version}" 26 | 27 | github_user=$($git_cmd config github.user || true) 28 | if [[ -z "$github_user" ]]; then 29 | fail "github.user is not set in git config" 30 | fi 31 | 32 | # view the release. will fail if the release does not exist 33 | $gh_cmd release view ${upstream_tag} --repo tailwindlabs/tailwindcss 34 | 35 | # get on the right starting branch 36 | if [[ -n "$($git_cmd status --porcelain --untracked-files=no)" ]]; then 37 | fail "found uncommitted changes" 38 | fi 39 | 40 | if [[ $upstream_tag =~ ^v4 ]] ; then 41 | base_branch="main" 42 | elif [[ $upstream_tag =~ ^v3 ]] ; then 43 | base_branch="v3.x" 44 | else 45 | fail "Whoa! A new major version? Need to update the ${0} script." 46 | fi 47 | 48 | $git_cmd switch $base_branch 49 | 50 | if ! $git_cmd rev-parse --abbrev-ref @{push} >/dev/null 2>&1; then 51 | fail "current branch is not tracking a remote branch" 52 | fi 53 | 54 | # 55 | # modify the upstream version and gem version 56 | # 57 | $sed_cmd -E -i "s/^(\s+)VERSION\s+=.*/\1VERSION = \"${upstream_tag}\"/" lib/tailwindcss/ruby/upstream.rb 58 | $sed_cmd -E -i "s/^(\s+)VERSION\s+=.*/\1VERSION = \"${gem_version}\"/" lib/tailwindcss/ruby/version.rb 59 | 60 | bundle install 61 | 62 | # 63 | # modify the changelog 64 | # 65 | replacement_text=$(cat < e 17 | STDERR.puts("ERROR: " + e.message) 18 | exit 1 19 | end 20 | -------------------------------------------------------------------------------- /lib/tailwindcss/ruby.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "ruby/version" 4 | require_relative "ruby/upstream" 5 | 6 | module Tailwindcss 7 | module Ruby 8 | DEFAULT_DIR = File.expand_path(File.join(__dir__, "..", "..", "exe")) 9 | GEM_NAME = "tailwindcss-ruby" 10 | 11 | # raised when the host platform is not supported by upstream tailwindcss's binary releases 12 | class UnsupportedPlatformException < StandardError 13 | end 14 | 15 | # raised when the tailwindcss executable could not be found where we expected it to be 16 | class ExecutableNotFoundException < StandardError 17 | end 18 | 19 | # raised when TAILWINDCSS_INSTALL_DIR does not exist 20 | class DirectoryNotFoundException < StandardError 21 | end 22 | 23 | class << self 24 | def platform 25 | [:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-") 26 | end 27 | 28 | def executable(exe_path: DEFAULT_DIR) 29 | tailwindcss_install_dir = ENV["TAILWINDCSS_INSTALL_DIR"] 30 | if tailwindcss_install_dir 31 | if File.directory?(tailwindcss_install_dir) 32 | warn "NOTE: using TAILWINDCSS_INSTALL_DIR to find tailwindcss executable: #{tailwindcss_install_dir}" 33 | exe_path = tailwindcss_install_dir 34 | exe_file = File.expand_path(File.join(tailwindcss_install_dir, "tailwindcss")) 35 | else 36 | raise DirectoryNotFoundException, <<~MESSAGE 37 | TAILWINDCSS_INSTALL_DIR is set to #{tailwindcss_install_dir}, but that directory does not exist. 38 | MESSAGE 39 | end 40 | else 41 | if Tailwindcss::Ruby::Upstream::NATIVE_PLATFORMS.keys.none? { |p| Gem::Platform.match_gem?(Gem::Platform.new(p), GEM_NAME) } 42 | raise UnsupportedPlatformException, <<~MESSAGE 43 | #{GEM_NAME} does not support the #{platform} platform 44 | See https://github.com/flavorjones/tailwindcss-ruby#using-a-local-installation-of-tailwindcss 45 | for more details. 46 | MESSAGE 47 | end 48 | 49 | exe_file = Dir.glob(File.expand_path(File.join(exe_path, "*", "tailwindcss"))).find do |f| 50 | Gem::Platform.match_gem?(Gem::Platform.new(File.basename(File.dirname(f))), GEM_NAME) 51 | end 52 | end 53 | 54 | if exe_file.nil? || !File.exist?(exe_file) 55 | raise ExecutableNotFoundException, <<~MESSAGE 56 | Cannot find the tailwindcss executable for #{platform} in #{exe_path} 57 | 58 | If you're using bundler, please make sure you're on the latest bundler version: 59 | 60 | gem install bundler 61 | bundle update --bundler 62 | 63 | Then make sure your lock file includes this platform by running: 64 | 65 | bundle lock --add-platform #{platform} 66 | bundle install 67 | 68 | See `bundle lock --help` output for details. 69 | 70 | If you're still seeing this message after taking those steps, try running 71 | `bundle config` and ensure `force_ruby_platform` isn't set to `true`. See 72 | https://github.com/flavorjones/tailwindcss-ruby#check-bundle_force_ruby_platform 73 | for more details. 74 | MESSAGE 75 | end 76 | 77 | exe_file 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/tailwindcss/ruby/upstream.rb: -------------------------------------------------------------------------------- 1 | module Tailwindcss 2 | module Ruby 3 | module Upstream 4 | VERSION = "v4.1.8" 5 | 6 | # rubygems platform name => upstream release filename 7 | NATIVE_PLATFORMS = { 8 | "arm64-darwin" => "tailwindcss-macos-arm64", 9 | "x64-mingw32" => "tailwindcss-windows-x64.exe", 10 | "x64-mingw-ucrt" => "tailwindcss-windows-x64.exe", 11 | "x86_64-darwin" => "tailwindcss-macos-x64", 12 | "x86_64-linux-gnu" => "tailwindcss-linux-x64", 13 | "x86_64-linux-musl" => "tailwindcss-linux-x64-musl", 14 | "aarch64-linux-gnu" => "tailwindcss-linux-arm64", 15 | "aarch64-linux-musl" => "tailwindcss-linux-arm64-musl", 16 | } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/tailwindcss/ruby/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Tailwindcss 4 | module Ruby 5 | VERSION = "4.1.8" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /rakelib/package.rake: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # 3 | # Rake tasks to manage native gem packages with binary executables from tailwindlabs/tailwindcss 4 | # 5 | # TL;DR: run "rake package" 6 | # 7 | # The native platform gems (defined by Tailwindcss::Ruby::Upstream::NATIVE_PLATFORMS) will each contain 8 | # two files in addition to what the vanilla ruby gem contains: 9 | # 10 | # exe/ 11 | # ├── tailwindcss # generic ruby script to find and run the binary 12 | # └── / 13 | # └── tailwindcss # the tailwindcss binary executable 14 | # 15 | # The ruby script `exe/tailwindcss` is installed into the user's path, and it simply locates the 16 | # binary and executes it. Note that this script is required because rubygems requires that 17 | # executables declared in a gemspec must be Ruby scripts. 18 | # 19 | # Windows support note: we ship the same executable in two gems, the `x64-mingw32` and 20 | # `x64-mingw-ucrt` flavors because Ruby < 3.1 uses the MSCVRT runtime libraries, and Ruby >= 3.1 21 | # uses the UCRT runtime libraries. You can read more about this change here: 22 | # 23 | # https://rubyinstaller.org/2021/12/31/rubyinstaller-3.1.0-1-released.html 24 | # 25 | # As a concrete example, an x86_64-linux system will see these files on disk after installing 26 | # tailwindcss-ruby-1.x.x-x86_64-linux.gem: 27 | # 28 | # exe/ 29 | # ├── tailwindcss 30 | # └── x86_64-linux/ 31 | # └── tailwindcss 32 | # 33 | # So the full set of gem files created will be: 34 | # 35 | # - pkg/tailwindcss-ruby-1.0.0.gem 36 | # - pkg/tailwindcss-ruby-1.0.0-aarch64-linux.gem 37 | # - pkg/tailwindcss-ruby-1.0.0-arm64-darwin.gem 38 | # - pkg/tailwindcss-ruby-1.0.0-x64-mingw32.gem 39 | # - pkg/tailwindcss-ruby-1.0.0-x64-mingw-ucrt.gem 40 | # - pkg/tailwindcss-ruby-1.0.0-x86_64-darwin.gem 41 | # - pkg/tailwindcss-ruby-1.0.0-x86_64-linux.gem 42 | # 43 | # Note that in addition to the native gems, a vanilla "ruby" gem will also be created without 44 | # either the `exe/tailwindcss` script or a binary executable present. 45 | # 46 | # 47 | # New rake tasks created: 48 | # 49 | # - rake gem:ruby # Build the ruby gem 50 | # - rake gem:aarch64-linux # Build the aarch64-linux gem 51 | # - rake gem:arm64-darwin # Build the arm64-darwin gem 52 | # - rake gem:x64-mingw32 # Build the x64-mingw32 gem 53 | # - rake gem:x64-mingw-ucrt # Build the x64-mingw-ucrt gem 54 | # - rake gem:x86_64-darwin # Build the x86_64-darwin gem 55 | # - rake gem:x86_64-linux # Build the x86_64-linux gem 56 | # - rake download # Download all tailwindcss binaries 57 | # 58 | # Modified rake tasks: 59 | # 60 | # - rake gem # Build all the gem files 61 | # - rake package # Build all the gem files (same as `gem`) 62 | # - rake repackage # Force a rebuild of all the gem files 63 | # 64 | # Note also that the binary executables will be lazily downloaded when needed, but you can 65 | # explicitly download them with the `rake download` command. 66 | # 67 | require "rubygems/package_task" 68 | require "open-uri" 69 | require_relative "../lib/tailwindcss/ruby/upstream" 70 | 71 | def tailwindcss_download_url(filename) 72 | "https://github.com/tailwindlabs/tailwindcss/releases/download/#{Tailwindcss::Ruby::Upstream::VERSION}/#{filename}" 73 | end 74 | 75 | TAILWINDCSS_RUBY_GEMSPEC = Bundler.load_gemspec("tailwindcss-ruby.gemspec") 76 | 77 | # prepend the download task before the Gem::PackageTask tasks 78 | task :package => :download 79 | 80 | gem_path = Gem::PackageTask.new(TAILWINDCSS_RUBY_GEMSPEC).define 81 | desc "Build the ruby gem" 82 | task "gem:ruby" => [gem_path] 83 | 84 | exepaths = [] 85 | Tailwindcss::Ruby::Upstream::NATIVE_PLATFORMS.each do |platform, filename| 86 | TAILWINDCSS_RUBY_GEMSPEC.dup.tap do |gemspec| 87 | exedir = File.join(gemspec.bindir, platform) # "exe/x86_64-linux" 88 | exepath = File.join(exedir, "tailwindcss") # "exe/x86_64-linux/tailwindcss" 89 | exepaths << exepath 90 | 91 | # modify a copy of the gemspec to include the native executable 92 | gemspec.platform = platform 93 | gemspec.files += [exepath, "LICENSE-DEPENDENCIES"] 94 | 95 | # create a package task 96 | gem_path = Gem::PackageTask.new(gemspec).define 97 | desc "Build the #{platform} gem" 98 | task "gem:#{platform}" => [gem_path] 99 | 100 | directory exedir 101 | file exepath => [exedir] do 102 | release_url = tailwindcss_download_url(filename) 103 | warn "Downloading #{exepath} from #{release_url} ..." 104 | 105 | # lazy, but fine for now. 106 | URI.open(release_url) do |remote| 107 | File.open(exepath, "wb") do |local| 108 | local.write(remote.read) 109 | end 110 | end 111 | FileUtils.chmod(0755, exepath, verbose: true) 112 | end 113 | end 114 | end 115 | 116 | desc "Validate checksums for tailwindcss binaries" 117 | task "check" => exepaths do 118 | sha_filename = File.absolute_path("../package/tailwindcss-#{Tailwindcss::Ruby::Upstream::VERSION}-checksums.txt", __dir__) 119 | sha_url = if File.exist?(sha_filename) 120 | sha_filename 121 | else 122 | sha_url = tailwindcss_download_url("sha256sums.txt") 123 | end 124 | gemspec = TAILWINDCSS_RUBY_GEMSPEC 125 | 126 | checksums = URI.open(sha_url).each_line.map do |line| 127 | checksum, file = line.split 128 | [File.basename(file), checksum] 129 | end.to_h 130 | 131 | Tailwindcss::Ruby::Upstream::NATIVE_PLATFORMS.each do |platform, filename| 132 | exedir = File.join(gemspec.bindir, platform) # "exe/x86_64-linux" 133 | exepath = File.join(exedir, "tailwindcss") # "exe/x86_64-linux/tailwindcss" 134 | 135 | local_sha256 = Digest::SHA256.file(exepath).hexdigest 136 | remote_sha256 = checksums.fetch(filename) 137 | 138 | if local_sha256 == remote_sha256 139 | puts "Checksum OK for #{exepath} (#{local_sha256})" 140 | else 141 | abort "Checksum mismatch for #{exepath} (#{local_sha256} != #{remote_sha256})" 142 | end 143 | end 144 | end 145 | 146 | desc "Download all tailwindcss binaries" 147 | task "download" => :check 148 | 149 | CLOBBER.add(exepaths.map { |p| File.dirname(p) }) 150 | -------------------------------------------------------------------------------- /tailwindcss-ruby.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "lib/tailwindcss/ruby/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "tailwindcss-ruby" 7 | spec.version = Tailwindcss::Ruby::VERSION 8 | spec.authors = ["Mike Dalessio", "David Heinemeier Hansson"] 9 | spec.email = ["mike.dalessio@gmail.com", "david@loudthinking.com"] 10 | 11 | spec.summary = "A self-contained `tailwindcss` executable." 12 | spec.description = "A self-contained `tailwindcss` executable, wrapped up in a ruby gem. That's it. Nothing else." 13 | spec.homepage = "https://github.com/flavorjones/tailwindcss-ruby" 14 | spec.license = "MIT" 15 | spec.required_ruby_version = ">= 3.0.0" 16 | 17 | spec.metadata["source_code_uri"] = spec.homepage 18 | spec.metadata["changelog_uri"] = "https://github.com/flavorjones/tailwindcss-ruby/blob/main/CHANGELOG.md" 19 | spec.metadata["rubygems_mfa_required"] = "true" 20 | 21 | spec.files = Dir["lib/**/*", "LICENSE.txt", "LICENSE-DEPENDENCIES", "README.md"] 22 | spec.bindir = "exe" 23 | spec.executables << "tailwindcss" 24 | spec.require_paths = ["lib"] 25 | end 26 | -------------------------------------------------------------------------------- /test/tailwindcss/test_ruby.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "test_helper" 4 | 5 | class Tailwindcss::TestRuby < Minitest::Spec 6 | def mock_exe_directory(platform) 7 | Dir.mktmpdir do |dir| 8 | FileUtils.mkdir(File.join(dir, platform)) 9 | path = File.join(dir, platform, "tailwindcss") 10 | FileUtils.touch(path) 11 | stub_gem_platform_match_gem(true) do 12 | yield(dir, path) 13 | end 14 | end 15 | end 16 | 17 | def stub_gem_platform_match_gem(value) 18 | assert_respond_to(Gem::Platform, :match_gem?) 19 | Gem::Platform.stub(:match_gem?, value) do 20 | yield 21 | end 22 | end 23 | 24 | def mock_local_tailwindcss_install 25 | Dir.mktmpdir do |dir| 26 | path = File.join(dir, "tailwindcss") 27 | FileUtils.touch(path) 28 | yield(dir, path) 29 | end 30 | end 31 | 32 | it ".platform is a string containing just the cpu and os (not the version)" do 33 | expected = "#{Gem::Platform.local.cpu}-#{Gem::Platform.local.os}" 34 | assert_equal(expected, Tailwindcss::Ruby.platform) 35 | end 36 | 37 | it ".executable returns the absolute path to the binary" do 38 | mock_exe_directory("sparc-solaris2.8") do |dir, executable| 39 | expected = File.expand_path(File.join(dir, "sparc-solaris2.8", "tailwindcss")) 40 | assert_equal(expected, executable, "assert on setup") 41 | assert_equal(expected, Tailwindcss::Ruby.executable(exe_path: dir)) 42 | end 43 | end 44 | 45 | it ".executable raises UnsupportedPlatformException when we're not on a supported platform" do 46 | stub_gem_platform_match_gem(false) do # nothing is supported 47 | assert_raises(Tailwindcss::Ruby::UnsupportedPlatformException) do 48 | Tailwindcss::Ruby.executable 49 | end 50 | end 51 | end 52 | 53 | it ".executable raises ExecutableNotFoundException when we can't find the executable we expect" do 54 | Dir.mktmpdir do |dir| # empty directory 55 | assert_raises(Tailwindcss::Ruby::ExecutableNotFoundException) do 56 | Tailwindcss::Ruby.executable(exe_path: dir) 57 | end 58 | end 59 | end 60 | 61 | it ".executable returns the executable in TAILWINDCSS_INSTALL_DIR when no packaged binary exists" do 62 | mock_local_tailwindcss_install do |local_install_dir, expected| 63 | result = nil 64 | begin 65 | ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir 66 | assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do 67 | result = Tailwindcss::Ruby.executable(exe_path: "/does/not/exist") 68 | end 69 | ensure 70 | ENV["TAILWINDCSS_INSTALL_DIR"] = nil 71 | end 72 | assert_equal(expected, result) 73 | end 74 | end 75 | 76 | it ".executable returns the executable in TAILWINDCSS_INSTALL_DIR when we're not on a supported platform" do 77 | stub_gem_platform_match_gem(false) do # nothing is supported 78 | mock_local_tailwindcss_install do |local_install_dir, expected| 79 | result = nil 80 | begin 81 | ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir 82 | assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do 83 | result = Tailwindcss::Ruby.executable 84 | end 85 | ensure 86 | ENV["TAILWINDCSS_INSTALL_DIR"] = nil 87 | end 88 | assert_equal(expected, result) 89 | end 90 | end 91 | end 92 | 93 | it ".executable returns the executable in TAILWINDCSS_INSTALL_DIR even when a packaged binary exists" do 94 | mock_exe_directory("sparc-solaris2.8") do |dir, _executable| 95 | mock_local_tailwindcss_install do |local_install_dir, expected| 96 | result = nil 97 | begin 98 | ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir 99 | assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do 100 | result = Tailwindcss::Ruby.executable(exe_path: dir) 101 | end 102 | ensure 103 | ENV["TAILWINDCSS_INSTALL_DIR"] = nil 104 | end 105 | assert_equal(expected, result) 106 | end 107 | end 108 | end 109 | 110 | it ".executable raises ExecutableNotFoundException is TAILWINDCSS_INSTALL_DIR is set to a nonexistent dir" do 111 | begin 112 | ENV["TAILWINDCSS_INSTALL_DIR"] = "/does/not/exist" 113 | assert_raises(Tailwindcss::Ruby::DirectoryNotFoundException) do 114 | Tailwindcss::Ruby.executable 115 | end 116 | ensure 117 | ENV["TAILWINDCSS_INSTALL_DIR"] = nil 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $LOAD_PATH.unshift File.expand_path("../lib", __dir__) 4 | require "tailwindcss/ruby" 5 | 6 | require "minitest/autorun" 7 | --------------------------------------------------------------------------------