Introdução aos módulos Sass

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'; /*    `buttons`*/ @use 'forms'; /*    `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:

 /* : <namespace>.$variable */ $btn-color: buttons.$color; $form-border: forms.$input-border; /* : <namespace>.function() */ $btn-background: buttons.background(); $form-border: forms.border(); /* : @include <namespace>.mixin() */ @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; /* buttons.$color    */ $form-border: f.$input-border; /* forms.$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:

 /*   $base-color  'theme/dark'   */ @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

 /* theme/_dark.scss */ $base-color: black !default; /*    */ $_private: true !default; /*        */ $config: false; /*    ,      !default */ 

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'); /* ( button-color: blue, input-border: thin, ) */ $form-functions: module-functions('forms'); /* ( background: get-function('background'), border: get-function('border'), ) */ 

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() :

 /*  lighten(red, 20%) */ $light-red: color.adjust(red, $lightness: 20%); /*  adjust-hue(red, 180deg) */ $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:

 /*        20,   0.2,     */ $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:

 /* _buttons.scss */ $color: blue !default; /* old.scss */ $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 :

 /* forms/_index.scss */ @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:

 /* styles.scss */ @use 'forms'; /*        `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.

 /*    `border()`   `$border-color`   `input` */ @forward 'input' show border, $border-color; /*     `buttons`    `gradient()` */ @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 :

 /* forms/_index.scss */ /* @forward "<url>" as <prefix>-*; */ /* ,      `background()` */ @forward 'input' as input-*; @forward 'buttons' as btn-*; /* style.scss */ @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:

 /* _tools.scss */ /*        */ @use 'accoutrement/sass/tools' with ( $font-path: '../fonts/', ); /*    */ @forward 'accoutrement/sass/tools'; /* -  ... */ /* _anywhere-else.scss */ /*      */ @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:

 /* config/_index.scss */ @forward 'tools'; @forward 'fonts'; @forward 'scale'; @forward 'colors'; 

Ao desenvolver outras partes do site, posso importar essas ferramentas e configurações sempre que precisar:

 /* layout/_banner.scss */ @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 :

 # sass-migrator <migration> <entrypoint.scss...> sass-migrator module style.scss 

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:

 /*  `_forms.scss` */ @use 'forms'; /*  `_forms.import.scss` */ @import 'forms'; 


Isso é especialmente útil para adicionar prefixos para desenvolvedores que não usam módulos:

 /* _forms.import.scss */ /*       */ @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 .

imagem

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

Source: https://habr.com/ru/post/pt471924/


All Articles