Aguarde...

19 de outubro de 2019

Introdução aos módulos Sass

Introdução aos módulos Sass

O Sass acaba de lançar um novo recurso importante que você pode reconhecer de outros idiomas: um sistema de módulos . Este é um grande passo à frente @import. um dos recursos Sass mais usados. Embora a @importregra atual permita que você obtenha pacotes de terceiros e divida seu Sass em “parciais” gerenciáveis, ela tem algumas limitações:

  • @import também é um recurso de CSS, e as diferenças podem ser confusas
  • Se você @importusar o mesmo arquivo várias vezes, ele poderá desacelerar a compilação, causar conflitos de substituição e gerar saída duplicada.
  • Tudo está no espaço de nomes global, incluindo pacotes de terceiros – portanto, minha color()função pode substituir a sua color()função existente ou vice-versa.
  • Quando você usa uma função como color(). é impossível saber exatamente onde foi definido. De @importonde vem?

Os autores do pacote Sass (como eu) tentaram solucionar os problemas do espaço de nome prefixando manualmente nossas variáveis ​​e funções – mas os módulos Sass são uma solução muito mais poderosa. Em resumo, @importestá sendo substituído por mais explícitas @use@forwardregras. Nos próximos anos, o Sass @importserá preterido e depois removido. Você ainda pode usar importações de CSS , mas elas não serão compiladas pelo Sass. Não se preocupe, há uma ferramenta de migração para ajudá-lo a atualizar!

# Importar arquivos com @use

@use 'buttons';

O novo @useé semelhante a @import. mas tem algumas diferenças notáveis:

  • O arquivo é importado apenas uma vez, não importa quantas vezes você @useo faça em um projeto.
  • Variáveis, mixins e funções (o que Sass chama de “membros”) que começam com um sublinhado ( _) ou hífen ( -) são considerados particulares e não importados.
  • Os membros do arquivo usado ( buttons.scssneste caso) são disponibilizados apenas localmente, mas não são repassados ​​para futuras importações.
  • Da mesma forma, @extendsapenas aplicará a corrente; estendendo seletores em arquivos importados, mas não estendendo arquivos que importam este.
  • Todos os membros importados têm espaço para nome por padrão .

Quando criamos @useum arquivo, o Sass gera automaticamente um espaço para nome com base no nome do arquivo:

@use 'buttons'; // creates a `buttons` namespace
@use 'forms'; // creates a `forms` namespace

Agora temos acesso a membros de ambos buttons.scssforms.scss– mas esse acesso não é transferido entre as importações: forms.scssainda não tem acesso às variáveis ​​definidas em buttons.scss. Como os recursos importados estão no namespace, precisamos usar uma nova sintaxe dividida em períodos para acessá-los:

// variables: <namespace>.$variable
$btn-color: buttons.$color;
$form-border: forms.$input-border;

// functions: <namespace>.function()
$btn-background: buttons.background();
$form-border: forms.border();

// mixins: @include <namespace>.mixin()
@include buttons.submit();
@include forms.input();

Podemos alterar ou remover o espaço as <name>para nome padrão adicionando à importação:

@use 'buttons' as *; // the star removes any namespace
@use 'forms' as 'f';

$btn-color: $color; // buttons.$color without a namespace
$form-border: f.$input-border; // forms.$input-border with a custom namespace

O uso as *adiciona um módulo ao espaço para nome raiz, portanto, nenhum prefixo é necessário, mas esses membros ainda têm o escopo local do documento atual.

# Importar módulos Sass internos

Os recursos internos do Sass também foram transferidos para o sistema de módulos, portanto, temos controle total sobre o espaço para nome global. Existem vários módulos embutidos – mathcolorstringlistmapselector, e meta– que têm de ser importados explicitamente em um arquivo antes de serem usados:

@use 'sass:math';
$half: math.percentage(1/2);

Os módulos Sass também podem ser importados para o espaço de nomes global:

@use 'sass:math' as *;
$half: percentage(1/2);

Funções internas que já tinham nomes prefixados, como map-getou str-index. pode ser usado sem duplicar esse 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 de módulos internos, funções e alterações de nome na especificação do módulo Sass .

# Principais e novos recursos alterados

Como um benefício colateral, isso significa que o Sass pode adicionar novos mixins e funções internos com segurança, sem causar conflitos de nome. O exemplo mais emocionante deste lançamento é um sass:metamixin chamado load-css(). Isso funciona de maneira semelhante, @usemas retorna apenas a saída CSS gerada e pode ser usado dinamicamente em qualquer lugar do nosso código:

@use 'sass:meta';
$theme-name: 'dark';

[data-theme=‘#{$theme-name}’]

{ @include meta.load-css($theme-name); }

O primeiro argumento é um URL de módulo (como @use), mas pode ser alterado dinamicamente por variáveis ​​e até incluir interpolação, como theme-#{$name}. O segundo argumento (opcional) aceita um mapa de valores de configuração:

// Configure the $base-color variable in 'theme/dark' before loading
@include meta.load-css(
  'theme/dark', 
  $with: ('base-color': rebeccapurple)
);

$withargumento aceita chaves de configuração e valores para qualquer variável no módulo carregado, se ambos:

  • Uma variável global que não começa com _ou -(agora usada para significar privacidade)
  • Marcado como um !defaultvalor, a ser configurado
// theme/_dark.scss
$base-color: black !default; // available for configuration
$_private: true !default; // not available because private
$config: false; // not available because not marked as a !default

Observe que a 'base-color'chave definirá a $base-colorvariável.

Existem mais duas sass:metafunções novas: module-variables()module-functions(). Cada um retorna um mapa de nomes e valores de membros de um módulo já importado. Eles aceitam um único argumento que corresponde ao namespace 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 sass:metafunções – global-variable-exists()function-exists()mixin-exists(), e get-function()– terá adicionais $moduleargumentos, o que nos permite inspecionar cada namespace explicitamente.

Ajustando e dimensionando cores

sass:colormódulo também possui algumas advertências interessantes, à medida que tentamos nos afastar de alguns problemas herdados. Muitos dos atalhos herdados gostam lighten(). ou adjust-hue()estão obsoletas no momento em favor de funções color.adjust()e explícitas color.scale():

// previously lighten(red, 20%)
$light-red: color.adjust(red, $lightness: 20%);

// previously adjust-hue(red, 180deg)
$complement: color.adjust(red, $hue: 180deg);

Algumas dessas funções antigas (como adjust-hue) são redundantes e desnecessárias. Outros – como lightendarkensaturate. e assim por diante – precisam ser reconstruídos com melhor lógica interna. As funções originais foram baseadas adjust(). que usa matemática linear: aumentando 20%a leveza atual de rednosso exemplo acima. Na maioria dos casos, na verdade queremos scale()a claridade em porcentagem, em relação ao valor atual:

// 20% of the distance to white, rather than current-lightness + 20
$light-red: color.scale(red, $lightness: 20%);

Uma vez totalmente obsoletas e removidas, essas funções de atalho acabarão reaparecendo sass:colorcom um novo comportamento baseado em color.scale()e não color.adjust(). Isso está acontecendo em etapas para evitar mudanças repentinas e invertidas. Enquanto isso, recomendo verificar manualmente seu código para ver onde color.scale()pode funcionar melhor para você.

# Configurar bibliotecas importadas

Bibliotecas de terceiros ou reutilizáveis ​​geralmente vêm com variáveis ​​de configuração global padrão para você substituir. Costumávamos fazer isso com variáveis ​​antes de uma importação:

// _buttons.scss
$color: blue !default;

// old.scss
$color: red;
@import 'buttons';

Como os módulos usados ​​não têm mais acesso às variáveis ​​locais, precisamos de uma nova maneira de definir esses padrões. Podemos fazer isso adicionando um mapa de configuração a @use:

@use 'buttons' with (
  $color: red,
  $style: 'flat',
);

Isso é semelhante ao $withargumento em load-css(). mas, em vez de usar nomes de variáveis ​​como chaves, usamos a própria variável, começando com $.

Eu amo o quão explícito isso torna a configuração, mas há uma regra que me tropeçou várias vezes: um módulo pode ser configurado apenas uma vez, na primeira vez em que é usado . A ordem de importação sempre foi importante para o Sass, mesmo com @import. mas esses problemas sempre falhavam silenciosamente. Agora temos um erro explícito, que é bom e às vezes surpreendente. Certifique-se de @useconfigurar as bibliotecas primeiro em qualquer arquivo de “ponto de entrada” (o documento central que importa todas as parciais), para que essas configurações sejam compiladas antes de outras @usebibliotecas.

É (atualmente) impossível “encadear” configurações, mantendo-as editáveis, mas você pode agrupar um módulo configurado junto com as extensões e transmiti-lo como um novo módulo.

# Passe arquivos com @forward

Nem sempre precisamos usar um arquivo e acessar seus membros. Às vezes, queremos apenas repassá-lo para futuras importações. Digamos que temos várias parciais relacionadas ao formulário e queremos importar todas elas juntas como um espaço para nome. Podemos fazer isso com @forward:

// forms/_index.scss
@forward 'input';
@forward 'textarea';
@forward 'select';
@forward 'buttons';

Os membros dos 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 desejar @useou @forwarda coleção inteira. Se as parciais encaminhadas contiverem CSS real, isso também será transmitido sem gerar saída até que o pacote seja usado. Nesse ponto, tudo será tratado como um único módulo com um único espaço para nome:

// styles.scss
@use 'forms'; // imports all of the forwarded members in the `forms` namespace

Nota: se você pedir ao Sass para importar um diretório, ele procurará um arquivo chamado indexou _index)

Por padrão, todos os membros públicos encaminham um módulo. Mas podemos ser mais seletivos ao adicionar showou hidecláusulas e nomear membros específicos para incluir ou excluir:

// forward only the 'input' border() mixin, and $border-color variable
@forward 'input' show border, $border-color;

// forward all 'buttons' members *except* the gradient() function
@forward 'buttons' hide gradient;

Nota: quando funções e mixins compartilham um nome, elas são mostradas e ocultadas.

Para esclarecer a fonte ou evitar conflitos de nomenclatura entre os módulos encaminhados, podemos usar ascomo prefixo os membros de uma parcial à medida que encaminhamos:

// forms/_index.scss
// @forward "<url>" as <prefix>-*;
// assume both modules include a background() mixin
@forward 'input' as input-*;
@forward 'buttons' as btn-*;

// style.scss
@use 'forms';
@include forms.input-background();
@include forms.btn-background();

E, se precisarmos, podemos sempre @use@forwardo mesmo módulo adicionando as duas regras:

@forward 'forms';
@use 'forms';

Isso é particularmente útil se você deseja agrupar uma biblioteca com configuração ou qualquer ferramenta adicional antes de passá-la para seus outros arquivos. Pode até ajudar a simplificar os caminhos de importação:

// _tools.scss
// only use the library once, with configuration
@use 'accoutrement/sass/tools' with (
  $font-path: '../fonts/',
);
// forward the configured library with this partial
@forward 'accoutrement/sass/tools';

// add any extensions here...


// _anywhere-else.scss
// import the wrapped-and-extended library, already configured
@use 'tools';

Ambos @use@forwarddevem ser declarados na raiz do documento (não aninhado) e no início do arquivo. Somente @charsetdefinições de variável simples e podem aparecer antes dos comandos de importação.

# Movendo para módulos

Para testar a nova sintaxe, construí uma nova biblioteca Sass de código aberto ( Cascading Color Systems ) e um novo site para minha banda – ambos ainda em construção. Eu queria entender os módulos como um autor da biblioteca e do site. Vamos começar com a experiência do “usuário final” de escrever estilos de sites com a sintaxe do módulo…

Manutenção e estilos de escrita

Usar módulos no site foi um prazer. A nova sintaxe incentiva uma arquitetura de código que eu já uso. Todas as minhas importações globais de configuração e ferramentas vivem em um único diretório (eu o chamo config), com um arquivo de índice que encaminha tudo o que preciso:

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

À medida que construo outros aspectos do site, posso importar essas ferramentas e configurações sempre que precisar:

// layout/_banner.scss
@use '../config';

.page-title {
  @include config.font-family('header');
}

Isso funciona mesmo com minhas bibliotecas Sass existentes, como Accoutrement e Herman , que ainda usam a @importsintaxe antiga . Como a @importregra não será substituída em qualquer lugar da noite para o dia, Sass construiu um período de transição. Os módulos estão disponíveis agora, mas @importnão serão preteridos por mais um ou dois anos – e somente serão removidos do idioma um ano depois. Enquanto isso, os dois sistemas trabalharão juntos em qualquer direção:

  • Se tivermos @importum arquivo que contenha a nova @use@forwardsintaxe, apenas os membros públicos serão importados, sem espaço para nome.
  • Se nós @useou @forwardum arquivo que contém @importsintaxe herdada , obtemos acesso a todas as importações aninhadas como um único espaço para nome.

Isso significa que você pode começar a usar a nova sintaxe do módulo imediatamente, sem esperar por uma nova versão de suas bibliotecas favoritas: e posso demorar um pouco para atualizar todas as minhas bibliotecas!

Ferramenta de migração

A atualização não deve demorar muito se usarmos a Ferramenta de Migração criada por Jennifer Thakar. Pode ser instalado com Node, Chocolatey ou Homebrew:

npm install -g sass-migrator
choco install sass-migrator
brew install sass/sass/migrator

Esta não é uma ferramenta de uso único 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 migrar cada novo recurso. É uma boa ideia instalar isso globalmente e mantê-lo disponível para uso futuro.

O migrador pode ser executado a partir da linha de comando e, com sorte, também será adicionado a aplicativos de terceiros como o CodeKit e o Scout. Aponte para um único arquivo Sass, como style.scss. e diga a que migração (s) aplicar. Neste ponto, 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 único arquivo, mas na maioria dos casos, desejamos atualizar o arquivo principal e todas as suas dependências : quaisquer parciais importados, encaminhados ou usados. Podemos fazer isso mencionando cada arquivo individualmente ou adicionando o --migrate-depssinalizador:

sass-migrator --migrate-deps module style.scss

Para uma execução de teste, podemos adicionar --dry-run --verbose(ou -nvabreviar) e ver os resultados sem alterar nenhum arquivo. Existem várias outras opções que podemos usar para personalizar a migração – mesmo uma especificamente para ajudar os autores de bibliotecas a remover namespaces manuais antigos – mas não abordarei todas elas aqui. A ferramenta de migração está totalmente documentada no site do Sass .

Atualizando bibliotecas publicadas

Encontrei alguns problemas no lado da biblioteca, tentando especificamente disponibilizar as configurações do usuário em vários arquivos e solucionar as configurações encadeadas ausentes. Os erros de pedidos podem ser difíceis de depurar, mas os resultados valem o esforço, e acho que veremos alguns patches adicionais em breve. Ainda tenho que experimentar a ferramenta de migração em pacotes complexos e, possivelmente, escrever uma postagem de acompanhamento para os autores da biblioteca.

O importante a saber agora é que Sass nos cobriu durante o período de transição. Não apenas as importações e os módulos podem trabalhar juntos, mas também podemos criar arquivos ” somente de importação ” para proporcionar uma melhor experiência aos usuários herdados que ainda estão em @importnossas bibliotecas. Na maioria dos casos, essa será uma versão alternativa do arquivo do pacote principal e você os desejará lado a lado: <name>.scsspara usuários do módulo e <name>.import.scsspara usuários herdados. Sempre que um usuário ligar @import <name>, ele carregará a .importversão do arquivo:

// load _forms.scss
@use 'forms';

// load _forms.input.scss
@import 'forms';

Isso é particularmente útil para adicionar prefixos para usuários que não são do módulo:

// _forms.import.scss
// Forward the main module, while adding a prefix
@forward "forms" as forms-*;
Postado em Blog
Escreva um comentário