'How to use tailwind css gem in a rails 7 engine?
How to use tailwind in a rails engine? According to the documentation supplying a css argument to the Rails generator should work
Rails 7.0.2.2 engine generated using
rails plugin new tailtest --mountable --full -d postgresql --css tailwind
This generates the engine with Postgresql but does nothing with tailwind at all, and following manual installation instructions fail too.
Running, as per documentation, bundle add tailwindcss-rails
adds tailwind to the gemfile rather than the engines tailtest.gemspec
So after adding the dependency to the gemspec
spec.add_dependency "tailwindcss-rails", "~> 2.0"
and running bundle install
does install the engine however the rest of the manual installation fails
then adding the require to lib/engine.rb
require "tailwindcss-rails"
module Tailtest
class Engine < ::Rails::Engine
isolate_namespace Tailtest
end
end
then running the install process fails
rails tailwindcss:install
Resolving dependencies...
rails aborted!
Don't know how to build task 'tailwindcss:install' (See the list of available tasks with `rails --tasks`)
Did you mean? app:tailwindcss:install
Obviously the app:tailwindcss:install
command fails too.
So I am probably missing an initializer of some sort in the engine.rb file but no idea on what it should be.
Solution 1:[1]
It is the same idea as How to set up importmap-rails in Rails 7 engine?. We don't need to use the install task. Even if you're able to run it, it's not helpful in the engine (see the end of the answer for explanation).
Also rails plugin new
doesn't have a --css
option. To see available options: rails plugin new -h
.
Update engine's gemspec file:
# my_engine/my_engine.gemspec
spec.add_dependency "tailswindcss-rails"
Update engine.rb:
# my_engine/lib/my_engine/engine.rb
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
# NOTE: add engine manifest to precompile assets in production, if you don't have this yet.
initializer "my-engine.assets" do |app|
app.config.assets.precompile += %w[my_engine_manifest]
end
end
end
Update assets manifest:
# my_engine/app/assets/config/my_engine_manifest.js
//= link_tree ../builds/ .css
Update engine's layout:
# my_engine/app/views/layouts/my_engine/application.html.erb
<!DOCTYPE html>
<html>
<head>
<%#
NOTE: make sure this name doesn't clash with anything in the main app.
think of it as `require` and `$LOAD_PATH`,
but instead it is `stylesheet_link_tag` and `manifest.js`.
%>
<%= stylesheet_link_tag "my_engine", "data-turbo-track": "reload" %>
</head>
<body> <%= yield %> </body>
</html>
bundle show
command will give us the path where the gem is installed, so we can copy a few files:
$ bundle show tailwindcss-rails
/home/alex/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/tailwindcss-rails-2.0.8-x86_64-linux
Copy tailwind.config.js file from tailswindcss-rails
:
$ cp $(bundle show tailwindcss-rails)/lib/install/tailwind.config.js config/tailwind.config.js
Copy application.tailwind.css file into any directory to fit your setup:
$ cp $(bundle show tailwindcss-rails)/lib/install/application.tailwind.css app/assets/stylesheets/application.tailwind.css
Because tailwindcss-rails
uses standalone executable, we don't need node or rails to compile the stylesheets. We just need to get to the executable itself.
Executable is located here https://github.com/rails/tailwindcss-rails/tree/v2.0.8/exe/. Instead of running the build task https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/build.rake we can just call the executable directly.
$ $(bundle show tailwindcss-rails)/exe/tailwindcss -i app/assets/stylesheets/application.tailwind.css -o app/assets/builds/my_engine.css -c config/tailwind.config.js --minify
Use -w
option to start watch mode.
$ $(bundle show tailwindcss-rails)/exe/tailwindcss -i app/assets/stylesheets/application.tailwind.css -o app/assets/builds/my_engine.css -c config/tailwind.config.js --minify -w
The output file should match the name in stylesheet_link_tag "my_engine"
.
Now that you have a plain my_engine.css file, do with it what you want. Use it in the layout, require it from the main app application.css. The usual rails asset pipeline rules apply.
If you want to put all that into a task, use Engine.root
to get the paths.
# my_engine/lib/tasks/my_engine.rake
task :tailwind_engine_watch do
require 'tailwindcss-rails'
# NOTE: tailwindcss-rails is an engine
system "#{Tailwindcss::Engine.root.join("exe/tailwindcss")} \
-i #{MyEngine::Engine.root.join("app/assets/stylesheets/application.tailwind.css")} \
-o #{MyEngine::Engine.root.join("app/assets/builds/my_engine.css")} \
-c #{MyEngine::Engine.root.join("config/tailwind.config.js")} \
--minify -w"
end
From the engine directory:
$ bin/rails app:tailwind_engine_watch
+ /home/alex/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/tailwindcss-rails-2.0.8-x86_64-linux/exe/x86_64-linux/tailwindcss -i /home/alex/code/stackoverflow/my_engine/app/assets/stylesheets/application.tailwind.css -o /home/alex/code/stackoverflow/my_engine/app/assets/builds/my_engine.css -c /home/alex/code/stackoverflow/my_engine/config/tailwind.config.js --minify -w
Rebuilding...
Done in 549ms.
Make your own install task if you have a lot of engines to set up:
desc "Install tailwindcss into our engine"
task :tailwind_engine_install do
require 'tailwindcss-rails'
# NOTE: use default app template, which will fail to modify layout, manifest,
# and the last command that compiles the initial `tailwind.css`.
# It will also add `bin/dev` and `Procfile.dev` which we don't need.
# Basically, it's useless in the engine as it is.
template = Tailwindcss::Engine.root.join("lib/install/tailwindcss.rb")
# TODO: better to copy the template from
# https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/install/tailwindcss.rb
# and customize it
# template = MyEngine::Engine.root("lib/install/tailwindcss.rb")
require "rails/generators"
require "rails/generators/rails/app/app_generator"
# NOTE: because the app template uses `Rails.root` it will run the install
# on our engine's dummy app. Just override `Rails.root` with our engine
# root to run install in the engine directory.
Rails.configuration.root = MyEngine::Engine.root
generator = Rails::Generators::AppGenerator.new [Rails.root], {}, { destination_root: Rails.root }
generator.apply template
end
Install task reference:
https://github.com/rails/rails/blob/v7.0.2.4/railties/lib/rails/tasks/framework.rake#L8
https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/install.rake
Watch task reference:
https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/build.rake#L10
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |