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 
:
- @importtambém existe em CSS, e qualquer diferença em seu comportamento pode ser confusa.
- Se você @importvá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 colorpode substituir sua função decolorexistente ou vice-versa.
- Quando você usa uma função como color, é impossível saber exatamente onde ela está definida. Que@importconectou?
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 @useno 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 casobuttons.scss) são acessíveis apenas localmente e não são transferidos para importação subsequente.
- Da mesma forma, @extendsserá 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 !defaultDefault
  $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 @importpara um arquivo que contenha a nova sintaxe@use/@forward, apenas membros públicos serão importados sem um espaço para nome.
- Se executarmos @useou@forwardpara um arquivo que contenha a sintaxe@importantiga, 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 .