将数据注入 Ember 应用程序中的 Sass 个变量
Inject data into Sass variables in Ember application
我正在开发一个将许多单独的 "sites" 呈现为子目录的应用程序 - 例如/client/1
、/client/2
等。对于其中的每一个,可以在应用程序的管理部分指定两个颜色值。
我想知道是否有一种方法可以将最初发布到后端 API 然后由 Ember 从后端检索到的值注入到 SCSS 文件中以用于预处理?
到目前为止我还没有找到解决办法。
在我们的 Ember/Rails 应用程序中,我们根据数据库中的某些设置为每个客户端生成 CSS 文件。例如,我们的 Tenant
模型有两个字段:
{
primary_color: 'ff3300',
secondary_color: '00ff00'
}
我们公开路线
scope '/stylesheets', format: 'css' do
get 'tenant/:tenant_id', to: 'stylesheets#tenant_css'
end
我们的控制器看起来像这样:
class StylesheetsController < ApplicationController
layout nil
rescue_from 'ActiveRecord::RecordNotFound' do
render nothing: true, status: 404
end
def tenant_css
# fetch model
tenant = Tenant.find(params[:tenant_id])
# cache the css under a unique key for tenant
cache_key = "tenant_css_#{tenant.id}"
# fetch the cache
css = Rails.cache.fetch(cache_key) do
# pass sass "params"
render_css_for 'tenant', {
primary_color: tenant.primary_color,
secondary_color: tenant.secondary_color
}
end
render_as_css css
end
protected
# our renderer, could also add a custom one, but simple enough here
def render_as_css(css)
render text: css, content_type: 'text/css'
end
# looks for a template in views/stylesheets/_#{template}.css.erb
def render_css_for(template, params = {})
# load the template, parse ERB w params
scss = render_to_string partial: template, locals: { params: params }
load_paths = [Rails.root.join('app/assets/stylesheets')]
# parse the rendered template via Saas
Sass::Engine.new(scss, syntax: :scss, load_paths: load_paths).render
end
end
这样,您可以 link 到 /stylesheets/tenant/1.css
,这将为使用 Sass 引擎的租户呈现 CSS。
在这种情况下,在 views/stylesheets/_tenant.css.erb 中,您会得到类似这样的内容(这是一个 ERB 文件,但您现在可以在其中使用 Sass):
@import "bootstrap-buttons";
<% if params[:primary_color].present? %>
$primary-color: <%= params[:primary_color] %>;
h1, h2, h3, h4, h5, h6 {
color: $primary-color;
}
<% end %>
<% if params[:secondary_color].present? %>
$secondary-color: <%= params[:secondary_color] %>;
a {
color: $secondary-color;
&:hover {
color: darken($secondary-color, 10%);
}
}
<% end %>
您会注意到,我现在可以使用 @import
为 Sass 引擎导入样式表路径中的任何内容(在这种情况下,我可以利用 Bootstrap 中的一些助手Sass 库)。
当支持 CSS 的模型更新时,您需要某种缓存清理器来擦除缓存:
class Tenant < ActiveRecord::Base
after_update do
Rails.cache.delete("tenant_css_#{id}")
end
end
简而言之,这就是 Rails 方面。
在 Ember 中,我的猜测是您需要根据 ID 加载样式表,这样样式表就不能 hard-coded 到 "index.html" 中。 Ember CSS Routes 插件可能对你有用,但我发现它只是将 <link>
附加到 header,所以如果你需要随时交换 CSS 样式表,这不会'不工作。我通过这样的路线解决了这个问题:
afterModel(model, transition) {
// dynamically form the URL here
const url = "/stylesheets/tenant/1";
// build link object
const $link = $('<link>', { rel: 'stylesheet', href: url, id: 'tenant-styles' });
// resolve the promise once the stylesheet loads
const promise = new RSVP.Promise((resolve, reject) => {
$link.on('load', () => {
$link.appendTo('head');
resolve();
}).on('error', () => {
// resolve anyway, no stylesheet in this case
resolve();
});
});
return promise;
},
// remove the link when exiting
resetController(controller, isExiting, transition) {
this._super(...arguments);
if (isExiting) {
$('#tenant-styles').remove();
}
}
您还可以在 <head>
中添加一个空白元素,然后使用 Ember Wormhole 格式化 <link>
标记并呈现到 "wormhole" 中。
编辑
您也可以查看 rendering Sass directly in the client application。对于像两种颜色这样简单的东西,这不会对性能产生太大影响,特别是如果您使用 service worker 或类似工具来缓存结果。
我正在开发一个将许多单独的 "sites" 呈现为子目录的应用程序 - 例如/client/1
、/client/2
等。对于其中的每一个,可以在应用程序的管理部分指定两个颜色值。
我想知道是否有一种方法可以将最初发布到后端 API 然后由 Ember 从后端检索到的值注入到 SCSS 文件中以用于预处理?
到目前为止我还没有找到解决办法。
在我们的 Ember/Rails 应用程序中,我们根据数据库中的某些设置为每个客户端生成 CSS 文件。例如,我们的 Tenant
模型有两个字段:
{
primary_color: 'ff3300',
secondary_color: '00ff00'
}
我们公开路线
scope '/stylesheets', format: 'css' do
get 'tenant/:tenant_id', to: 'stylesheets#tenant_css'
end
我们的控制器看起来像这样:
class StylesheetsController < ApplicationController
layout nil
rescue_from 'ActiveRecord::RecordNotFound' do
render nothing: true, status: 404
end
def tenant_css
# fetch model
tenant = Tenant.find(params[:tenant_id])
# cache the css under a unique key for tenant
cache_key = "tenant_css_#{tenant.id}"
# fetch the cache
css = Rails.cache.fetch(cache_key) do
# pass sass "params"
render_css_for 'tenant', {
primary_color: tenant.primary_color,
secondary_color: tenant.secondary_color
}
end
render_as_css css
end
protected
# our renderer, could also add a custom one, but simple enough here
def render_as_css(css)
render text: css, content_type: 'text/css'
end
# looks for a template in views/stylesheets/_#{template}.css.erb
def render_css_for(template, params = {})
# load the template, parse ERB w params
scss = render_to_string partial: template, locals: { params: params }
load_paths = [Rails.root.join('app/assets/stylesheets')]
# parse the rendered template via Saas
Sass::Engine.new(scss, syntax: :scss, load_paths: load_paths).render
end
end
这样,您可以 link 到 /stylesheets/tenant/1.css
,这将为使用 Sass 引擎的租户呈现 CSS。
在这种情况下,在 views/stylesheets/_tenant.css.erb 中,您会得到类似这样的内容(这是一个 ERB 文件,但您现在可以在其中使用 Sass):
@import "bootstrap-buttons";
<% if params[:primary_color].present? %>
$primary-color: <%= params[:primary_color] %>;
h1, h2, h3, h4, h5, h6 {
color: $primary-color;
}
<% end %>
<% if params[:secondary_color].present? %>
$secondary-color: <%= params[:secondary_color] %>;
a {
color: $secondary-color;
&:hover {
color: darken($secondary-color, 10%);
}
}
<% end %>
您会注意到,我现在可以使用 @import
为 Sass 引擎导入样式表路径中的任何内容(在这种情况下,我可以利用 Bootstrap 中的一些助手Sass 库)。
当支持 CSS 的模型更新时,您需要某种缓存清理器来擦除缓存:
class Tenant < ActiveRecord::Base
after_update do
Rails.cache.delete("tenant_css_#{id}")
end
end
简而言之,这就是 Rails 方面。
在 Ember 中,我的猜测是您需要根据 ID 加载样式表,这样样式表就不能 hard-coded 到 "index.html" 中。 Ember CSS Routes 插件可能对你有用,但我发现它只是将 <link>
附加到 header,所以如果你需要随时交换 CSS 样式表,这不会'不工作。我通过这样的路线解决了这个问题:
afterModel(model, transition) {
// dynamically form the URL here
const url = "/stylesheets/tenant/1";
// build link object
const $link = $('<link>', { rel: 'stylesheet', href: url, id: 'tenant-styles' });
// resolve the promise once the stylesheet loads
const promise = new RSVP.Promise((resolve, reject) => {
$link.on('load', () => {
$link.appendTo('head');
resolve();
}).on('error', () => {
// resolve anyway, no stylesheet in this case
resolve();
});
});
return promise;
},
// remove the link when exiting
resetController(controller, isExiting, transition) {
this._super(...arguments);
if (isExiting) {
$('#tenant-styles').remove();
}
}
您还可以在 <head>
中添加一个空白元素,然后使用 Ember Wormhole 格式化 <link>
标记并呈现到 "wormhole" 中。
编辑
您也可以查看 rendering Sass directly in the client application。对于像两种颜色这样简单的东西,这不会对性能产生太大影响,特别是如果您使用 service worker 或类似工具来缓存结果。