mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-23 23:04:48 +08:00
Previously we were compiling core and theme CSS into two targets: Desktop and Mobile. The majority of both files was the 'common' css. This commit splits those common styles into their own targets so that there is less duplication. This should improve compilation times + cache reuse, as well as opening the door for experiments with media-query-based mobile-modes. The only functional change is that we can no longer use `@extend` to copy 'common' rules in core to mobile/desktop. This is probably for the best. Duplication and/or mixins are a more native-css pattern for this. Plugins already have a common / mobile / desktop pattern, so are unchanged by this commit.
266 lines
8.3 KiB
Ruby
Vendored
266 lines
8.3 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
require "stylesheet/compiler"
|
|
|
|
RSpec.describe Stylesheet::Compiler do
|
|
describe "compilation" do
|
|
Dir["#{Rails.root.join("app/assets/stylesheets")}/*.scss"].each do |path|
|
|
next if path =~ /ember_cli/
|
|
|
|
path = File.basename(path, ".scss")
|
|
|
|
it "can compile '#{path}' css" do
|
|
css, _map = Stylesheet::Compiler.compile_asset(path)
|
|
expect(css.length).to be > 500
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with a theme" do
|
|
let!(:theme) { Fabricate(:theme) }
|
|
let!(:upload) do
|
|
UploadCreator.new(file_from_fixtures("logo.png"), "logo.png").create_for(
|
|
Discourse.system_user.id,
|
|
)
|
|
end
|
|
let!(:upload_theme_field) do
|
|
ThemeField.create!(
|
|
theme: theme,
|
|
target_id: 0,
|
|
name: "primary",
|
|
upload: upload,
|
|
value: "",
|
|
type_id: ThemeField.types[:theme_upload_var],
|
|
)
|
|
end
|
|
let!(:stylesheet_theme_field) do
|
|
ThemeField.create!(
|
|
theme: theme,
|
|
target_id: 0,
|
|
name: "scss",
|
|
value: "body { background: $primary }",
|
|
type_id: ThemeField.types[:scss],
|
|
)
|
|
end
|
|
|
|
it "theme stylesheet should be able to access theme asset variables" do
|
|
theme.reload.with_scss_load_paths do |load_paths|
|
|
css, _map =
|
|
Stylesheet::Compiler.compile_asset(
|
|
"common_theme",
|
|
theme_id: theme.id,
|
|
theme_variables: theme.scss_variables,
|
|
load_paths: load_paths,
|
|
)
|
|
expect(css).to include(upload.url)
|
|
end
|
|
end
|
|
|
|
context "with a plugin" do
|
|
let :plugin1 do
|
|
plugin1 = plugin_from_fixtures("my_plugin")
|
|
plugin1.register_css "body { background: $primary }"
|
|
plugin1
|
|
end
|
|
|
|
let :plugin2 do
|
|
plugin2 = plugin_from_fixtures("scss_plugin")
|
|
plugin2
|
|
end
|
|
|
|
before do
|
|
Discourse.plugins << plugin1
|
|
Discourse.plugins << plugin2
|
|
plugin1.activate!
|
|
plugin2.activate!
|
|
Stylesheet::Importer.register_imports!
|
|
end
|
|
|
|
after do
|
|
Discourse.plugins.delete plugin1
|
|
Discourse.plugins.delete plugin2
|
|
Stylesheet::Importer.register_imports!
|
|
DiscoursePluginRegistry.reset!
|
|
end
|
|
|
|
it "does not include theme variables in plugins" do
|
|
css, _map = Stylesheet::Compiler.compile_asset("my_plugin", theme_id: theme.id)
|
|
expect(css).not_to include(upload.url)
|
|
expect(css).to include("background:")
|
|
end
|
|
|
|
context "with the `rtl` option" do
|
|
it "generates an RTL version of the plugin CSS if the option is true" do
|
|
css, _ = Stylesheet::Compiler.compile_asset("scss_plugin", theme_id: theme.id, rtl: true)
|
|
expect(css).to include(".pull-left{float:right}")
|
|
expect(css).not_to include(".pull-left{float:left}")
|
|
end
|
|
|
|
it "returns an unchanged version of the plugin CSS" do
|
|
css, _ = Stylesheet::Compiler.compile_asset("scss_plugin", theme_id: theme.id, rtl: false)
|
|
expect(css).to include(".pull-left{float:left}")
|
|
expect(css).not_to include(".pull-left{float:right}")
|
|
end
|
|
end
|
|
|
|
it "supports SCSS imports" do
|
|
css, _map = Stylesheet::Compiler.compile_asset("scss_plugin", theme_id: theme.id)
|
|
|
|
expect(css).to include("border-color:red")
|
|
expect(css).to include("fill:green")
|
|
expect(css).to include("line-height:1.2em")
|
|
expect(css).to include("border-color:#c00")
|
|
expect(css).to include("--simple-css-color: red")
|
|
end
|
|
end
|
|
end
|
|
|
|
it "supports absolute-image-url" do
|
|
scss = Stylesheet::Importer.new({}).prepended_scss
|
|
scss += ".body{background-image: absolute-image-url('/favicons/github.png');}"
|
|
css, _map = Stylesheet::Compiler.compile(scss, "test.scss")
|
|
|
|
expect(css).to include('url("http://test.localhost/images/favicons/github.png")')
|
|
expect(css).not_to include("absolute-image-url")
|
|
end
|
|
|
|
it "supports absolute-image-url in subfolder" do
|
|
set_subfolder "/subfo"
|
|
scss = Stylesheet::Importer.new({}).prepended_scss
|
|
scss += ".body{background-image: absolute-image-url('/favicons/github.png');}"
|
|
css, _map = Stylesheet::Compiler.compile(scss, "test2.scss")
|
|
|
|
expect(css).to include('url("http://test.localhost/subfo/images/favicons/github.png")')
|
|
expect(css).not_to include("absolute-image-url")
|
|
end
|
|
|
|
it "supports absolute-image-url with CDNs" do
|
|
set_cdn_url "https://awesome.com"
|
|
scss = Stylesheet::Importer.new({}).prepended_scss
|
|
scss += ".body{background-image: absolute-image-url('/favicons/github.png');}"
|
|
css, _map = Stylesheet::Compiler.compile(scss, "test2.scss")
|
|
|
|
expect(css).to include('url("https://awesome.com/images/favicons/github.png")')
|
|
expect(css).not_to include("absolute-image-url")
|
|
end
|
|
|
|
it "supports absolute-image-url in plugins" do
|
|
set_cdn_url "https://awesome.com"
|
|
scss = Stylesheet::Importer.new({}).prepended_scss
|
|
scss +=
|
|
".body{background-image: absolute-image-url('/plugins/discourse-special/images/somefile.png');}"
|
|
css, _map = Stylesheet::Compiler.compile(scss, "discourse-special.scss")
|
|
|
|
expect(css).to include(
|
|
'url("https://awesome.com/plugins/discourse-special/images/somefile.png")',
|
|
)
|
|
expect(css).not_to include("absolute-image-url")
|
|
end
|
|
|
|
context "with a color scheme" do
|
|
it "returns the default color definitions when no color scheme is specified" do
|
|
css, _map = Stylesheet::Compiler.compile_asset("color_definitions")
|
|
expect(css).to include("--header_background:")
|
|
expect(css).to include("--primary:")
|
|
end
|
|
|
|
it "returns color definitions for a custom color scheme" do
|
|
cs =
|
|
Fabricate(
|
|
:color_scheme,
|
|
name: "Stylish",
|
|
color_scheme_colors: [
|
|
Fabricate(:color_scheme_color, name: "header_primary", hex: "88af8e"),
|
|
Fabricate(:color_scheme_color, name: "header_background", hex: "f8745c"),
|
|
],
|
|
)
|
|
|
|
css, _map = Stylesheet::Compiler.compile_asset("color_definitions", color_scheme_id: cs.id)
|
|
|
|
expect(css).to include("--header_background: #f8745c")
|
|
expect(css).to include("--header_primary: #88af8e")
|
|
expect(css).to include("--header_background-rgb: 248, 116, 92")
|
|
end
|
|
|
|
context "with a plugin" do
|
|
before do
|
|
plugin = plugin_from_fixtures("color_definition")
|
|
Discourse.plugins << plugin
|
|
plugin.activate!
|
|
end
|
|
|
|
after do
|
|
Discourse.plugins.pop
|
|
DiscoursePluginRegistry.reset!
|
|
end
|
|
|
|
it "includes color definitions from plugins" do
|
|
css, _map = Stylesheet::Compiler.compile_asset("color_definitions")
|
|
|
|
expect(css).to include("--plugin-color")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "indexes" do
|
|
it "include all SCSS files in their respective folders" do
|
|
refs = []
|
|
|
|
Dir
|
|
.glob(Rails.root.join("app/assets/stylesheets/**/*/"))
|
|
.each do |dir|
|
|
Dir
|
|
.glob("#{dir}_index.scss")
|
|
.each do |indexfile|
|
|
contents = File.read indexfile
|
|
|
|
files = Dir["#{dir}*.scss"]
|
|
files -= Dir["#{dir}_index.scss"]
|
|
files.each do |path|
|
|
filename = File.basename(path, ".scss")
|
|
if !contents.match(/@import "#{filename}";/)
|
|
refs << "#{filename} import missing in #{indexfile}"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
expect(refs).to eq([])
|
|
end
|
|
end
|
|
|
|
describe ".compile" do
|
|
it "produces RTL CSS when rtl option is given" do
|
|
css, _ = Stylesheet::Compiler.compile("a{right:1px}", "test.scss", rtl: true)
|
|
expect(css).to eq("a{left:1px}")
|
|
end
|
|
|
|
it "runs through postcss" do
|
|
css, map = Stylesheet::Compiler.compile(<<~SCSS, "test.scss")
|
|
@media (min-resolution: 2dppx) {
|
|
body {
|
|
background-color: light-dark(white, black);
|
|
}
|
|
}
|
|
SCSS
|
|
|
|
expect(css).to include("-webkit-min-device-pixel-ratio")
|
|
expect(css).to include("csstools-light-dark-toggle")
|
|
expect(map.size).to be > 10
|
|
end
|
|
|
|
it "handles errors gracefully" do
|
|
bad_css = <<~SCSS
|
|
$foo: unquote("https://notacolor.example.com");
|
|
.example {
|
|
color: $foo;
|
|
}
|
|
SCSS
|
|
|
|
expect { Stylesheet::Compiler.compile(bad_css, "test.scss") }.to raise_error(
|
|
DiscourseJsProcessor::TranspileError,
|
|
/Missed semicolon/,
|
|
)
|
|
end
|
|
end
|
|
end
|