Rails 7 引擎如何使未编译的样式表可用于托管应用程序?
Rails 7 engine how to make uncompiled stylesheets available to host app?
所以我有一个找不到文件的问题。
我有一个在引擎 test/dummy 应用程序中以开发模式工作的引擎,该引擎允许编辑 sass 变量并将它们存储在主题 table 中,这些变量由 sass 部分如 _banner.scss 包含主样式表中使用的变量,如 $banner_color 然后导入到主样式表中,主样式表又使用 engine.rb 中的初始化程序预编译文件并包含在 app/config/engine_name_manifest.js.
这些文件都可以在本地虚拟应用程序的开发中使用,但由于资产正在编译,所以在最终的主机应用程序中不可用。
我有一个 rake 任务,它获取数据,更新相关部分,例如_banner.scss 使用主题 table 中的数据,但当然部分部分在主机应用程序中不可用,因为引擎已经编译了它们。
我正在寻找一种解决方案,允许我编辑原始的、未编译的样式表,然后重新编译它们。显然,我的 Capistrano 部署脚本将需要重新应用样式表更改每个部署,但这只是一个 rake 任务调用。
我应该采取什么方法?我是否应该找到一种方法将 css 文件复制到引擎初始化程序中的主机应用程序?我是否应该完全使用不同的方法,我已经开始研究传动轴,但这是取代 sass rails 的重要一步,我不确定这会有什么帮助
引擎
require "deface"
require 'ccs_cms_admin_dashboard'
require 'ccs_cms_custom_page'
require 'ccs_cms_core'
require 'css_menu'
#require 'tinymce-rails'
require 'delayed_job_active_record'
require 'daemons'
require 'sprockets/railtie'
require 'sassc-rails'
module CcsCms
module PublicTheme
class Engine < ::Rails::Engine
isolate_namespace CcsCms::PublicTheme
paths["app/views"] << "app/views/ccs_cms/public_theme"
initializer "ccs_cms.assets.precompile" do |app|
app.config.assets.precompile += %w( public_theme_manifest.js )
end
initializer :append_migrations do |app|
unless app.root.to_s.match?(root.to_s)
config.paths['db/migrate'].expanded.each do |p|
app.config.paths['db/migrate'] << p
end
end
end
initializer :active_job_setup do |app|
app.config.active_job.queue_adapter = :delayed_job
end
config.to_prepare do
Dir.glob(Engine.root.join("app", "decorators", "**", "*_decorator*.rb")) do |c|
Rails.configuration.cache_classes ? require(c) : load(c)
end
end
config.generators do |g|
g.test_framework :rspec,
fixtures: false,
request: false,
view_specs: false,
helper_specs: false,
controller_specs: false,
routing_specs: false
g.fixture_replacement :factory_bot
g.factory_bot dir: 'spec/factories'
end
end
end
end
写cssCssclass
class Css
def get_stylesheet_path
Rails.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
def write_css(theme)
update_css_files_for(theme.banner, '_public_banner.scss', BANNER_ARRAY, BANNER_FIELD_MAP)
update_css_files_for(theme.banner.font, '_public_banner_font.scss', BANNER_FONT_ARRAY, BANNER_FONT_FIELD_MAP)
end
private
def update_css_files_for(model_record_to_use, css_file, array_to_use, field_map)
amended_css = amend_css_for(model_record_to_use, css_file, array_to_use, field_map)
create_css_files_for(css_file, amended_css)
end
def amend_css_for(model_record_to_use, file_name, array_to_use, field_map)
original_css_array = IO.readlines("#{get_stylesheet_path}/#{file_name}")
new_array = []
original_css_array.each do |line|
new_line = line
array_to_use.each do |ma|
if line.start_with?(ma)
field_name = field_map[ma.to_sym]
new_line = ma + ": #{model_record_to_use[field_name.to_sym]};"
#puts("@@@@ original line: #{line}, ma: #{ma}, Field name: #{field_name}, value: #{theme[field_name]}")
break
end
end
new_array << new_line
end
new_array
end
# ---- File and I/O Handling ---- #
def create_css_files_for(file_name, css_array)
File.open("#{get_stylesheet_path}/#{file_name}", "w") do |file|
file.puts css_array
end
end
end
感谢您的澄清。如果我在这里理解正确的话,我会接受它。
partials are not not available in a host app as the engine has already compiled them
部分仍然存在,预编译只是将 *.{css/js}
文件输出到 public/assets/
中,这些文件在 app/assets/config/manifest.js
.
中声明
要获取引擎文件,而不是 Rails.root
使用:
CcsCms::PublicTheme::Engine.root
在Css
class中,例如:
def get_stylesheet_path
CcsCms::PublicTheme::Engine.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
支持更换主题引擎。可以在引擎初始化程序中将主题根设置为 Rails.configuration.theme_root
之类的内容,并在主应用程序中使用。
因为您的主题也是可配置的,我认为最好阅读主题的原始 sass 文件但不要修改它们,将它们复制到 tmp 文件夹并使用主题 table 中的值进行更新,然后使用 sass 在主应用程序中输出 theme.css
。
https://sass-lang.com/documentation/cli/dart-sass
# Compiles all Sass
$ sass tmp/theme/application.scss:app/stylesheets/theme.css
然后让Rails接管预编译过程
另一个选择是有一个 sass 配置文件并且只更新这个文件。这样就不会依赖于任何特定主题的文件结构。
import 'configuration' // sass variables with values from theme table
import 'banner' // uses sass variables only
...
也只使用 css 变量,如果这是一个选项,并避免上述所有复杂性;没有预编译,没有在主题 table 更改时重新部署。
更新 css 个变量。
所以我们在同一页面上。我的意思是这些 css 变量:
https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties。如果 Internet Explorer 不是您的首选,那么这是最佳解决方案。
设置是这样的:
<!-- app/views/layouts/application.erb -->
<!-- NOTE: with turbo this loads only once; full page refresh is needed when @theme changes -->
<head>
<style>
:root { --text-color: <%= @theme.text_color %>; }
</style>
<%= stylesheet_link_tag 'application' %>
</head>
/* app/assets/stylesheets/application.css */
p { color: var(--text-color); }
可能的修复以避免修改 css 文件。在 sass 文件中使用 erb
插值。无需每次更改主题配置时都进行修改。在开发中即时编译。在生产中,当主题配置更改时,必须重新预编译;不修改。
// _banner.scss.erb
p { color: <%= Theme.text_color %>; }
您甚至可以使用 amend_css_for
函数插入文字 erb 代码并节省一些时间。例如
new_line = ma + ": <%= Theme.#{model_name}.#{field_name} %>;"
最后,如果您不想接触引擎文件,并且因为这些文件不是 main/host 应用程序的一部分(就像在文件系统中的两个独立文件夹中一样)。修改时必须复印一份;从 CcsCms::PublicTheme::Engine.root
读取到 Rails.root
.
def get_stylesheet_path
CcsCms::PublicTheme::Engine.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
# but save to main app
def create_css_files_for(file_name, css_array)
File.open("#{Rails.root.join("app/assets/stylesheets/ccs_cms/public_theme")}/#{file_name}", "w") do |file|
file.puts css_array
end
end
所以我有一个找不到文件的问题。 我有一个在引擎 test/dummy 应用程序中以开发模式工作的引擎,该引擎允许编辑 sass 变量并将它们存储在主题 table 中,这些变量由 sass 部分如 _banner.scss 包含主样式表中使用的变量,如 $banner_color 然后导入到主样式表中,主样式表又使用 engine.rb 中的初始化程序预编译文件并包含在 app/config/engine_name_manifest.js.
这些文件都可以在本地虚拟应用程序的开发中使用,但由于资产正在编译,所以在最终的主机应用程序中不可用。
我有一个 rake 任务,它获取数据,更新相关部分,例如_banner.scss 使用主题 table 中的数据,但当然部分部分在主机应用程序中不可用,因为引擎已经编译了它们。 我正在寻找一种解决方案,允许我编辑原始的、未编译的样式表,然后重新编译它们。显然,我的 Capistrano 部署脚本将需要重新应用样式表更改每个部署,但这只是一个 rake 任务调用。 我应该采取什么方法?我是否应该找到一种方法将 css 文件复制到引擎初始化程序中的主机应用程序?我是否应该完全使用不同的方法,我已经开始研究传动轴,但这是取代 sass rails 的重要一步,我不确定这会有什么帮助
引擎
require "deface"
require 'ccs_cms_admin_dashboard'
require 'ccs_cms_custom_page'
require 'ccs_cms_core'
require 'css_menu'
#require 'tinymce-rails'
require 'delayed_job_active_record'
require 'daemons'
require 'sprockets/railtie'
require 'sassc-rails'
module CcsCms
module PublicTheme
class Engine < ::Rails::Engine
isolate_namespace CcsCms::PublicTheme
paths["app/views"] << "app/views/ccs_cms/public_theme"
initializer "ccs_cms.assets.precompile" do |app|
app.config.assets.precompile += %w( public_theme_manifest.js )
end
initializer :append_migrations do |app|
unless app.root.to_s.match?(root.to_s)
config.paths['db/migrate'].expanded.each do |p|
app.config.paths['db/migrate'] << p
end
end
end
initializer :active_job_setup do |app|
app.config.active_job.queue_adapter = :delayed_job
end
config.to_prepare do
Dir.glob(Engine.root.join("app", "decorators", "**", "*_decorator*.rb")) do |c|
Rails.configuration.cache_classes ? require(c) : load(c)
end
end
config.generators do |g|
g.test_framework :rspec,
fixtures: false,
request: false,
view_specs: false,
helper_specs: false,
controller_specs: false,
routing_specs: false
g.fixture_replacement :factory_bot
g.factory_bot dir: 'spec/factories'
end
end
end
end
写cssCssclass
class Css
def get_stylesheet_path
Rails.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
def write_css(theme)
update_css_files_for(theme.banner, '_public_banner.scss', BANNER_ARRAY, BANNER_FIELD_MAP)
update_css_files_for(theme.banner.font, '_public_banner_font.scss', BANNER_FONT_ARRAY, BANNER_FONT_FIELD_MAP)
end
private
def update_css_files_for(model_record_to_use, css_file, array_to_use, field_map)
amended_css = amend_css_for(model_record_to_use, css_file, array_to_use, field_map)
create_css_files_for(css_file, amended_css)
end
def amend_css_for(model_record_to_use, file_name, array_to_use, field_map)
original_css_array = IO.readlines("#{get_stylesheet_path}/#{file_name}")
new_array = []
original_css_array.each do |line|
new_line = line
array_to_use.each do |ma|
if line.start_with?(ma)
field_name = field_map[ma.to_sym]
new_line = ma + ": #{model_record_to_use[field_name.to_sym]};"
#puts("@@@@ original line: #{line}, ma: #{ma}, Field name: #{field_name}, value: #{theme[field_name]}")
break
end
end
new_array << new_line
end
new_array
end
# ---- File and I/O Handling ---- #
def create_css_files_for(file_name, css_array)
File.open("#{get_stylesheet_path}/#{file_name}", "w") do |file|
file.puts css_array
end
end
end
感谢您的澄清。如果我在这里理解正确的话,我会接受它。
partials are not not available in a host app as the engine has already compiled them
部分仍然存在,预编译只是将 *.{css/js}
文件输出到 public/assets/
中,这些文件在 app/assets/config/manifest.js
.
要获取引擎文件,而不是 Rails.root
使用:
CcsCms::PublicTheme::Engine.root
在Css
class中,例如:
def get_stylesheet_path
CcsCms::PublicTheme::Engine.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
支持更换主题引擎。可以在引擎初始化程序中将主题根设置为 Rails.configuration.theme_root
之类的内容,并在主应用程序中使用。
因为您的主题也是可配置的,我认为最好阅读主题的原始 sass 文件但不要修改它们,将它们复制到 tmp 文件夹并使用主题 table 中的值进行更新,然后使用 sass 在主应用程序中输出 theme.css
。
https://sass-lang.com/documentation/cli/dart-sass
# Compiles all Sass
$ sass tmp/theme/application.scss:app/stylesheets/theme.css
然后让Rails接管预编译过程
另一个选择是有一个 sass 配置文件并且只更新这个文件。这样就不会依赖于任何特定主题的文件结构。
import 'configuration' // sass variables with values from theme table
import 'banner' // uses sass variables only
...
也只使用 css 变量,如果这是一个选项,并避免上述所有复杂性;没有预编译,没有在主题 table 更改时重新部署。
更新 css 个变量。
所以我们在同一页面上。我的意思是这些 css 变量: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties。如果 Internet Explorer 不是您的首选,那么这是最佳解决方案。 设置是这样的:
<!-- app/views/layouts/application.erb -->
<!-- NOTE: with turbo this loads only once; full page refresh is needed when @theme changes -->
<head>
<style>
:root { --text-color: <%= @theme.text_color %>; }
</style>
<%= stylesheet_link_tag 'application' %>
</head>
/* app/assets/stylesheets/application.css */
p { color: var(--text-color); }
可能的修复以避免修改 css 文件。在 sass 文件中使用 erb
插值。无需每次更改主题配置时都进行修改。在开发中即时编译。在生产中,当主题配置更改时,必须重新预编译;不修改。
// _banner.scss.erb
p { color: <%= Theme.text_color %>; }
您甚至可以使用 amend_css_for
函数插入文字 erb 代码并节省一些时间。例如
new_line = ma + ": <%= Theme.#{model_name}.#{field_name} %>;"
最后,如果您不想接触引擎文件,并且因为这些文件不是 main/host 应用程序的一部分(就像在文件系统中的两个独立文件夹中一样)。修改时必须复印一份;从 CcsCms::PublicTheme::Engine.root
读取到 Rails.root
.
def get_stylesheet_path
CcsCms::PublicTheme::Engine.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
# but save to main app
def create_css_files_for(file_name, css_array)
File.open("#{Rails.root.join("app/assets/stylesheets/ccs_cms/public_theme")}/#{file_name}", "w") do |file|
file.puts css_array
end
end