-
-
Save jeromecornet/93f04cc8358dcf3a96750615062bfc70 to your computer and use it in GitHub Desktop.
tailwind_transformer.rb -> app/models/tailwind_transformer.rb | |
tailwind.rb -> config/initializers/tailwind.rb | |
tailwind.config.js.erb -> config/tailwind.config.js.erb | |
package.json -> ./package.json |
{ | |
... | |
"dependencies": { | |
"@tailwindcss/aspect-ratio": "^0.2.1", | |
"@tailwindcss/forms": "^0.3.3", | |
"@tailwindcss/typography": "^0.4.1", | |
"autoprefixer": "^10.0.2", | |
"clean-css-cli": "^5.3.3", | |
"postcss": "8.3.6", | |
"tailwindcss": "^2.2.7", | |
"tailwindcss-cli": "^0.1.2" | |
} | |
} |
module.exports = { | |
mode: 'jit', | |
darkMode: 'class', | |
purge: { | |
content: [ | |
'./app/**/*.erb', | |
'./app/helpers/**/*.rb', | |
'./app/**/*.html', | |
'./app/**/*.js', | |
], | |
css: [ | |
'./app/**/*.scss', | |
'./app/**/*.css', | |
] | |
}, | |
theme: { | |
extend: { | |
fontFamily: { | |
sans: ['Inter var', ...defaultTheme.fontFamily.sans], | |
} | |
}, | |
}, | |
variants: {}, | |
plugins: [ | |
require('@tailwindcss/forms'), | |
require('@tailwindcss/typography'), | |
require('@tailwindcss/aspect-ratio'), | |
], | |
} | |
Rails.application.reloader.to_prepare do | |
Sprockets.register_compressor "text/css", :tailwind, TailwindTransformer | |
Rails.application.config.assets.css_compressor = :tailwind | |
end | |
if Rails.env.production? | |
Rails.application.config.assets.configure do |env| | |
env.cache = ActiveSupport::Cache.lookup_store(:null_store) | |
end | |
end |
# frozen_string_literal: true | |
require "open3" | |
class TailwindTransformer | |
def self.instance | |
@instance ||= new | |
end | |
def self.call(input) | |
instance.call(input) | |
end | |
def temp_config | |
Rails.root.join("tmp", "tailwind.config.js") | |
end | |
def initialize(options = {}) | |
templated = Rails.root.join("config", "tailwind.config.js.erb") | |
non_templated = Rails.root.join("config", "tailwind.config.js") | |
if File.exist?(templated) | |
File.write(temp_config, ERB.new(File.read(templated)).result) | |
elsif File.exist?(non_templated) | |
FileUtils.cp(non_templated, temp_config) | |
else | |
raise StandardError, "Cannot find config/tailwind.config.js[.erb]" | |
end | |
@options = { | |
files: ["application"], | |
}.merge(options).freeze | |
end | |
def call(input) | |
if input[:name].in?(@options[:files]) | |
temp_file = Tempfile.new([input[:name], ".css"]) | |
temp_file.open | |
temp_file.write(input[:data]) | |
temp_file.flush | |
out, err, status = Open3.capture3("npx", "tailwindcss-cli", "build", "-i", temp_file.path, "--config", temp_config.to_s) | |
unless status.success? | |
raise StandardError, | |
"Error while compiling #{input[:filename]}. " \ | |
"npx tailwindcss-cli build '#{temp_file.path}' --config '#{temp_config}' returned: \n#{err}" | |
end | |
return { data: out } unless ENV["ASSETS_MODE"] == "production" || Rails.env.production? | |
File.truncate(temp_file.path, 0) | |
temp_file.open | |
temp_file.write(out) | |
temp_file.flush | |
out, err, status = Open3.capture3("npx", "cleancss", temp_file.path) | |
unless status.success? | |
raise StandardError, | |
"Error while compiling #{input[:filename]}. " \ | |
"NODE_ENV=production npx tailwindcss-cli build '#{temp_file.path}' --config '#{temp_config}' returned: \n#{err}" | |
end | |
{ data: out } | |
else | |
input[:data] | |
end | |
end | |
end |
Just pushed an update so the css is also processed with cleancss in production
Just pushed an update so the css is also processed with cleancss in production
Could/should this be handled by a Sprockets compressor?
Just pushed an update so the css is also processed with cleancss in production
Could/should this be handled by a Sprockets compressor?
Probably. You can easily remove the second stage after https://gist.github.com/jeromecornet/93f04cc8358dcf3a96750615062bfc70#file-tailwind_transformer-rb-L47 and simply return the output of the first stage.
I just whipped this up because I wanted the combination of tailwindcss with its @apply
directives in a rails app without webpacker (using importmaps, now https://github.com/rails/importmap-rails) and https://github.com/rails/tailwindcss-rails takes a fully no javascript approach (packaging the full css, then purging it with a ruby-based class detector). I didn't try to understand anything about sprockets when I did this (hence it's just a gist, not a proper project). I would love for someone to package up properly something like this though 😄
I just whipped this up because I wanted the combination of tailwindcss … without webpacker
Same! I created a demo here: https://github.com/domchristie/tailwindcss-jit-rails but it's much less integrated with Sprockets, and much more manual. I don't have experience authoring gems or Sprockets extenions, but would also love to see this approach packaged up :)
This looks like a great introduction to integrating a node CLI with Sprockets. Thanks for sharing!
Line 22 of the transformer has a type
exists
instead ofexist?
orexists?
This only worked for me when I moved registering the compressor and setting it out of
Rails.application.reloader.to_prepare
and to the bottom of the assets.rb file. I think there was an issue with load order around setting precompiled assets, but I'm not certain.