Статьи

Ответственное использование @error в Sass

Начиная с Ruby Sass 3.4 и LibSass 3.1, можно использовать директиву @error . Эта директива, аналогичная @warn , предназначена для @warn процесса выполнения и отображения настраиваемого сообщения в текущий поток вывода (вероятно, консоль).

Само собой разумеется, что эта функция очень полезна при создании функций и миксинов, включающих немного логики Sass, чтобы контролировать ввод автора и выдавать ошибку в случае, если что-то пойдет не так. Вы должны признать, что это лучше, чем позволить несчастному сбою компилятора, не так ли?

Все прекрасно. За исключением Sass 3.3 все еще широко используется. Даже Sass 3.2 в некоторых местах. Обновление Sass не всегда легкая задача, особенно в больших проектах. Иногда тратить время и бюджет на обновление чего-либо, что работает нормально, не вариант. Для этих более старых версий @error ничего не значит и рассматривается как пользовательская директива at, что совершенно допустимо в Sass по соображениям прямой совместимости.

Значит ли это, что мы не можем использовать @error если не решим поддерживать только последние движки Sass? Ну, вы можете себе представить, что есть способ, отсюда и эта статья.

В чем идея?

Идея проста: если @error поддерживается, мы используем его. @warn мы используем @warn . Хотя @warn не препятствует дальнейшей работе компилятора, поэтому мы можем захотеть вызвать ошибку компиляции после предупреждения, чтобы компиляция прервалась навсегда. Наслаждайтесь этим, это не так часто, что вы можете безрассудно потерпеть крах.

Это означает, что нам нужно обернуть все это в миксин, назовем это log(..) . Мы могли бы использовать это так:

 @include log('Oops, something is wrong with what you just did!'); 

Вы должны признать, это довольно рад, не так ли? Хорошо, хватит хвастаться, давай построим это.

Сборка регистратора

Таким образом, наш миксин работает точно так же, как @error или @warn поскольку это всего лишь оболочка. Таким образом, ему нужен только один аргумент: сообщение.

 @mixin log($message) { ... } 

Вы можете спросить себя, как мы будем проверять поддержку @error . Сначала я придумал хакерское решение, связанное с анализом версий, но это было ужасно. Кроме того, я полностью упустил из виду тот факт, что разработчики ядра Sass — это умные люди, которые подумали обо всем этом и представили ключ at-error для feature-exists(..) , возвращающий информацию о том, поддерживается ли функция.

 @mixin log($message) { @if feature-exists('at-error') == true { @error $message; } @else { @warn $message; } } 

Если вы читатель патча, вы можете знать, что feature-exists(..) была представлена ​​только в Sass 3.3. Это не распространяется на Sass 3.2! Ну, это отчасти правда. В Sass 3.2 feature-exists('at-error') оценивается как строка, которая соответствует действительности . Добавляя == true , мы убеждаемся, что Sass 3.2 не входит в это условие и переходит на версию @warn .

Все идет нормально. Хотя мы должны вызвать ошибку компиляции после предупреждения. Как мы собираемся это сделать? Ну, есть много способов разбить Sass, но в идеале мы бы хотели что-то, что вы можете узнать. Некоторое время назад Эрик Сюзанн выдвинул идею: вызова функции без оператора @return достаточно для сбоя. Этот шаблон часто называют noop , для бездействия . В основном это пустая функция, ничего не делать. Из-за способа работы Sass происходит сбой компилятора. И это хорошо!

 @function noop() {} 

И последнее, но не менее важное, что касается этой функции, как мы будем ее называть? Функции Sass могут быть вызваны только в определенных местах. Есть несколько способов, доступных для нас:

  • Фиктивная переменная, например: $_: noop()
  • crash: noop() свойство, например: crash: noop()
  • Пустое условие, например: @if noop() {}
  • И вы, вероятно, можете найти несколько других способов вызова этой функции.

Я хотел бы предостеречь вас от использования $_ поскольку эта переменная обычно используется в библиотеках и средах Sass. Хотя это может и не быть проблемой в Sass 3.3+, в Sass 3.2 это перезапишет любую глобальную переменную $_ , что в некоторых случаях приведет к трудным отслеживанию проблем. Давайте перейдем к пустому условию, так как оно имеет смысл, когда соединено с noop . Условие noop для функции noop.

 @mixin log($message) { @if feature-exists('at-error') == true { @error $message; } @else { @warn $message; // Because functions cannot be called anywhere in Sass, // we need to hack the call in a dummy condition. @if noop() {} } } 

Хорошо! Давайте проверим это с нашим предыдущим кодом:

 @include log('Oops, something is wrong with what you just did!'); 

Вот LibSass:

 message: path/to/file.scss 1:1 Oops, something is wrong with what you just did! Details: column: 1 line: 1 file: /path/to/file.scss status: 1 messageFormatted: path/to/file.scss 1:1 Oops, something is wrong with what you just did! 

Вот Sass 3.4:

 Error: Oops, something is wrong with what you just did! on line 1 of path/to/file.scss, in `log' Use --trace for backtrace. 

Вот Sass 3.2 и 3.3 (вывод — дикое предположение, так как я больше не могу тестировать эти версии в моем терминале):

 WARNING: Oops, something is wrong with what you just did! on line 1 of path/to/file.scss, in `log' ERROR: Function noop finished without @return on line 1 of path/to/file.scss, in `log' Use --trace for backtrace. 

Это, кажется, делает трюк! В любом движке, даже старом, компилятор завершается. На тех, которые поддерживают @at-error , они сразу получают сообщение об ошибке. На тех, которые этого не делают, они получают сообщение как предупреждение, а затем происходит сбой компиляции благодаря функции noop .

Возможность входа в функции

Единственная проблема, с которой мы столкнулись в нашей текущей настройке, заключается в том, что мы не можем выдать ошибку из функции, так как мы создали миксин. Миксин не может быть включен в функцию (так как он может печатать код CSS, который не имеет ничего общего с функцией Sass)!

Что если мы превратили наш миксин в функцию для начинающих? В этот момент происходит нечто странное: @error не распознается как допустимая директива at для функции в Sass 3.3-, которая, таким образом, терпит неудачу с помощью:

Функции могут содержать только объявления переменных и управляющие директивы.

Справедливо. Это означает, что нам больше не нужен взлом noop так как неподдерживаемые двигатели аварийно noop без нас его форсировать. Хотя мы должны поместить директиву @warn вверху потока, чтобы сообщение распечатывалось в консоли автора перед сбоем.

 @function log($message) { @if feature-exists('at-error') != true { @warn $message; } @else { @error $message; } } 

Затем мы можем предоставить миксин, чтобы иметь более дружественный API, чем грязные пустые условия и фиктивные переменные.

 @mixin log($message) { // Because functions cannot be called anywhere in Sass, // we need to hack the call in a dummy condition. // There are other ways to do this, such as `log: log(..)`. @if log($message) {} } 

Последние мысли

Это оно! Теперь мы можем использовать функцию log(..) внутри функций (из-за ограничений) и log(..) любом месте, чтобы ответственно выдавать ошибку. Довольно аккуратно!

Вот полный код:

Поиграйте с этим в SassMeister.

Для более продвинутой системы ведения журналов в Sass, я могу порекомендовать вам прочитать Building A Logger Mixin . Что касается поддержки старых версий Sass, я предлагаю вам взглянуть на то, когда и как поддерживать несколько версий Sass .