Memperkenalkan Modul Sass

Halo, Habr! Saya mempersembahkan untuk Anda terjemahan dari artikel “Introducing Sass Modules” oleh Miriam Suzanne.

Baru-baru ini, sebuah fitur muncul di Sass yang akrab bagi Anda dalam bahasa lain: sistem modular . Ini adalah langkah besar ke depan untuk @import , salah satu fungsi yang paling umum digunakan di Sass. Terlepas dari kenyataan bahwa arahan @import ada memungkinkan Anda untuk menghubungkan paket pihak ketiga dan memisahkan gaya Anda menjadi elemen yang didukung, masih ada beberapa keterbatasan :

  • @import juga ada di CSS, dan setiap perbedaan dalam perilakunya dapat membingungkan.
  • Jika Anda melakukan @import beberapa kali untuk satu file, ini dapat memperlambat kompilasi, menyebabkan konflik redefinisi, dan Anda mendapatkan kode duplikat di output.
  • Semuanya ada dalam lingkup global, termasuk paket pihak ketiga - ini adalah bagaimana fungsi color saya dapat mengesampingkan fungsi color ada atau sebaliknya.
  • Saat Anda menggunakan fungsi seperti color , tidak mungkin untuk mengetahui dengan tepat di mana ia didefinisikan. @import mana yang menghubungkannya?

Para penulis paket Sass (seperti saya) mencoba untuk mengatasi masalah namespace dengan secara manual mengatur awalan untuk variabel dan fungsi - tetapi modul Sass adalah solusi yang jauh lebih kuat. Singkatnya, @import digantikan oleh @forward dan @forward lebih eksplisit. Selama beberapa tahun ke depan, @import di Sass akan ditinggalkan dan kemudian dihapus. Anda masih dapat menggunakan CSS Import , tetapi mereka tidak akan dikompilasi oleh Sass. Tapi jangan khawatir, ada alat migrasi yang akan membantu Anda meningkatkan.

Impor file menggunakan @use


 @use 'buttons'; 

@use baru mirip dengan @import @use , tetapi memiliki beberapa perbedaan penting:

  • File diimpor sekali, tidak peduli berapa kali Anda menggunakan @use dalam proyek.
  • Variabel, mixin, dan fungsi (yang disebut "anggota" di Sass) dimulai dengan garis bawah ( _ ) atau tanda hubung ( - ) dianggap pribadi dan tidak diimpor.
  • Anggota dari file yang terhubung melalui @use (dalam kasus kami buttons.scss ) hanya dapat diakses secara lokal dan tidak ditransfer ke impor berikutnya.
  • Demikian pula, @extends hanya akan berlaku di hulu; yaitu, ekstensi hanya berlaku untuk gaya yang diimpor, dan bukan untuk gaya yang diimpor.
  • Semua anggota yang diimpor memiliki namespace mereka sendiri secara default.

Ketika kami melampirkan file melalui @use , Sass secara otomatis menghasilkan namespace berdasarkan nama file.

 @use 'buttons'; /*    `buttons`*/ @use 'forms'; /*    `forms`*/ 

Sekarang kita memiliki akses ke anggota file buttons.scss dan file forms.scss , tetapi akses ini tidak ditransfer antara impor: forms.scss masih tidak memiliki akses ke variabel yang ditentukan dalam buttons.scss . Karena entitas yang diimpor memiliki namespace, kita harus menggunakan sintaks pembatas-titik baru untuk mengaksesnya:

 /* : <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(); 

Kami dapat mengubah atau menghapus namespace default dengan menambahkan as <name> ke impor.

 @use 'buttons' as *; /*      */ @use 'forms' as 'f'; $btn-color: $color; /* buttons.$color    */ $form-border: f.$input-border; /* forms.$input-border    */ 

Menggunakan as * menambahkan modul ke root namespace, sehingga awalan tidak diperlukan, tetapi anggotanya masih dibatasi secara lokal oleh dokumen saat ini.

Impor Modul Tertanam Sass


Kemampuan internal di Sass juga telah dipindahkan ke sistem modular, jadi kami memiliki kontrol penuh atas namespace global. Ada beberapa modul math - math , color , string , list , map , selector , dan meta - yang harus diimpor ke file secara eksplisit sebelum digunakan.

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

Modul tertanam juga dapat diimpor ke ruang global:

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

Fungsi bawaan yang sudah memiliki nama awalan, seperti map-get atau str-index , dapat digunakan tanpa menduplikasi awalan ini:

 @use 'sass:map'; @use 'sass:string'; $map-get: map.get(('key': 'value'), 'key'); $str-index: string.index('string', 'i'); 

Anda dapat menemukan daftar lengkap modul built-in, fungsi dan perubahan nama dalam spesifikasi modul Sass .

Fitur inti baru dan berubah


Sebagai manfaat tambahan, ini berarti bahwa Sass dapat dengan aman menambahkan mixin dan fungsi internal baru tanpa menyebabkan konflik nama. Contoh yang paling menakjubkan adalah sass:meta load-css dari modul sass:meta . Ia bekerja mirip dengan @use , tetapi hanya mengembalikan CSS yang dihasilkan dan bekerja secara dinamis di mana saja dalam kode Anda:

 @use 'sass:meta'; $theme-name: 'dark'; [data-theme='#{$theme-name}'] { @include meta.load-css($theme-name); } 

Argumen pertama adalah URL modul (seperti dalam @use ), tetapi dapat diubah secara dinamis menggunakan variabel, bahkan menggunakan interpolasi, misalnya theme-#{$name} . Argumen kedua (opsional) mengambil struktur map dengan konfigurasi:

 /*   $base-color  'theme/dark'   */ @include meta.load-css( 'theme/dark', $with: ('base-color': rebeccapurple) ); 

Argumen $with memungkinkan Anda untuk mengonfigurasi variabel apa pun di modul yang dimuat menggunakan struktur map , dan variabel ini harus memenuhi ketentuan:

  • Ini bukan variabel pribadi yang dimulai dengan _ atau -
  • Ditandai dengan !default Arahan default

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

Perhatikan bahwa kunci 'base-color' menetapkan variabel $base-color .

Ada beberapa fungsi baru dari modul sass:meta : module-variables() dan module-functions() . Masing-masing mengembalikan struktur map dari nama dan nilai dari modul yang sudah diimpor. Mereka mengambil satu argumen yang sesuai dengan namespace modul:

 @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'), ) */ 

Beberapa fungsi lain dari sass:meta - global-variable-exists() , function-exists() , mixin-exists() , dan get-function() - akan menerima argumen $module tambahan yang memungkinkan kita memeriksa setiap namespace secara eksplisit.

Sesuaikan dan skala warna


Modul sass:color juga memiliki beberapa reservasi menarik tentang penyelesaian beberapa masalah lama kita. Banyak fungsi lawas seperti lighten() atau adjust-hue() tidak lagi direkomendasikan untuk digunakan dalam mendukung fungsi-fungsi eksplisit color.adjust() dan color.scale() :

 /*  lighten(red, 20%) */ $light-red: color.adjust(red, $lightness: 20%); /*  adjust-hue(red, 180deg) */ $complement: color.adjust(red, $hue: 180deg); 


Beberapa dari fungsi yang sudah usang ini (mis., adjust-hue ) adalah berlebihan dan tidak perlu. Lainnya - seperti lighten , darken , saturate , dll. - perlu implementasi ulang untuk meningkatkan logika internal. Fungsi asli didasarkan pada adjust() , yang menggunakan matematika linier: menambahkan 20% ke cahaya red dalam contoh kami di atas. Dalam kebanyakan kasus, kami ingin mengubah ( scale() ) warna dengan persentase tertentu relatif terhadap nilai saat ini:

 /*        20,   0.2,     */ $light-red: color.scale(red, $lightness: 20%); 

Setelah sepenuhnya ditinggalkan dan dihapus, fungsi-fungsi ini pada akhirnya akan muncul kembali dalam sass:color dengan perilaku baru berdasarkan color.scale() , bukan color.adjust() . Ini akan terjadi secara bertahap untuk menghindari masalah kompatibilitas mundur yang tiba-tiba. Sementara itu, saya sarankan secara manual memeriksa kode Anda untuk melihat di mana color.scale() mungkin lebih berguna.

Konfigurasikan Perpustakaan yang Diimpor


Pustaka pihak ketiga atau yang dapat digunakan kembali sering disertai dengan variabel dengan beberapa nilai default yang bisa Anda timpa. Kami melakukan ini dengan variabel sebelum mengimpor:

 /* _buttons.scss */ $color: blue !default; /* old.scss */ $color: red; @import 'buttons'; 

Karena ketika menggunakan modul tidak ada lagi akses ke variabel lokal, kita perlu cara baru untuk menetapkan nilai. Kita bisa melakukan ini dengan meneruskan pengaturan melalui map ke @use :

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

Ini mirip $with argumen $with di load-css() , tetapi alih-alih menggunakan nama variabel sebagai kunci, kami menggunakan variabel itu sendiri dengan simbol $ .

Saya suka bagaimana eksplisit pengaturan telah menjadi, tetapi ada satu aturan yang telah membingungkan saya beberapa kali: modul hanya dapat dikonfigurasikan sekali setelah digunakan pertama kali . Urutan koneksi selalu penting bagi Sass, bahkan dengan @import , tetapi masalah ini tidak diperhatikan. Sekarang kita mendapatkan kesalahan yang jelas, dan ini baik dan sedikit tidak terduga. Pastikan untuk menghubungkan pustaka melalui @use dan mengkonfigurasinya di titik entri file (dokumen pusat yang mengimpor semua file lain) sehingga pengaturan ini dikompilasi sebelum koneksi pustaka lainnya melalui @use .

Tidak mungkin (saat ini) untuk "mengikat" konfigurasi bersama-sama, menjaganya tetap dapat diedit, tetapi Anda dapat membungkus modul yang dikonfigurasi dan mentransfernya sebagai modul baru.

Mentransfer file dengan @forward


Kami tidak selalu perlu menggunakan file dan merujuk ke anggotanya. Terkadang kami hanya ingin meneruskannya ke impor berikutnya. Misalkan kita memiliki beberapa file yang terkait dengan formulir, dan kami ingin menghubungkan semuanya bersama sebagai satu namespace. Kita bisa melakukan ini dengan @forward :

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

Anggota file yang diteruskan tersebut tidak tersedia di dokumen saat ini dan tidak ada namespace yang dibuat, tetapi variabel, fungsi dan mixin ini akan tersedia ketika file lain menghubungkannya melalui @use atau @use seluruh koleksi melalui @forward . Jika file individual yang dikirim mengandung CSS yang sebenarnya, itu juga akan dikirim tanpa membuatnya secara langsung sampai paket itu sendiri digunakan. Pada tahap ini, semua ini akan dianggap sebagai satu modul dengan satu namespace:

 /* styles.scss */ @use 'forms'; /*        `forms` */ 

Catatan : Jika Anda meminta Sass untuk melampirkan folder, itu akan mencari file index atau _index di dalamnya.

Secara default, semua anggota publik akan diteruskan bersama dengan modul. Tetapi kita bisa lebih selektif dengan menggunakan kondisi show dan hide serta menentukan anggota tertentu yang ingin kita tambahkan atau kecualikan.

 /*    `border()`   `$border-color`   `input` */ @forward 'input' show border, $border-color; /*     `buttons`    `gradient()` */ @forward 'buttons' hide gradient; 

Catatan : ketika fungsi dan mixin memiliki nama yang sama, mereka ditambahkan dan disembunyikan juga bersamaan.

Untuk memperjelas sumber atau menghindari konflik nama modul yang diteruskan, kami dapat menambahkan awalan ke anggota file yang terhubung menggunakan 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(); 

Dan, jika perlu, kita selalu dapat menggunakan via @use dan @forward modul yang sama melalui @forward , menambahkan kedua aturan:

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

Ini sangat berguna jika Anda ingin melakukan pra-konfigurasi perpustakaan atau menambahkan alat tambahan sebelum mentransfernya ke file lain. Ini dapat membantu menyederhanakan jalur koneksi:

 /* _tools.scss */ /*        */ @use 'accoutrement/sass/tools' with ( $font-path: '../fonts/', ); /*    */ @forward 'accoutrement/sass/tools'; /* -  ... */ /* _anywhere-else.scss */ /*      */ @use 'tools'; 

Baik @use dan @forward harus dideklarasikan di root dokumen (tidak bersarang) dan di awal file. Hanya @charset dan definisi variabel sederhana yang dapat muncul sebelum mengimpor arahan.

Transisi ke sistem modular


Untuk menguji sintaks baru, saya membuat perpustakaan Sass open source baru ( Cascading Color Systems ) dan situs baru untuk grup saya - keduanya masih dalam pengembangan. Saya perlu memahami modul dari sudut pandang penulis perpustakaan dan dari sudut pandang pengembang situs. Mari kita mulai dengan pengalaman "pengguna akhir" dalam menulis gaya situs menggunakan sintaksis modul ...

Gaya dukungan dan penulisan


Menggunakan modul di situs itu menyenangkan. Sintaks baru mendukung arsitektur kode yang sudah saya gunakan. Semua impor pengaturan dan alat global saya ada di direktori yang sama (saya menyebutnya config ) dengan file indeks yang mentransfer semua yang saya butuhkan:

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

Dengan mengembangkan bagian lain dari situs ini, saya dapat mengimpor alat dan konfigurasi ini di mana pun saya membutuhkannya:

 /* layout/_banner.scss */ @use '../config'; .page-title { @include config.font-family('header'); } 

Ia bahkan bekerja bersama dengan pustaka saya yang ada, seperti Accoutrement dan Herman , yang masih menggunakan sintaks @import lama. Karena aturan @import tidak akan diganti di mana saja sekaligus, pengembang Sass telah memberikan waktu untuk transisi. Modul tersedia sekarang, tetapi @import tidak akan @import satu atau dua tahun lagi - dan akan dihapus dari bahasa hanya setahun setelah itu. Pada saat yang sama, kedua sistem akan bekerja bersama dengan cara apa pun:

  • Jika kita menjalankan @import untuk file yang berisi sintaks @use/@forward , hanya anggota publik yang akan diimpor tanpa namespace.
  • Jika kami menjalankan @use atau @forward untuk file yang berisi sintaks @import lama, kami mendapatkan akses ke semua impor bersarang sebagai ruang nama tunggal.

Ini berarti bahwa Anda dapat segera mulai menggunakan sintaks modul baru, tanpa menunggu rilis versi baru perpustakaan favorit Anda: dan saya dapat meluangkan waktu memperbarui semua perpustakaan saya!

Alat migrasi


Pembaruan tidak akan memakan waktu lama jika kami menggunakan alat migrasi yang dibuat oleh Jennifer Thakar. Itu dapat diinstal menggunakan NPM, Chocolatey atau Homebrew:

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

Ini bukan alat satu kali untuk bermigrasi ke modul. Sekarang setelah Sass kembali dalam pengembangan aktif (lihat di bawah), alat migrasi juga akan menerima pembaruan rutin untuk membantu port setiap fitur baru. Merupakan ide bagus untuk menginstal alat ini secara global, dan menyimpannya untuk penggunaan di masa mendatang.

Migrator dapat diluncurkan dari baris perintah dan, mudah-mudahan, akan ditambahkan ke aplikasi pihak ketiga seperti CodeKit dan Scout. Arahkan dia ke file Sass tunggal, misalnya style.scss dan beri tahu migrasi yang akan diterapkan. Saat ini, hanya ada satu migrasi yang disebut module :

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

Secara default, migrator hanya memperbarui satu file, tetapi dalam kebanyakan kasus kami ingin memperbarui file utama dan semua dependensinya: elemen apa pun yang terhubung melalui @forward , @forward atau @use . Kita dapat melakukan ini dengan menentukan masing-masing file secara terpisah atau hanya dengan menambahkan flag --migrate-deps .

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

Untuk uji coba, kita bisa menambahkan --dry-run --verbose (atau dalam bentuk disingkat -nv ) dan melihat hasilnya tanpa mengubah file sumber. Ada sejumlah opsi lain yang dapat kita gunakan untuk mengonfigurasi migrasi - bahkan ada satu yang secara khusus dirancang untuk membantu penulis perpustakaan menghapus ruang nama yang dibuat secara manual - tapi saya tidak akan menjelaskan semuanya di sini. Alat migrasi sepenuhnya didokumentasikan di situs web Sass .

Memperbarui Perpustakaan yang Diterbitkan


Saya mengalami beberapa masalah di sisi perpustakaan, khususnya, ketika saya mencoba membuat konfigurasi pengguna tersedia untuk beberapa file dan menemukan solusi untuk konfigurasi "rantai" yang hilang. Kesalahan terkait pesanan mungkin sulit untuk di-debug, tetapi hasilnya sepadan dengan usaha, dan saya pikir kita akan segera melihat beberapa perbaikan tambahan. Saya masih perlu bereksperimen dengan alat migrasi pada paket yang kompleks, dan mungkin menulis artikel tambahan untuk penulis perpustakaan.

Yang penting untuk diketahui saat ini adalah bahwa Sass memberi kami perlindungan selama masa transisi. Tidak hanya impor dan modul lama dapat bekerja bersama, kita dapat membuat file " hanya impor " untuk memberikan pekerjaan yang lebih nyaman bagi pengguna yang masih menghubungkan perpustakaan kami melalui @import . Dalam kebanyakan kasus, ini akan menjadi versi alternatif dari file paket utama, dan Anda ingin mereka berada di dekat: <name>.scss untuk pengguna modul dan <name>.import.scss untuk pengguna lama. Setiap kali pengguna memanggil @import <name> , ia memuat .import file:

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


Ini sangat berguna untuk menambahkan awalan untuk pengembang yang tidak menggunakan modul:

 /* _forms.import.scss */ /*       */ @forward 'forms' as forms-*; 


Sass Update


Anda mungkin ingat bahwa beberapa tahun yang lalu Sass membekukan penambahan fungsi baru, sehingga berbagai implementasinya (LibSass, Node Sass, Dart Sass) mengejar ketinggalan dengan implementasi Ruby yang asli, agar benar - benar meninggalkannya . Pembekuan berakhir tahun lalu dengan beberapa fitur baru dan diskusi aktif dan pengembangan di GitHub - tetapi tidak begitu serius. Jika Anda melewatkan rilis ini, maka Anda dapat membaca blog Sass :


Saat ini, Dart Sass adalah implementasi kanonik dan biasanya yang pertama memperkenalkan fitur baru. Saya sarankan beralih ke itu jika Anda ingin menerima semua yang terbaru. Anda dapat menginstal Dart Sass menggunakan NPM, Chocolatey atau Homebrew. Ini juga bekerja sangat baik dengan tegukan-sass .

Seperti CSS (dimulai dengan CSS3), tidak ada lagi nomor versi tunggal untuk rilis baru. Semua implementasi Sass bekerja dengan spesifikasi yang sama, tetapi masing-masing memiliki jadwal rilis dan penomoran yang unik, yang tercermin dalam informasi dukungan dalam dokumentasi baru yang indah yang dirancang oleh Jina .

gambar

Modul Sass tersedia mulai 1 Oktober 2019 di Dart Sass 1.23.0 .

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


All Articles