如何在 rails 7 引擎中使用顺风 css gem



如何在轨道发动机中使用顺风?根据向 Rails 生成器提供 css 参数的文档应该可以工作

Rails 7.0.2.2 引擎生成于

rails plugin new tailtest --mountable --full -d postgresql --css tailwind

这会使用 Postgresql 生成引擎,但对顺风没有任何作用,并且遵循手动安装说明也会失败。

根据文档,运行bundle add tailwindcss-rails会将顺风添加到 gemfile 而不是引擎 tailtest.gemspec 因此,在将依赖项添加到宝石规格之后

spec.add_dependency "tailwindcss-rails", "~> 2.0"

运行bundle install确实安装了引擎,但手动安装的其余部分失败

然后将 require 添加到 lib/engine.rb

require "tailwindcss-rails"
module Tailtest
class Engine < ::Rails::Engine
isolate_namespace Tailtest
end
end

然后运行安装过程失败

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

显然,app:tailwindcss:install命令也会失败。

所以我可能在 engine.rb 文件中缺少某种初始值设定项,但不知道它应该是什么。

这与如何在 Rails 7 引擎中设置 importmap-rails的想法相同?。我们不需要使用安装任务。即使你能够运行它,它在引擎中也没有帮助(请参阅答案的末尾以获取解释)。

此外,rails plugin new没有--css选项。要查看可用选项:rails plugin new -h

更新引擎的宝石规格文件:

# my_engine/my_engine.gemspec
spec.add_dependency "tailwindcss-rails"

更新引擎.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

更新资产清单:

# my_engine/app/assets/config/my_engine_manifest.js
//= link_tree ../builds/ .css

更新引擎的布局:

# 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命令将为我们提供 gem 的安装路径,因此我们可以复制一些文件:

$ 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

tailwindcss-rails复制tailwind.config.js文件:

$ cp $(bundle show tailwindcss-rails)/lib/install/tailwind.config.js config/tailwind.config.js

application.tailwind.css文件复制到任何目录中以适合您的设置:

$ cp $(bundle show tailwindcss-rails)/lib/install/application.tailwind.css app/assets/stylesheets/application.tailwind.css

因为tailwindcss-rails使用独立的可执行文件,所以我们不需要节点或轨道来编译样式表。我们只需要了解可执行文件本身。

可执行文件位于此处https://github.com/rails/tailwindcss-rails/tree/v2.0.8/exe/。无需运行构建任务https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/build.rake我们可以直接调用可执行文件。

$ $(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选项启动监视模式。

$ $(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

输出文件应与stylesheet_link_tag "my_engine"中的名称匹配。

现在您有一个普通的my_engine.css文件,请根据需要对其进行处理。在布局中使用它,需要它来自主应用程序.css。通常的 rails 资产管道规则适用。

如果要将所有这些放入任务中,请使用Engine.root获取路径。

# 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

从引擎目录:

$ 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.

如果要设置大量引擎,请创建自己的安装任务:

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

安装任务参考:
https://github.com/rails/rails/blob/v7.0.2.4/railties/lib/rails/tasks/framework.rake#L8<</em>br/>https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/install.rake

监视任务参考:
https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/build.rake#L10


更新如何合并两个顺风。

上面的设置假设引擎是它自己独立的东西,就像管理后端一样,它有自己的路由、模板和样式。如果引擎功能要与主应用(如view_component集合)混合使用,则顺风样式将相互覆盖。在这种情况下,使用前缀隔离引擎样式可以工作:
https://tailwindcss.com/docs/configuration#prefix

顺风样式不混合的原因是大多数选择器具有相同的特异性,并且顺序非常重要。

所以这里有一个例子。带有引擎的主应用程序,都使用顺风,都分别编译样式,顺风配置只监视引擎中的一个文件和一个主应用程序的文件,仅使用@tailwind实用程序;指令:

我们要在主应用程序中使用的引擎模板应该可以正常工作:

<!-- blep/app/views/blep/_partial.html.erb -->
<div class="bg-red-500 sm:bg-blue-500"> red never-blue </div>

但是当在主应用程序中呈现时,它永远不会变成蓝色。以下是演示设置:

<!-- app/views/home/index.html.erb -->
<%= stylesheet_link_tag "blep",     "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
<!-- output generated css in the same order as above link tags -->
<% require "open-uri" %>
<b>Engine css</b>
<pre><%= URI.open(asset_url("blep")).read %></pre>
<b>Main app css</b>
<pre><%= URI.open(asset_url("tailwind")).read %></pre>
<div class="bg-red-500"> red </div> <!-- this generates another bg-red-500 -->
<br>
<%= render "blep/partial" %>

它看起来像这样:

/* Engine css */
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity))
}
@media (min-width: 640px) {
.sm:bg-blue-500 {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity))
}
}
/* Main app css */
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity))
}
<div class="bg-red-500"> red </div>
<br>
<div class="bg-red-500 sm:bg-blue-500"> red never-blue </div>

^您可以点击运行并单击"整页"。主应用bg-red-500选择器排在最后,因此它会覆盖引擎sm:bg-blue-500选择器,媒体查询不会增加特异性分数。这与你不能覆盖的原因是一样的,比如说,用m-2覆盖mt-1,边距顶部在样式表中的后面出现。这就是为什么@layer指令很重要的原因。

解决此问题的唯一方法是在主应用程序中运行 tailwind 时监视引擎目录,以便将样式编译在一起并按正确的顺序进行。这意味着您实际上不需要发动机中的顺风:

module.exports = {
content: [
"./app/**/*",
"/just/type/the/path/to/engine/views",
"/or/see/updated/task/below",
],
}

我尝试了其他方法,例如为主应用程序和引擎的每一层运行 6 个顺风命令,以便我可以将它们按顺序排列,更好,但仍然有点乱序和重复。或者做一个@import,以某种方式让postcss-import知道在哪里寻找引擎样式(我不知道,我只是将其符号链接到node_modules进行测试),但这仍然需要顺风来监视引擎文件。


我做了更多的挖掘,顺风cli 有一个--content选项,它将覆盖tailwind.config.js中的content。我们可以使用它来设置一个新任务:

namespace :tailwindcss do
desc "Build your Tailwind CSS + Engine"
task :watch do |_, args|
# NOTE: there have been some updates, there is a whole Commands class now
#       lets copy paste and modify.          (debug = no --minify)
command = Tailwindcss::Commands.watch_command(debug: true, poll: false)
# --content /path/to/app/**/*,/path/to/engine/**/*
command << "--content"
command << [
Rails.root.join("app/views/home/*"),
Blep::Engine.root.join("app/views/**/*.erb")
].join(",")
p command
system(*command)
end
# same for build, just call `compile_command`
# task :build do |_, args|
#   command = Tailwindcss::Commands.compile_command(debug: false)
#   ...
end

https://github.com/rails/tailwindcss-rails/blob/v2.0.21/lib/tasks/build.rake#L11

亚历克斯的回答真的很好,我希望我在开始时就有它。(但我什至没有谷歌的问题) 只想补充两件事:

1-一个小的简化。我刚刚制作了一个脚本来运行引擎中的顺风

#!/usr/bin/env sh
# Since tailwind does not install into the engine, this will
# watch and recompile during development
# tailwindcss executable must exist (by bundling tailwindcss-rails eg)
tailwindcss -i app/assets/stylesheets/my_engine.tailwind.css 
-o app/assets/stylesheets/my_engine/my_engine.css 
-c config/tailwind.config.js 
-w

2-对于在应用程序中的使用,显然也使用顺风,我正在努力,因为两个生成的css相互咬合,我无法让两种样式在一个页面中工作。总是其中一个(应用或引擎)的样式不正确。直到我得到了应用程序的顺风来选择引擎类。 这样:

添加到应用程序的顺风.config.js:在模块之前

const execSync = require('child_process').execSync;
const output = execSync('bundle show my_engine', { encoding: 'utf-8' });

然后在内容中作为最后一行

output.trim() + '/app/**/*.{erb,haml,html,rb}'

然后只需在布局中包含应用程序生成的顺风 css,就像安装程序一样。不要在布局中包含引擎样式表,或将其添加到资源中

最新更新