Перевод статьи The Module System is Launched
Команда Sass уже много лет знает, что правило @import
, одно из самых ранних добавлений в Sass, не было хорошим настолько насколько мы хотели. Что вызывало перечень проблем для наших пользователей:
- Было почти невозможно выяснить где была объявлена переменная, миксин или функция (назовем их «члены» или «members»), поскольку всё, что объявлялось в одном CSS файле было доступно для всех остальных файлов, что были импортированы после.
- Даже если вы явно импортируете каждый SASS файл, который определяет «члены», в итоге вы получите дубликаты CSS и странные побочные эффекты, так как таблицы стилей перезагружались с нуля при каждом импорте.
- Использовать краткие и простые имена было небезопасно, потому что всегда была вероятность, что некоторые другие таблицы стилей в другом месте вашего приложения будут использовать то же имя и сломают вашу логику. Чтобы обезопасить себя, пользователям приходилось вручную добавлять длинные, неуклюжие пространства имен (namespaces) ко всему, что они определяли.
- Авторы библиотек не могли гарантировать, что их хелперы не будут доступны для пользователей этих библиотек, что вызовет путаницу и головную боль с обратной совместимостью.
- Правило
@extend
может влиять на любой селектор в любом месте таблицы стилей, а не только там где автор его применил.
Мы также знали, что любая замена, которую мы хотели бы внедрить, должна быть спроектирована и разработана с предельной тщательностью, чтобы обеспечить прочную основу для будущего развития Sass. За последние несколько лет мы обсудили, спроектировали и разработали совершенно новую модульную систему, которая решает эти и многие другие проблемы, и сегодня мы рады сообщить, что она доступна в Dart Sass 1.23.0.
Обратите внимание, что модульная система полностью обратно совместима. Существующие функции не были удалены или объявлены нежелательным для использования, и ваши текущие Sass стили будут работать так же, как и всегда. Мы разработали модульную систему так, чтобы она была полностью совместима с @import
, чтобы авторам таблиц стилей было легко переходить к ней постепенно. В конечном итоге мы планируем избавиться от @import
, но по прошествии длительного времени только после того как у каждого будет возможность мигрировать.
@use, сердце модульной системы
Правило @use
является основной заменой @import
: оно позволяет делать CSS, переменные, миксины и функции из другой таблицы стилей доступными в текущей таблице стилей. По умолчанию переменные, миксины и функции доступны в пространстве имен на основе базового имени URL-адреса.
В дополнение к пространству имен, есть несколько важных различий между @use
и @import
:
@use
загружает таблицу стилей и включает ее CSS только один раз, независимо от того, сколько раз эта таблица стилей была использована.@use
делает имена доступными только в текущем файле стилей, а не глобально.- Члены, имена которых начинаются с
-
или_
, являются приватными для текущей таблицы стилей с@use
. - Если таблица стилей содержит
@extend
, он применяется только к импортируемым таблицам стилей, а не к таблицам стилей, которые импортируют его.
Обратите внимание, что placeholder-selectors
не имеют пространства имен, но они понимают приватность.
Контролируя пространство имен
Хотя пространство имен для @use
по умолчанию определяется базовым именем его URL-адреса, его также можно явно указать с помощью as
.
Специальная конструкция as *
также может использоваться для включения всего в пространство имен верхнего уровня. Обратите внимание, что если несколько «членов» с тем же самым именем появляются в нескольких модулях с использованием as *
, то Sass выдаст ошибку.
Конфигурируя библиотеки
Так используя @import
библиотеки часто перенастраиваются путем установки глобальных переменных, которые переопределяют переменные по умолчанию !default
, определенные в этих библиотеках. Поскольку переменные больше не являются глобальными с @use
, он поддерживает более явный способ настройки библиотек: дополнение with
.
Это устанавливает переменную $paragraph-margin-bottom
в 1.2rem перед тем как ее оценить. Дополнение with
допускает только переменные, определенные в (или перенаправленные) импортируемым модулем, и только если они определены с параметром !default
, поэтому пользователи защищены от опечаток.
@forward
, для авторов
Правило @forward
включает переменные, миксины и функции другого модуля как часть API, предоставляемого текущим модулем, не делая их видимыми для кода в текущем модуле. Это позволяет авторам библиотеки разделять свою библиотеку по множеству различных исходных файлов, не жертвуя локальностью в этих файлах. В отличие от @use
, @forward
не добавляет к именам пространства имен.
Настройка видимости
С правилом @forward
можно как показывать только определенные имена:
Так и скрывать имена, которые должны быть приватными:
Дополнительные префиксы
Если вы перенаправляете дочерний модуль через модуль all-in-one («все в одном»), вы можете захотеть добавить к этому модулю некоторое пространство имен вручную. Вы можете сделать это с помощью дополнения as
, которое добавляет префикс к каждому перенаправленному имени члена:
Таким образом, пользователи могут использовать модуль all-in-one с хорошо определенными именами для переменных темы:
Или они могут использовать дочерний модуль с простыми именами:
Встроенные модули — Built-In Modules
Новая модульная система также добавляет встроенные модули (sass:math
, sass:color
, sass:string
, sass:list
, sass:map
, sass:selector
, и sass:meta
) для хранения всех существующих встроенных функций Sass. Поскольку эти модули (как правило) будут импортироваться с пространством имен, и теперь гораздо проще использовать функции Sass, не сталкиваясь с конфликтами с обычными CSS функциями.
Это, в свою очередь, делает Sass более безопасным для добавления новых функций. Мы ожидаем добавить ряд удобных функций для этих модулей в будущем.
Переименованные функции
Некоторые функции имеют во встроенных модулях имена, отличные от названий глобальных функций. Встроенные функции, которые уже имели пространства имен определенные вручную, такие, как map-get()
, удаляют эти пространства имен во встроенных модулях, поэтому вы можете просто написать map.get()
. Аналогично, adjust-color()
, scale-color()
, иchange-color()
теперь color.adjust()
, color.scale()
, и color.change()
.
Мы также воспользовались этой возможностью, чтобы изменить несколько запутанных имен старых функций. unitless()
теперь math.is-unitless()
, а comparable()
теперь math.compatible()
.
Удаленные функции
Сокращенные цветовые функции Sass: lighten()
, darken()
, saturate()
, desaturate()
, opacify()
, fade-in()
, transparentize()
, и fade-out()
— все имели очень неинтуитивное поведение. Вместо того, чтобы плавно масштабировать связанные с ними атрибуты, они просто увеличивают их на статическую величину, так lighten($color, 20%)
скорее вернет white
для цвета с 85%
яркостью, чем вернет цвет с 88%
яркостью (20%
очень близко к полному белому цвету).
Чтобы помочь нам встать на путь исправления данной ситуации, эти функции (наряду с adjust-hue()
) не были включены в новые built-in модули. Вы можете получить тот же эффект, вызвав color.adjust()
— например, lighten($color, $amount)
эквивалентен color.adjust($color, $lightness: $amount)
— но вместо этого, мы рекомендуем попробовать использовать color.scale()
, если возможно, так как он более интуитивен.
В какой-то момент в будущем мы планируем добавить color.lighten()
и аналогичные функции в качестве сокращений для color.scale()
.
meta.load-css()
Новая модульная система так же идет вместе с новым миксином meta.load-css($url, $with: ())
. Этот миксин динамически загружает модуль с заданным URL и включает его CSS (хотя его функции, переменные и миксины сделаны недоступными). Это замена для вложенных импортов, и она помогает решить некоторые сценарии использования динамического импорта без тех многочисленных проблем, которые могут возникнуть, если новые «члены» будут загружены динамически.
Совместимость @import
Экосистема Sass не переключится на @use
в одночасье, и поэтому в настоящее время она должна хорошо взаимодействовать с @import
. Это поддерживается в обоих направлениях:
- Когда файл, содержащий
@import
, используется@use
, все в его глобальном пространстве имен обрабатывается как единый модуль. «Члены» этого модуля затем обращаются к использованию его пространства имен как к нормальному пространству имен. - Когда файл, содержащий
@use
, используется@import
, все в его публичном API добавляется в глобальную область видимости импорта таблицы стилей. Это позволяет библиотеке контролировать, какие конкретные имена она экспортирует, даже для пользователей, которые используют@import
, а не@use
.
Чтобы позволить библиотекам поддерживать их существующий @import
-ориентированный API с явным пространством имен, где необходимо, в это предложение также добавлена поддержка файлов, которые видны только @import
, но не @use
. Они пишутся как "file.import.scss"
и импортируются, когда пользователь пишет @import "file"
.
Автоматическая миграция
Одновременно с запуском новой модульной системы мы запускаем новый автоматизированный Sass-мигратор. Этот инструмент позволяет легко перенести большинство таблиц стилей для автоматического использования новой системы модулей. Следуйте инструкциям на сайте Sass, чтобы установить его, а затем запустите его в своем приложении:
$ sass-migrator module --migrate-deps <path/to/style.scss>
Флаг --migrate-deps
говорит мигратору перенести не только передаваемый вами файл, но и все, что этот файл импортирует. Мигратор автоматически возьмет файлы, импортированные с помощью синтаксиса Webpack node_modules
, но вы также можете передать явные пути загрузки с флагом --load-paths
.
Если вы хотите, чтобы мигратор сообщал вам, какие изменения он будет вносить, не внося их на самом деле, передайте оба флага — --dry-run
и — --verbose
, чтобы он просто показывал изменения, которые он будет вносить, не сохраняя их на диск.
Миграция библиотеки
Если вы хотите перенести Sass библиотеку, которую пользователи должны загружать и использовать, запустите:
$ sass-migrator module --migrate-deps --forward=all <path/to/index.scss>
Флаг --forward
говорит мигратору добавить правила @forward
, чтобы пользователи могли по-прежнему загружать все миксины, переменные и функции, определенные вашей библиотекой с единственным @use
.
Если вы добавиляли пространство имен вручную в свою библиотеку, то чтобы избежать конфликтов, передайте флаг --remove-prefix
и мигратор удалит его за вас. Вы даже можете выбрать переадресацию только тех «членов», которые изначально имели этот префикс, передав --forward=prefixed
.
Формирование вопрсов
Инструмент миграции совершенно новый, так что он до сих пор может иметь некоторые неровные края. Если вы столкнетесь с проблемами, пожалуйста не стесняйтесь создавать новые ишью в GitHub!
Попробуйте уже сейчас!
Модульная система доступна как часть Dart Sass 1.23.0. Вы можете установить его прямо сейчас написав:
$ npm install -g sass
Как альтернативу, посмотрите страницу инсталяции со всеми возможными вариантами установки.
Планы на будущее
Команда Sass хочет выделить больше времени, когда @use
и @import
будут сосуществовать вместе, чтобы помочь экосистеме плавно перейти на новую. Однако отказ от @import
является конечной целью для простоты, производительности и совместимости с CSS. Поэтому мы планируем постепенно отказаться от поддержки @import
по следующему расписанию:
- Через год после того, как Dart Sass и LibSass запустят поддержку для модульной системы, или через два года после того, как Dart Sass запустит поддержку для модульной системы, в зависимости от того, что наступит раньше (не позднее 1 октября 2021 года), мы будем отказываться от
@import
, считать нежелательным для использования, а также вызовы функций глобального ядра библиотеки, которые можно выполнять через модули. - Через год после того, как этот отказ вступит в силу (не позднее 1 октября 2022 года), мы полностью откажемся от поддержки
@import
, а также большинства глобальных функций. Это потребует выпуска мажорной версии для всех реализаций.
Это означает, что будет по крайней мере два полных года, когда @import
и @use
будут использоваться одновременно, и, вероятно даже ближе к трем годам на практике.
Перевел: Я