DEV: Move to Sass compilation to dart-sass (#19910)

This PR is a major change to Sass compilation in Discourse.

The new version of sass-ruby moves to dart-sass putting we back on the supported version of Sass. It does so while keeping compatibility with the existing method signatures, so minimal change is needed in Discourse for this change.

This moves us

From:
  - sassc 2.0.1 (Feb 2019)
  - libsass 3.5.2 (May 2018)

To:
  - dart-sass 1.58

This update applies the following breaking changes:

> 
> These breaking changes are coming soon or have recently been released:
> 
>  [Functions are stricter about which units they allow](https://sass-lang.com/documentation/breaking-changes/function-units) beginning in Dart Sass 1.32.0.
> 
>  [Selectors with invalid combinators are invalid](https://sass-lang.com/documentation/breaking-changes/bogus-combinators) beginning in Dart Sass 1.54.0.
> 
>  [/ is changing from a division operation to a list separator](https://sass-lang.com/documentation/breaking-changes/slash-div) beginning in Dart Sass 1.33.0.
> 
>  [Parsing the special syntax of @-moz-document will be invalid](https://sass-lang.com/documentation/breaking-changes/moz-document) beginning in Dart Sass 1.7.2.
> 
>  [Compound selectors could not be extended](https://sass-lang.com/documentation/breaking-changes/extend-compound) in Dart Sass 1.0.0 and Ruby Sass 4.0.0.


SCSS files have been migrated automatically using `sass-migrator division app/assets/stylesheets/**/*.scss`
This commit is contained in:
Rafael dos Santos Silva 2023-02-07 12:24:57 -03:00 committed by GitHub
parent 9b0b60274a
commit 6e522e4aad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 70 additions and 43 deletions

View File

@ -229,10 +229,9 @@ gem "logstash-event", require: false
gem "logstash-logger", require: false
gem "logster"
# NOTE: later versions of sassc are causing a segfault, possibly dependent on processer architecture
# and until resolved should be locked at 2.0.1
gem "sassc", "2.0.1", require: false
gem "sassc-rails"
# These are forks of sassc and sassc-rails with dart-sass support
gem "dartsass-ruby"
gem "dartsass-sprockets"
gem "rotp", require: false

View File

@ -121,6 +121,14 @@ GEM
crass (1.0.6)
css_parser (1.14.0)
addressable
dartsass-ruby (3.0.1)
sass-embedded (~> 1.54)
dartsass-sprockets (3.0.0)
dartsass-ruby (~> 3.0)
railties (>= 4.0.0)
sprockets (> 3.0)
sprockets-rails
tilt
date (3.3.3)
debug_inspector (1.1.0)
diff-lcs (1.5.0)
@ -159,6 +167,7 @@ GEM
gc_tracer (1.5.1)
globalid (1.1.0)
activesupport (>= 5.0)
google-protobuf (3.21.12)
guess_html_encoding (0.0.11)
hana (1.3.7)
hashdiff (1.0.1)
@ -429,15 +438,17 @@ GEM
sanitize (6.0.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
sassc (2.0.1)
ffi (~> 1.9)
rake
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sass-embedded (1.58.0)
google-protobuf (~> 3.21)
rake (>= 10.0.0)
sass-embedded (1.58.0-aarch64-linux-gnu)
google-protobuf (~> 3.21)
sass-embedded (1.58.0-arm64-darwin)
google-protobuf (~> 3.21)
sass-embedded (1.58.0-x86_64-darwin)
google-protobuf (~> 3.21)
sass-embedded (1.58.0-x86_64-linux-gnu)
google-protobuf (~> 3.21)
selenium-webdriver (4.8.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
@ -540,6 +551,8 @@ DEPENDENCIES
cose
cppjieba_rb
css_parser
dartsass-ruby
dartsass-sprockets
diffy
digest
discourse-fonts
@ -627,8 +640,6 @@ DEPENDENCIES
ruby-readability
rubyzip
sanitize
sassc (= 2.0.1)
sassc-rails
selenium-webdriver
shoulda-matchers
sidekiq

View File

@ -2,6 +2,8 @@
// To style group content differently, use the existing classes with a .group parent class.
// For example: .group .user-secondary-navigation
@use "sass:math";
.group-details-container {
background: var(--primary-very-low);
padding: 20px;
@ -55,7 +57,7 @@
}
$size: 50px;
$icon-size: $size / 1.8;
$icon-size: math.div($size, 1.8);
.avatar-flair-image {
width: $size;

View File

@ -1,3 +1,5 @@
@use "sass:math";
.groups-header {
display: flex;
flex-wrap: wrap;
@ -114,7 +116,7 @@
}
$size: 40px;
$icon-size: $size / 1.8;
$icon-size: math.div($size, 1.8);
.group-avatar-flair {
display: inline-block;

View File

@ -27,6 +27,8 @@
// 1. Default Settings
////////////////////////
@use "sass:math";
$overlay-color: #0b0b0b !default;
$overlay-opacity: 0.8 !default;
$shadow: 0 0 8px rgba(0, 0, 0, 0.6) !default; // shadow on image or iframe
@ -46,7 +48,7 @@ $include-iframe-type: true !default;
$iframe-padding-top: 40px !default;
$iframe-background: #000 !default;
$iframe-max-width: 900px !default;
$iframe-ratio: 9/16 !default;
$iframe-ratio: math.div(9, 16) !default;
// Image-type options
$include-image-type: true !default;

View File

@ -1,3 +1,5 @@
@use "sass:math";
$card_width: 580px;
$avatar_width: 120px;
$avatar_margin: -50px; // negative margin makes avatars extend above cards
@ -265,7 +267,7 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
color: var(--primary);
.d-icon {
margin: auto;
font-size: $avatar_width / 1.5;
font-size: math.div($avatar_width, 1.5);
}
&.rounded {
border-radius: 50%;

View File

@ -4,6 +4,8 @@
// https://github.com/terkel/mathsass
// Constants
@use "sass:math";
$E: 2.718281828459045;
$PI: 3.141592653589793;
$LN2: 0.6931471805599453;
@ -48,7 +50,7 @@ $SQRT2: 1.4142135623730951;
}
} @else if $x >= 1 {
@while $x >= 1 {
$x: $x / 2;
$x: $x * 0.5;
$exp: $exp + 1;
}
}
@ -59,7 +61,7 @@ $SQRT2: 1.4142135623730951;
// @param {Number} $x
// @param {Number} $exp
@function ldexp($x, $exp) {
$b: if($exp >= 0, 2, 1 / 2);
$b: if($exp >= 0, 2, 1 * 0.5);
@if $exp < 0 {
$exp: $exp * -1;
}
@ -80,11 +82,11 @@ $SQRT2: 1.4142135623730951;
// log(10) // 2.30259
@function log($x) {
@if $x <= 0 {
@return 0 / 0;
@return math.div(0, 0);
}
$k: nth(frexp($x / $SQRT2), 2);
$x: $x / ldexp(1, $k);
$x: ($x - 1) / ($x + 1);
$k: nth(frexp(math.div($x, $SQRT2)), 2);
$x: math.div($x, ldexp(1, $k));
$x: math.div($x - 1, $x + 1);
$x2: $x * $x;
$i: 1;
$s: $x;
@ -93,7 +95,7 @@ $SQRT2: 1.4142135623730951;
$x: $x * $x2;
$i: $i + 2;
$sp: $s;
$s: $s + $x / $i;
$s: $s + math.div($x, $i);
}
@return $LN2 * $k + 2 * $s;
}
@ -115,7 +117,7 @@ $SQRT2: 1.4142135623730951;
$exp: floor($exp * 0.5);
$base: $base * $base;
}
@return if($s != 0, 1 / $r, $r);
@return if($s != 0, math.div(1, $r), $r);
}
// Returns E^x, where x is the argument, and E is Euler's constant, the base of the natural logarithms.
@ -126,7 +128,7 @@ $SQRT2: 1.4142135623730951;
@function exp($x) {
$ret: 0;
@for $n from 0 to 24 {
$ret: $ret + ipow($x, $n) / fact($n);
$ret: $ret + math.div(ipow($x, $n), fact($n));
}
@return $ret;
}
@ -158,7 +160,7 @@ $SQRT2: 1.4142135623730951;
}
$ret: 1;
@for $i from 1 through 24 {
$ret: $ret - (pow($ret, 2) - $x) / (2 * $ret);
$ret: $ret - math.div(pow($ret, 2) - $x, 2 * $ret);
}
@return $ret;
}

View File

@ -5,6 +5,8 @@
// Media queries
// --------------------------------------------------
@use "sass:math";
$breakpoints: (
mobile-small: 320px,
mobile-medium: 350px,
@ -162,7 +164,7 @@ $hpad: 0.65em;
$encoded: "";
$slice: 2000;
$index: 0;
$loops: ceil(str-length($svg) / $slice);
$loops: ceil(math.div(str-length($svg), $slice));
@for $i from 1 through $loops {
$chunk: str-slice($svg, $index, $index + $slice - 1);

View File

@ -6,6 +6,8 @@
// Layout dimensions
// --------------------------------------------------
@use "sass:math";
$small-width: 800px !default;
$medium-width: 995px !default;
$large-width: 1110px !default;
@ -165,7 +167,7 @@ $box-shadow: (
// Uses an approximation of sRGB blending, GAMMA=2 instead of GAMMA=2.2
@function srgb-scale($foreground, $background, $percent) {
$ratio: ($percent / 100%);
$ratio: math.div($percent, 100%);
$iratio: 1 - $ratio;
$f_r2: red($foreground) * red($foreground);
$f_g2: green($foreground) * green($foreground);

View File

@ -1,3 +1,5 @@
@use "sass:math";
$flair-size: 18px;
.select-kit.flair-chooser {
@ -15,14 +17,14 @@ $flair-size: 18px;
width: $flair-size;
&.rounded {
background-size: ($flair-size / 1.4) ($flair-size / 1.4);
background-size: math.div($flair-size, 1.4) math.div($flair-size, 1.4);
border-radius: 50%;
}
.d-icon {
display: block;
height: ($flair-size / 1.8);
width: ($flair-size / 1.8);
height: math.div($flair-size, 1.8);
width: math.div($flair-size, 1.8);
}
}

View File

@ -460,7 +460,7 @@ class ThemeField < ActiveRecord::Base
else
self.error = nil unless error.nil?
end
rescue SassC::SyntaxError => e
rescue SassC::SyntaxError, SassC::NotRenderedError => e
self.error = e.message unless self.destroyed?
end
self.compiler_version = Theme.compiler_version

View File

@ -60,6 +60,7 @@ module Stylesheet
theme_field: options[:theme_field],
color_scheme_id: options[:color_scheme_id],
load_paths: load_paths,
validate_source_map_path: false,
)
result = engine.render

View File

@ -47,7 +47,7 @@ class Stylesheet::Manager::Builder
color_scheme_id: @color_scheme&.id,
load_paths: load_paths,
)
rescue SassC::SyntaxError => e
rescue SassC::SyntaxError, SassC::NotRenderedError => e
if Stylesheet::Importer::THEME_TARGETS.include?(@target.to_s)
# no special errors for theme, handled in theme editor
["", nil]

View File

@ -164,7 +164,7 @@ RSpec.describe Stylesheet::Compiler do
expect(css).to include("--header_background: #f8745c")
expect(css).to include("--header_primary: #88af8e")
expect(css).to include("--header_background-rgb: 248,116,92")
expect(css).to include("--header_background-rgb: 248, 116, 92")
end
context "with a plugin" do

View File

@ -118,7 +118,7 @@ RSpec.describe Stylesheet::Importer do
styles = Stylesheet::Importer.new({ theme_id: theme.id }).import_color_definitions
expect(styles).to include("Color definitions from Child Theme")
expect(styles).to include("--custom-color: red")
expect(styles).to include("--custom-color-rgb: 0,0,128")
expect(styles).to include("--custom-color-rgb: 0, 0, 128")
end
it "should include default theme color definitions" do

View File

@ -680,8 +680,8 @@ RSpec.describe Stylesheet::Manager do
manager: manager,
).compile(force: true)
expect(stylesheet).not_to include("--primary: #c00;")
expect(stylesheet).to include("--primary: #222;") # from base scheme
expect(stylesheet).not_to include("--primary: #CC0000;")
expect(stylesheet).to include("--primary: #222222;") # from base scheme
end
it "uses the correct scheme when a valid scheme id is used" do
@ -726,7 +726,7 @@ RSpec.describe Stylesheet::Manager do
stylesheet2 = builder2.compile
expect(stylesheet).not_to eq(stylesheet2)
expect(stylesheet2).to include("--primary: #c00;")
expect(stylesheet2).to include("--primary: #CC0000;")
end
it "includes updated font definitions" do

View File

@ -160,7 +160,7 @@ HTML
field.value = "@import 'missingfile';"
field.save!
field.ensure_baked!
expect(field.error).to include("File to import not found or unreadable: missingfile")
expect(field.error).to include("Error: Can't find stylesheet to import.")
field.value = "body {color: blue};"
field.save!

View File

@ -47,7 +47,7 @@ RSpec.describe EmailStyleUpdater do
false,
)
expect(updater.errors).to_not be_empty
expect(updater.errors.first).to include("Invalid CSS after")
expect(updater.errors.first).to include('Error: expected "}".')
expect_settings_to_be_unset
end
end