Pavel Laptev
9 min readOct 13, 2019

--

Перевод статьи 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 будут использоваться одновременно, и, вероятно даже ближе к трем годам на практике.

Перевел: Я

--

--