Olá Habr! Apresento a você a tradução do artigo
“Introducing Sass Modules”, de Miriam Suzanne.
Recentemente, um recurso apareceu no Sass que você conhece em outros idiomas: um
sistema modular . Este é um grande passo em frente para o
@import
, uma das funções mais usadas no Sass. Apesar de a diretiva
@import
existente permitir conectar pacotes de terceiros e separar seus estilos em elementos suportados, ela ainda possui várias limitações
:
@import
também existe em CSS, e qualquer diferença em seu comportamento pode ser confusa.- Se você
@import
várias vezes para um arquivo, isso pode diminuir a compilação, causar conflitos de redefinição e obter código duplicado na saída. - Tudo está no escopo global, incluindo pacotes de terceiros - é assim que minha função de
color
pode substituir sua função de color
existente ou vice-versa. - Quando você usa uma função como
color
, é impossível saber exatamente onde ela está definida. Que @import
conectou?
Os autores dos pacotes Sass (como eu) tentaram contornar os problemas do espaço para nome definindo manualmente prefixos para variáveis e funções - mas os módulos Sass são uma solução muito mais poderosa. Em resumo,
@import
está
@import
substituído por
@forward
e
@forward
mais explícitas. Nos próximos anos, o
@import
em Sass será preterido e removido. Você ainda pode usar
CSS Import
's , mas eles não serão compilados pelo Sass. Mas não se preocupe, existe
uma ferramenta de migração que ajudará você a atualizar.
Importar arquivos usando @use
@use 'buttons';
O novo
@use
é semelhante ao
@import
, mas possui algumas diferenças notáveis:
- O arquivo é importado uma vez, não importa quantas vezes você use
@use
no projeto. - Variáveis, mixins e funções (chamadas de "membros" no Sass) que começam com um sublinhado (
_
) ou hífen ( -
) são consideradas privadas e não são importadas. - Os membros do arquivo conectado via
@use
(no nosso caso buttons.scss
) são acessíveis apenas localmente e não são transferidos para importação subsequente. - Da mesma forma,
@extends
será aplicado apenas a montante; isto é, a extensão se aplica apenas aos estilos importados e não aos estilos importados. - Todos os membros importados têm seu próprio espaço para nome por padrão.
Quando anexamos o arquivo via
@use
, o Sass gera automaticamente um espaço para nome com base no nome do arquivo.
@use 'buttons'; @use 'forms';
Agora, temos acesso aos membros dos arquivos
buttons.scss
e
forms.scss
, mas esse acesso não é transferido entre as importações:
forms.scss
ainda não tem acesso às variáveis definidas em
buttons.scss
. Como as entidades importadas têm um espaço para nome, devemos usar a nova sintaxe delimitada por pontos para acessá-las:
$btn-color: buttons.$color; $form-border: forms.$input-border; $btn-background: buttons.background(); $form-border: forms.border(); @include buttons.submit(); @include forms.input();
Podemos alterar ou remover o espaço para nome padrão adicionando
as <name>
à importação.
@use 'buttons' as *; @use 'forms' as 'f'; $btn-color: $color; $form-border: f.$input-border;
Usar
as *
adiciona o módulo ao espaço para nome raiz, portanto, o prefixo não é necessário, mas seus membros ainda são limitados localmente pelo documento atual.
Importar módulos incorporados Sass
Os recursos internos do Sass também foram transferidos para um sistema modular, para que tenhamos controle total sobre o espaço para nome global. Existem vários módulos
math
-
math
,
color
,
string
,
list
,
map
,
selector
e
meta
- que devem ser importados explicitamente no arquivo antes do uso.
@use 'sass:math'; $half: math.percentage(1/2);
Os módulos incorporados também podem ser importados para o espaço global:
@use 'sass:math' as *; $half: percentage(1/2);
Funções internas que já possuem nomes de prefixo, como
map-get
ou
str-index
, podem ser usadas sem duplicar este prefixo:
@use 'sass:map'; @use 'sass:string'; $map-get: map.get(('key': 'value'), 'key'); $str-index: string.index('string', 'i');
Você pode encontrar uma lista completa dos módulos internos, funções e alterações de nome na
especificação do módulo Sass .
Recursos principais novos e alterados
Como um benefício adicional, isso significa que o Sass pode adicionar novos mixins e funções internos com segurança, sem causar conflitos de nome. O exemplo mais surpreendente é o
load-css
sass:meta
do módulo
sass:meta
. Funciona de maneira semelhante a
@use
, mas retorna apenas o CSS gerado e funciona dinamicamente em qualquer lugar do seu código:
@use 'sass:meta'; $theme-name: 'dark'; [data-theme='#{$theme-name}'] { @include meta.load-css($theme-name); }
O primeiro argumento é a URL do módulo (como em
@use
), mas pode ser alterada dinamicamente usando uma variável, mesmo usando interpolação, por exemplo,
theme-#{$name}
. O segundo argumento (opcional) usa uma estrutura de
map
com a configuração:
@include meta.load-css( 'theme/dark', $with: ('base-color': rebeccapurple) );
O argumento
$with
permite configurar qualquer variável no módulo carregado usando a estrutura do
map
, e essa variável deve atender às condições:
- Não é uma variável privada que começa com
_
ou -
- Marcado com a diretiva
!default
Default
$base-color: black !default; $_private: true !default; $config: false;
Observe que a tecla
'base-color'
define a variável
$base-color
.
Existem mais algumas funções novas no módulo
sass:meta
:
module-variables()
e
module-functions()
. Cada um deles retorna uma estrutura de
map
com nomes e valores de um módulo já importado. Eles usam um argumento correspondente ao espaço para nome do módulo:
@use 'forms'; $form-vars: module-variables('forms'); $form-functions: module-functions('forms');
Várias outras funções do
sass:meta
-
global-variable-exists()
,
function-exists()
,
mixin-exists()
e
get-function()
- receberão argumentos adicionais do
$module
que nos permitem verificar explicitamente cada namespace.
Ajustar e dimensionar cores
O módulo
sass:color
também possui algumas reservas interessantes sobre a resolução de alguns de nossos problemas antigos. Muitas das funções herdadas, como
lighten()
ou
adjust-hue()
não
adjust-hue()
mais recomendadas para uso em favor das funções explícitas
color.adjust()
e
color.scale()
:
$light-red: color.adjust(red, $lightness: 20%); $complement: color.adjust(red, $hue: 180deg);
Algumas dessas funções descontinuadas (por exemplo,
adjust-hue
) são redundantes e desnecessárias. Outros - como
lighten
,
darken
,
saturate
etc. - precisa de re-implementação para melhorar a lógica interna. As funções originais foram baseadas em
adjust()
, que usa matemática linear: adicionando
20%
à luminosidade atual do
red
no nosso exemplo acima. Na maioria dos casos, queremos alterar (
scale()
) a cor em uma determinada porcentagem em relação ao valor atual:
$light-red: color.scale(red, $lightness: 20%);
Após serem completamente reprovadas e removidas, essas funções eventualmente reaparecerão em
sass:color
com um novo comportamento baseado em
color.scale()
, não
color.adjust()
. Isso acontecerá gradualmente para evitar problemas repentinos de compatibilidade com versões anteriores. Enquanto isso, recomendo verificar manualmente seu código para ver onde
color.scale()
pode ser mais útil.
Configurar bibliotecas importadas
Bibliotecas de terceiros ou reutilizáveis geralmente vêm com variáveis com alguns valores padrão que você pode substituir. Fizemos isso com variáveis antes da importação:
$color: blue !default; $color: red; @import 'buttons';
Como ao usar módulos, não há mais acesso a variáveis locais, precisamos de uma nova maneira de definir valores. Podemos fazer isso passando as configurações via
map
para
@use
:
@use 'buttons' with ( $color: red, $style: 'flat', );
Isso é semelhante ao argumento
$with
em
load-css()
, mas em vez de usar nomes de variáveis como chaves, usamos as próprias variáveis com o símbolo
$
.
Eu gosto de quão explícita a configuração se tornou, mas há uma regra que me confundiu várias vezes: um
módulo só pode ser configurado uma vez no primeiro uso . A ordem de conexão sempre foi importante para o Sass, mesmo com o
@import
, mas esses problemas passaram despercebidos. Agora temos um erro claro, e isso é bom e um pouco inesperado. Certifique-se de conectar as bibliotecas via
@use
e configurá-las no ponto de entrada de arquivo (o documento central que importa todos os outros arquivos) para que essas configurações sejam compiladas antes de outras conexões de biblioteca via
@use
.
Não é possível (no momento) “unir” as configurações, mantendo-as editáveis, mas você pode agrupar o módulo configurado e transferi-lo como um novo módulo.
Transferindo arquivos com @forward
Nem sempre precisamos usar o arquivo e nos referir a seus membros. Às vezes, queremos apenas repassá-lo para importações subsequentes. Suponha que temos vários arquivos associados a formulários e queremos conectá-los todos juntos como um espaço para nome. Podemos fazer isso com o
@forward
:
@forward 'input'; @forward 'textarea'; @forward 'select'; @forward 'buttons';
Os membros desses arquivos encaminhados não estão disponíveis no documento atual e nenhum espaço para nome é criado, mas essas variáveis, funções e mixins estarão disponíveis quando outro arquivo os conectar via
@use
ou
@use
coleção inteira através do
@forward
. Se os arquivos individuais enviados contiverem CSS real, eles também serão transmitidos sem gerá-lo diretamente até que o próprio pacote seja usado. Nesta fase, tudo isso será considerado como um módulo com um espaço para nome:
@use 'forms';
Nota : Se você pedir ao Sass para anexar uma pasta, ele procurará o arquivo de
index
ou
_index
nela.
Por padrão, todos os membros públicos serão encaminhados junto com o módulo. Mas podemos ser mais seletivos usando as condições
show
and
hide
e especificando membros específicos que queremos adicionar ou excluir.
@forward 'input' show border, $border-color; @forward 'buttons' hide gradient;
Nota : quando funções e mixins têm um nome comum, elas são adicionadas e ocultas também.
Para esclarecer as fontes ou evitar conflitos de nomes de módulos encaminhados, podemos adicionar prefixos aos membros do arquivo conectado usando
as
:
@forward 'input' as input-*; @forward 'buttons' as btn-*; @use 'forms'; @include forms.input-background(); @include forms.btn-background();
E, se precisarmos, sempre podemos usar via
@use
e
@forward
o mesmo módulo por
@forward
, adicionando as duas regras:
@forward 'forms'; @use 'forms';
Isso é especialmente útil se você deseja pré-configurar a biblioteca ou adicionar ferramentas adicionais antes de transferi-la para outros arquivos. Isso pode ajudar a simplificar os caminhos de conexão:
@use 'accoutrement/sass/tools' with ( $font-path: '../fonts/', ); @forward 'accoutrement/sass/tools'; @use 'tools';
@use
e
@forward
devem ser declarados na raiz do documento (não aninhada) e no início do arquivo. Somente
@charset
e definições de variáveis simples podem aparecer antes das diretivas de importação.
Transição para um sistema modular
Para testar a nova sintaxe, criei uma nova biblioteca Sass de código aberto (
Cascading Color Systems ) e um
novo site para o meu grupo - ambos ainda em desenvolvimento. Eu precisava entender os módulos do ponto de vista do autor da biblioteca e do ponto de vista do desenvolvedor do site. Vamos começar com a experiência do "usuário final" ao escrever estilos de sites usando a sintaxe do módulo ...
Estilos de suporte e escrita
O uso dos módulos no site foi agradável. A nova sintaxe suporta a arquitetura de código que eu já uso. Todas as minhas importações de configurações e ferramentas globais estão no mesmo diretório (eu chamo de
config
) com um arquivo de índice que transfere tudo o que eu preciso:
@forward 'tools'; @forward 'fonts'; @forward 'scale'; @forward 'colors';
Ao desenvolver outras partes do site, posso importar essas ferramentas e configurações sempre que precisar:
@use '../config'; .page-title { @include config.font-family('header'); }
Até funciona junto com minhas bibliotecas existentes, como
Accoutrement e
Herman , que ainda usam a antiga sintaxe
@import
. Como a regra
@import
não será substituída em todos os lugares ao mesmo tempo, os desenvolvedores do Sass deram algum tempo para a transição. Os módulos estão disponíveis agora, mas o
@import
não
@import
mais um ou dois anos - e será removido do idioma apenas um ano depois. Ao mesmo tempo, os dois sistemas funcionarão juntos de qualquer maneira:
- Se executarmos
@import
para um arquivo que contenha a nova sintaxe @use/@forward
, apenas membros públicos serão importados sem um espaço para nome. - Se executarmos
@use
ou @forward
para um arquivo que contenha a sintaxe @import
antiga, obteremos acesso a todas as importações aninhadas como um único espaço para nome.
Isso significa que você pode começar a usar imediatamente a nova sintaxe do módulo, sem aguardar o lançamento de uma nova versão de suas bibliotecas favoritas: e posso gastar algum tempo atualizando todas as minhas bibliotecas!
Ferramenta de migração
A atualização não levará muito tempo se usarmos a ferramenta de migração criada por Jennifer Thakar. Pode ser instalado usando NPM, Chocolatey ou Homebrew:
npm install -g sass-migrator choco install sass-migrator brew install sass/sass/migrator
Esta não é uma ferramenta única para migrar para módulos. Agora que o Sass está de volta ao desenvolvimento ativo (veja abaixo), a ferramenta de migração também receberá atualizações regulares para ajudar a portar cada novo recurso. É uma boa ideia instalar essa ferramenta globalmente e salvá-la para uso futuro.
O migrador pode ser iniciado a partir da linha de comando e, esperançosamente, será adicionado a aplicativos de terceiros, como o CodeKit e o Scout. Aponte-o para um único arquivo Sass, por exemplo
style.scss
e diga a ele quais migrações aplicar. No momento, há apenas uma migração chamada
module
:
Por padrão, o migrador atualiza apenas um arquivo, mas na maioria dos casos, queremos atualizar o arquivo principal e todas as suas dependências: quaisquer elementos conectados via
@import
,
@forward
ou
@use
. Podemos fazer isso especificando cada arquivo individualmente ou simplesmente adicionando o
--migrate-deps
.
sass-migrator --migrate-deps module style.scss
Para uma execução de teste, podemos adicionar
--dry-run --verbose
(ou no formato abreviado
-nv
) e ver os resultados sem alterar os arquivos de origem. Há várias outras opções que podemos usar para configurar a migração - há ainda uma que foi projetada especificamente para ajudar os autores da biblioteca a excluir antigos espaços para nome criados manualmente - mas não descreverei todos eles aqui.
A ferramenta de migração está totalmente documentada no
site da Sass .
Atualizando bibliotecas publicadas
Encontrei vários problemas no lado da biblioteca, em particular, quando tentei disponibilizar as configurações do usuário para vários arquivos e encontrar uma solução para as configurações "em cadeia" ausentes. Os erros relacionados a pedidos podem ser difíceis de depurar, mas os resultados valem o esforço, e acho que veremos algumas correções adicionais em breve. Ainda preciso experimentar a ferramenta de migração em pacotes complexos e talvez escrever um artigo adicional para os autores da biblioteca.
O importante a saber agora é que Sass nos forneceu proteção durante a transição. Não apenas as importações e os módulos antigos podem trabalhar juntos, como também podemos criar arquivos “
somente importação ” para fornecer um trabalho mais conveniente aos usuários que ainda conectam nossas bibliotecas via
@import
. Na maioria dos casos, essa será uma versão alternativa do arquivo do pacote principal e você deseja que eles estejam próximos:
<name>.scss
para usuários do módulo e
<name>.import.scss
para usuários antigos. Sempre que o usuário chama
@import <name>
, ele carrega a
.import
arquivo:
@use 'forms'; @import 'forms';
Isso é especialmente útil para adicionar prefixos para desenvolvedores que não usam módulos:
@forward 'forms' as forms-*;
Atualização Sass
Você deve se lembrar que, há vários anos, o Sass congelou a adição de novas funções, para que suas várias implementações (LibSass, Node Sass, Dart Sass) acompanhem a implementação original do Ruby, a fim de
abandoná-la completamente . O congelamento terminou no ano passado com vários novos recursos,
discussões e desenvolvimento ativos no GitHub - mas não tão solenemente. Se você perdeu esses lançamentos, pode ler o
blog Sass :
Atualmente, o Dart Sass é uma implementação canônica e geralmente é a primeira a introduzir novos recursos. Eu recomendo mudar para ele, se você deseja receber as últimas novidades. Você pode
instalar o Dart Sass usando NPM, Chocolatey ou Homebrew. Também funciona muito bem com
gulp-sass .
Como o CSS (começando com CSS3), não há mais um número de versão para novos lançamentos. Todas as implementações do Sass funcionam com a mesma especificação, mas cada uma delas possui um cronograma e numeração de versão exclusivos, que são refletidos nas informações de suporte em
uma bela e nova documentação projetada por
Jina .

Os módulos Sass estão disponíveis a partir de
1 de outubro de 2019 no
Dart Sass 1.23.0 .