-
-
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
existsinstead ofexist?orexists?This only worked for me when I moved registering the compressor and setting it out of
Rails.application.reloader.to_prepareand 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.