Z nieba leje się żar, co oznacza, że wkroczyliśmy w sezon ogórkowy. Frontendowy świat zdaje się jednak ignorować ten fakt, bo w minionym miesiącu dostaliśmy nową bibliotekę CSS-in-JS od twórców Chakra UI, prawdziwe if-else statement dla Angulara czy alternatywę dla Hotjar od Microsoftu.
Panda CSS – Universal, Type-Safe, CSS-in-JS
Sporo wody w Wiśle upłynęło od kiedy jakaś biblioteka CSS-in-JS narobiła tyle szumu co Panda CSS. Nowość spod rąk twórców Chakra UI (jednej z najpopularniejszych bibliotek komponentów dla Reacta) łączy w sobie to co najlepsze w rozwiązaniach takich jak Tailwind CSS, Stitches czy Emotion. Zanim przejdziemy jednak do omówienia konkretów, zastanówmy się chwilę po co nam tak naprawdę kolejna biblioteka CSS-in-JS?
Chakra UI do stylowania wykorzystuje popularną bibliotekę Emotion. Jej zastosowanie wiąże się jednak z dwoma istotnymi konsekwencjami. Po pierwsze, biblioteka ta żeby w ogóle zacząć działać potrzebuje wczytać po stronie klienta sporo kodu. Po drugie, biblioteki tej nie da się użyć w połączeniu z React Server Components – najświeższym dzieckiem zespołu Reacta, o którym wszyscy (łącznie z nami) trąbią na prawo i lewo. Te dwa czynniki z czasem zaczęły coraz bardziej uwierać zespołowi odpowiedzialnemu za rozwój Chakra UI i dlatego zdecydowali się oni stworzyć własną bibliotekę CSS-in-JS.
Na pierwszy rzut oka Panda CSS nie różni się zbytnio od Emotion. Diabeł tkwi jednak w szczegółach. Emotion generował unikalne nazwy klas dla każdego wywołania metody css()
. Panda CSS na etapie budowania aplikacji rozbija po kluczach obiekt przekazany do metody css()
i generuje klasy mocno przypominające te znane z Tailwinda. Dzięki temu, że nazwy klas generowane są na etapie budowania aplikacji, Panda CSS nie potrzebuje dodatkowego kodu JavaScript po stronie klienta i może agresywnie zoptymalizować ilość wysyłanych CSS-ów.
import { css } from '../styled-system/css'
function App() {
return (
//👇 Example usage of Panda CSS
<div className={css({
backgroundColor: 'gainsboro',
borderRadius: '9999px',
fontSize: '13px',
padding: '10px 15px'
})}>
<p>Hello World</p>
</div>
);
}
/* Below file represents CSS output sent to the client */
.bg_gainsboro {
background-color: gainsboro;
}
.rounded_9999px {
border-radius: 9999px;
}
.fs_13px {
font-size: 13px;
}
.p_10px_15px {
padding: 10px 15px;
}
Panda CSS to nie tylko zero runtime, ale też paczka ciekawych usprawnień. Zacznijmy od Patterns, czyli paczki „przydasiów” dzięki którym już nigdy nie będziecie musieli zastanawiać się jak wyśrodkować div’a czy jak dokładnie wygląda składnia flex’a.
import { center } from '../styled-system/patterns'
function App() {
return (
<div className={center({ bg: 'red.200' })}>
<Icon />
</div>
)
}
import { flex } from '../styled-system/patterns'
function App() {
return (
<div className={flex({ direction: 'row', align: 'center' })}>
<div>First</div>
<div>Second</div>
<div>Third</div>
</div>
)
}
Kolejna nowość, to „Recipies”, które mocno inspirowane są biblioteką Class Variance Authority. Dzięki nim, możemy definiować wiele różnych wariantów komponentów, a następnie komponować je ze sobą zachowując pełne bezpieczeństwo typów. Składnia na pierwszy rzut oka wydaje się trochę przekomplikowana, ale ustandaryzowany sposób na tworzenie wariantów, które są czytelne dla naszych klientów wydaje się tego warta.
import { cva } from '../styled-system/css'
const button = cva({
base: {
display: 'flex'
},
variants: {
visual: {
solid: { bg: 'red.200', color: 'white' },
outline: { borderWidth: '1px', borderColor: 'red.200' }
},
size: {
sm: { padding: '4', fontSize: '12px' },
lg: { padding: '8', fontSize: '24px' }
}
}
})
import { button } from './button'
const Button = () => {
return (
<button className={button({ visual: 'solid', size: 'lg' })}>
Click Me
</button>
)
}
Ostatnią nowością wartą wspomnienia są Design Tokens. Co ważne, jest to implementacja dość zaawansowana, gdyż mogą one bez problemu odnosić się do siebie nawzajem.
export default defineConfig({
theme: {
// 👇 Define your tokens here
tokens: {
colors: {
primary: { value: '#0FEE0F' },
secondary: { value: '#EE0F0F' }
},
fonts: {
body: { value: 'system-ui, sans-serif' }
}
}
}
})
import { css } from '../styled-system/css'
function App() {
return (
<p
className={css({
color: 'primary', // 👈 So you can later use them like this
fontFamily: 'body'
})}
>
Hello World
</p>
)
}
Źródła
Zainstaluj teraz i czytaj tylko dobre teksty!
Angular – Built-In Control Flow
W ostatnich miesiącach Angular rozwija się szybciej niż kiedykolwiek. Niespełna kilka tygodniu temu światło dzienne ujrzał Angular 16, a wraz z nim nowy reaktywny prymityw w postaci Signals. Teraz stojący za frameworkiem zespół zaprezentował kolejne RFC, tym razem dotyczące Control Flow. Jeśli wszystko pójdzie z planem, wyśle ono na emeryturę znane nam od dawna dyrektywy strukturalne.
Zaraz, zaraz? Co jest nie tak ze znanymi od dawna strukturalnymi dyrektywami? Jeśli nie wiadomo o co chodzi, to zapewne chodzi o zone.js
, a właściwie jego usunięcie. Dla przypomnienia, zone.js
to mała biblioteka będąca jednym z kamieni węgielnych Angulara. W uproszczeniu jest ona odpowiedzialna za przechwytywanie asynchronicznych wydarzeń w przeglądarce i informowaniu o nich Angulara, który następnie uruchamia mechanizm wykrywania zmian. Obecnie zespół z Google pracuje w pocie czoła, aby umożliwić deweloperom tworzenie aplikacji pozbawionych zone.js. Strukturalne dyrektywy są tak mocno związane z architekturą zone.js
, że zespół zdecydował, że najlepiej będzie zaimplementować coś zupełnie nowego i przy okazji nadrobić braki strukturalnych dyrektyw.
Nowa składnia mocno inspirowana jest Svelte i co ciekawe, jest ona w 100% zgodna ze standardem HTML. Warto zwrócić uwagę na to, że nowa składnia to nie tylko słodzik syntaktyczny, ale także realne usprawnienia dla deweloperów. If statement staje się wreszcie pełnoprawnym If-else statement (i nikt nie wmówi mi, że stare rozwiązanie oparte o template, było czytelne), switch statement podobnie jak w TypeScript będzie w stanie zawężać typy, a for-loop wymagać będzie parametru track
dzięki czemu ciężko będzie zaimplementować nie optymalną pętlę.
Currently (If Statement)
<div *ngIf="cond.expr(); else elseBlock">
Main case was true!
</div>
<ng-template #elseBlock>
<div *ngIf="other.expr(); else elseElseBlock">
Extra case was true!
</div>
<ng-template #elseElseBlock>
<div>False case!</div>
</ng-template>
</ng-template>
RFC (If Statement)
{#if cond.expr}
Main case was true!
{:else if other.expr}
Extra case was true!
{:else}
False case!
{/if}
Currently (Switch Statement)
<ng-container [ngSwitch]="cond.kind()">
<ng-container *ngSwitchCase="x">X case</ng-container>
<ng-container *ngSwitchCase="y">Y case</ng-container>
<ng-container *ngSwitchCase="z">Z case</ng-container>
<ng-container *ngSwitchDefault>No case matched</ng-container>
</ng-container>
RFC (Switch Statement)
{#switch cond.kind}
{:case x}
X case
{:case y}
Y case
{:case z}
Z case
{:default}
No case matched
{/switch}
Currently (For Statement)
<ng-container *ngFor="let item of items; trackBy: trackByFn">
{{item}}
</ng-container>
<ng-container *ngIf="items.length === 0">
There were no items in the list.
</ng-container>
RFC (For Statement)
{#for item of items; track item.id}
{{ item }}
{:empty}
There were no items in the list.
{/for}
Oprócz alternatyw dla znanych nam już strukturalnych dyrektyw, zespół Angulara przygotował również RFC dla zupełnie nowej funkcjonalności – leniwego ładowania fragmentów szablonów. Nowa „dyrektywa” oferuje wszystko czego możecie potrzebować przy lazy loadingu – zaawansowane strategie ładowania, obsługę stanu ładowania i błędu, czy definicję minimalnego czasu wyświetlania poszczególnych wersji, w celu uniknięcie mrugania.
{#defer on interaction, timer(5s)}
<calendar-cmp />
{:placeholder minimum 500ms}
<img src="placeholder.png" />
{:loading}
<div class="loading">Loading the calendar...</div>
{:error}
<p> Failed to load the calendar </p>
<p><strong>Error:</strong> {{$error.message}}</p>
{/defer}
Źródła
RFC: Built-In Control Flow
RFC: Deferred Loading
TypeScript 5.1
Kilka ostatnich wersji TypeScript przyniosło nam naprawdę ciekawych funkcjonalności. W wersji 4.9 dostaliśmy nowe słowo kluczowe satisfies
. W wersji 5.0 cały codebase został przepisany z archaicznych namespaces do modułów, co przyniosło spore usprawnienia wydajności. Niestety wersja 5.1 nie przynosi zbyt wielu ciekawych nowinek…
Największą nowością w TypeScript 5.1 jest lepsze wnioskowanie typów dla funkcji nie zwierających return statement. W czystym JavaScript jeśli funkcja nie zawiera return statement to zwraca ona wartość undefined. W TypeScript, jeśli funkcja nie zawiera return statement to musi być otypowana jako void
. Ta drobna różnica w zachowaniu potrafiła czasami być irytująca, ale na szczęście TypeScript 5.1 w całości ją naprawia.
// ✅ fine - we inferred that 'f1' returns 'void'
function f1() {
// no returns
}
// ✅ fine - 'void' doesn't need a return statement
function f2(): void {
// no returns
}
// ✅ fine - 'any' doesn't need a return statement
function f3(): any {
// no returns
}
// ❌ error in TypeScript 5.0
// |A function whose declared type is neither |
// |'void' nor 'any' must return a value. |
// ✅ fine in TypeScript 5.1
function f4(): undefined {
// no returns
}
Kolejna nowość to całkowite rozdzielenie typów dla setterów i getterów. Co prawda do tej pory mogły się one różnić, ale istniał między nimi bardzo specyficzny kontrakt. Od teraz kontrakt ten przestaje mieć znaczenia i mogą one przyjmować zupełnie niezwiązane ze sobą typy.
// ❌ error in TypeScript 5.0
// ✅ fine in TypeScript 5.1
interface CSSStyleRule {
// ...
/** Always reads as a `CSSStyleDeclaration` */
get style(): CSSStyleDeclaration;
/** Can only write a `string` here. */
set style(newValue: string);
// ...
}
Źródła
Microsoft Clarity
W minionym miesiącu Microsoft podzielił się ze światem swoim rozwiązaniem do tworzenia map cieplnych stron i nagrywania sesji użytkowników. Co ważne, jest ono darmowe i korporacja z Redmond zapowiada, że takim pozostanie. Ponadto Microsoft sam intensywnie korzysta już z tego narzędzia dla wewnętrznych projektów. Następnym razem kiedy przyjdzie Wam wybierać narzędzie do analityki waszej aplikacji, warto rozważyć Microsoft Clarity jako darmową ograniczoną w funkcjonalności wersję Hotjar’a.
Źródła
See what your users want—with Clarity
Zainstaluj teraz i czytaj tylko dobre teksty!
State of CSS 2023
Kilka tygodni temu do sieci trafiła kolejna edycja ankiety State of CSS. Powtarzam to co roku i powtórzę to też teraz: Jeśli szukacie czegoś co pozwoli Wam szybko i efektywnie nadrobić nowości ze świata CSS-ów z kilku ostatnich lat, to State of CSS jest najlepszym miejscem żeby to zrobić. Podsumowując, nie tylko macie okazję przyczynić się dla dobra społeczności, ale również efektywnie i szybko nauczyć się czegoś nowego.