Frontend, Poradnik

Wprowadzenie do Preact. Poznajcie lżejszą alternatywę Reacta

Rozpoczynając przygodę z React, nie miałem zbyt dużej świadomości na temat wydajności aplikacji webowych. Pracując jednak na co dzień z aplikacjami internetowymi i korzystając z biblioteki React, coraz częściej zaczynałem zauważać problemy z wydajnością czy też contentem dostosowanym pod SEO. Poszukując lepszego, alternatywnego rozwiązania dla React, natrafiłem na temat, który zapewne nie tylko dla mnie stanowi nowość – Preact.

Co to jest biblioteka Preact? Zanim zajmiemy się szerzej tymi zagadnieniami, przedstawię Ci, dlaczego w ogóle warto zwrócić uwagę na Preact, jakie posiada zalety i czym różni się od React.

Najpopularniejsze frameworki – porównanie

W poszukiwaniu odpowiedzi na pytanie o najpopularniejszy framework, zbadajmy rynek polski oraz światowy za pomocą narzędzia trends.google. Na poniższych wykresach, gdzie kolorem niebieskim oznaczono React, czerwonym Angular, a żółtym Vue, od razu widzimy, które z rozwiązań cieszy się największym zainteresowaniem.

Analizując wykres szybko dostrzeżemy bardzo dużą popularności biblioteki React, która plasuje się dużo wyżej niż Angular czy Vue zarówno wśród polskich, jak i zagranicznych użytkowników. Nie należy się temu dziwić, ponieważ React jest w pełni dojrzałą biblioteką, która pozwala w bardzo szybki sposób budować interfejsy użytkownika.

popularność bibliotek it polska

Popularność bibliotek – Polska

popularność bibliotek it świat

Popularność bibliotek/frameworków – świat

Możemy także zauważyć znaczną różnicę w ilości pobrań projektów z npm (managera pakietów). Aby porównać ilości pobrań React, Angular i Vue skorzystamy z narzędzia nmptrends.com. Na zamieszczonym poniżej wykresie, React jest oznaczony kolorem pomarańczowym, Vue zielonym, zaś Angular niebieskim.

Przeglądając źródła nmptrends.com, widzimy ogromną różnicę w ilości pobrań biblioteki React w porównaniu do Angular czy Vue. Także i tutaj React deklasuje konkurencję.

popularność react angular vue

Skąd taka różnica i tak wielka popularność React w tym zestawieniu? Według mnie spora tutaj zasługa szkół/bootcamp’ów programowania, których powstało ostatnimi czasy bardzo dużo, a które opierają swój program nauczania właśnie o React. Jako że zalety React są najlepiej znane i ma on niższy „próg wejścia”, jest zazwyczaj wybierany podczas szkoleń. W przypadku frameworku Angular nie jest już tak łatwo, co znajduje odbicie na powyższych wykresach.

Zalety React

Chociaż, jak wspomniałem wyżej, popularność React w dużej mierze może wynikać z powszechności zastosowania w szkołach programowania, nie znaczy to, że jest to jedyny jej powód. Nie należy umniejszać bowiem możliwościom React i trzeba przyznać, że jest fenomenalną biblioteką, posiadającą wiele zalet, które doceniają użytkownicy na całym świecie. Te zalety to przede wszystkim:

  1. Łatwość nauki – niższy próg wejścia,​
  2. Wirtualny DOM,​
  3. Re-używalne komponenty / modularność,​
  4. Bardzo duża społeczność,
  5. React developer tools,​
  6. One-way data flow,​
  7. Łatwość integracji z Redux​JSX.

Dlaczego warto dbać o wielkość bundla?

Korzystając z internetu wiemy, jak irytujące potrafią być aplikacje, które ładują się zdecydowanie zbyt długo. Najpewniej większość użytkowników ma ochotę po prostu je zamknąć i poszukać takich, które działają szybciej. Wiedząc o tym, warto zwrócić uwagę na szybkość ładowania naszej aplikacji, która ma przecież przyciągnąć do siebie jak największą liczbę odbiorców. Co możemy zrobić?

Tworząc aplikacje dla użytkowników z całego świata, nie mamy wpływu na to, jak szybkim połączeniem internetowym dysponują nasi końcowi odbiorcy. Mamy natomiast wpływ na wagę projektu, na wielkość bundla, która ma ogromne znaczenie dla szybkości ładowania i na tym powinniśmy się skupić. Chcąc sprawdzić, w jakim tempie nasza aplikacja będzie się ładować w przypadku słabszych połączeń internetowych, dobrze jest to przetestować przed wypuszczeniem naszego release’a.

Do pomiarów aktualnych rozmiarów pakietów warto wykorzystać dwa narzędzia:

  • Analizator pakietów Webpack
  • Lighthouse

Jak sprawdzić szybkość ładowania się aplikacji?

W przypadku aplikacji zbudowanej za pomocą create-react-app wystarczy wykonać następujące kroki:

npm install --save source-map-explorer

Następnie w pliku package.json dodajmy linie w scripts:

"scripts": {
+    "analyze": "source-map-explorer 'build/static/js/*.js' --html tree.html",
     "start": "react-scripts start",
     "build": "react-scripts build",
     "test": "react-scripts test",

W dalszej części przechodzimy do budowania projektu:

## budowanie projektu
npm run build

## uruchomienie analizera bundla
npm run analyse

Na zakończenie, po otworzeniu pliku tree.html widzimy wyliczenie per zależność:

widok bundle

Analiza bundla aplikacji React (CRA)

Sprawa wygląda bardzo podobnie w przypadku aplikacji React z własną konfiguracją webpack.

Na samym początku instalujemy plugin webpack-bundle-analyzer:

npm install --save-dev webpack-bundle-analyzer

Następnie dodajemy plugin w konfiguracji webpacka:

const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

plugins: [
  ...
  new BundleAnalyzerPlugin({
    analyzerMode: "static",
  })
]
webpack bundle

Sprawdzanie szybkości aplikacji za pomocą Lighthouse

Google Lighthouse jest narzędziem, które pozwala na przeprowadzenie audytu strony internetowej. Chcąc tego dokonać, musimy zainstalować wtyczkę, a następnie przejść do naszej strony i otworzyć narzędzie Lighthouse. Kolejnym krokiem będzie kliknięcie w pole „Generate report”. Tutaj mała wskazówka – najlepsze efekty otrzymamy, jeżeli w celu wykonania audytu otworzymy naszą aplikację w oknie prywatnym (incognito mode).

Rozszerzenie otworzy nowe okno, w którym nasza strona zostanie załadowana w różnych formach i tym samym zostanie sprawdzona pod różnymi kątami. Po załadowaniu strony, Lighthouse otworzy nowe okno, w którym znajdzie się raport.

Badanie przeprowadzone przez narzędzie Lighthouse dotyczy 5 różnych aspektów działania strony:

  • Performance
  • Progressive Web App
  • Accesibility
  • Best practices
  • SEO.

Poniżej widok przykładowego raportu wykonanego za pośrednictwem Lighthouse:

statystyki preact

Z narzędzia możemy skorzystać w Chrome DevTools. Więcej informacji na temat narzędzi DevTools znajdziesz na poświęconej im stronie.

Preact vs React – porównanie

Po omówieniu zalet React, oraz tego, dlaczego tak istotna jest waga projektu i sprawdzanie czasu ładowania aplikacji internetowej, pora lepiej zapoznać się z Preact.

Dla pełnego zrozumienia fenomenu biblioteki Preact, zacznijmy od przeanalizowania rozmiarów paczek poszczególnych technologii. W tym celu wykorzystamy narzędzie bundlephobia.com. Wielkość paczek za pomocą tego narzędzia może dokładnie sprawdzić każdy z nas. Używając go teraz, skupimy się na porównaniu paczek:

  • react, react-dom,
  • preact, preact-dom.

Porównując rozmiary zminimalizowanych paczek możemy zauważyć ogromną różnicę. Rozmiar zminimalizowanej paczki react+react-dom to 128kb. Patrząc na tendencję wzrostową – jest to trochę niepokojące. Jak w tym porównaniu wypadł Preact? Wynik jest zaskakujący. Paczka preact + preact-dom waży niecałe 20kb!

Wygląda to interesująco. Jak jednak jest to możliwe i czy w związku z tym Preact na pewno posiada takie same funkcjonalności jak React? Okazuje się, że tak. Preact jest lżejszą alternatywą dla React, która mocno koncentruje się na wydajności. Dodatkowo, w przeciwieństwie do innych alternatyw, takich jak Vue czy Angular, korzysta z takiego samego API jak React.

Jakie są różnice między React a Preact?

  • Hooks: hooks w Preact są przechowywane oddzielnie i muszą być importowane inaczej niż w React.
  • Rozmiar aplikacji: jak pokazało porównanie, które przeprowadziliśmy wyżej, Preact jest znacznie lżejszy niż React.
  • Renderowanie: aplikacje React zajmują dużo czasu podczas ładowania, dzięki czemu proces renderowania jest powolny i kompleksowy. Preact ma szybszy proces renderowania.
  • Obsługa zdarzeń: React wdraża swój własny Syntetic Event dla obsługi zdarzeń, zmniejszając wydajność aplikacji, podczas gdy Preact korzysta z wbudowanego addEventListner.
  • Korzystanie z JSX i HTML: W Preact można użyć starych atrybutów HTML, ponieważ nie korzysta JSX do szablonowania po stronie klienta. Zamiast tego korzysta z implementacji HyperScript.

Co przemawia za Preact?

Zwykle nie przemawia do mnie argumentacja oparta wyłącznie na różnicach, ale zastanawiający jest dla mnie fakt, że Preact korzysta niemalże z takiego samego API jak React. Oprócz tego trzeba wspomnieć o tym, że Preact posiada specjalny moduł preact/compat, który pozwala na zmigrowanie naszej aplikacji napisanej w React na Preact i to tak naprawdę bez większej integracji w kod.

Co zyskamy na takim rozwiązaniu? Bardzo wiele, począwszy od wielkości naszego bundla (co zaraz przetestujemy), poprzez poprawę szybkości ładowania naszej strony, a na poprawie wydajności aplikacji kończąc. Dodatkowo Preact posiada najszybszy wirtualny DOM w porównaniu z innymi bibliotekami dostępnymi na rynku. Przynajmniej z tego powodu zasługuje na nasze uznanie.

Czy Preact posiada jakieś wady?

Jak każde rozwiązanie, tak i Preact posiada oczywiście pewne wady. Po pierwsze, społeczność Preact jest znacznie mniejsza niż React. Na szczęście społeczność Preact, choć niewielka, jest bardzo pomocna. Sami twórcy często się udzielają i pomagają użytkownikom w rozwiązywaniu problemów.

Za kolejną „wadę” możemy uznać to, że Preact nie jest utrzymywany przez dużą firmę, jak np. Google czy Facebook. Może to być dla większych firm powodem do tego, by nie wybrać tej technologii w obawie przed zaprzestaniem aktualizowania biblioteki. Wraz z wystąpieniem takiej ewentualności, pozbawiłyby się bowiem łatek bezpieczeństwa czy też aktualizacji „ficzerów”.

Budujemy aplikację Preact

Znamy już wady i zalety Preact. Najwyższa pora przetestować nowe rozwiązanie. Kolejnym plusem jest fakt, że Preact wypuścił fenomenalne CLI (Command Line Interface). Jeżeli więc chcemy zbudować aplikację opartą o Preact, wystarczy, że w terminalu wpiszemy następującą komendę:

npx preact-cli create

W tym momencie otrzymamy możliwość wyboru, który template chcemy wybrać. Dla naszego testu wybierzemy default. Automatycznie będziemy w nim już mieli zaimplementowany routing.

preact cli

Następnie zostaniemy poproszeni o podanie nazwy aplikacji. W tym miejscu możemy wpisać nazwę, jaką chcemy nadać swojej aplikacji, a CLI utworzy nowy folder wraz w pełni działającą aplikacją Preact.

Jeżeli wpisaliśmy już nazwę, możemy uruchomić projekt i zobaczyć, jak wygląda wydajność aplikacji. Moja aplikacja została nazwana preact, co można zauważyć poniżej.

cd preact # wejście do katalogu
npm run dev # uruchomienie aplikacji

Mając już pierwszy projekt, przeanalizujmy, jak wygląda bundle i zmierzmy jego wydajność. Całość bundla waży ok. 173kb. Poniżej znajduje się jego rozkład na poszczególne moduły:

Spójrzmy też na raport wygenerowany za pośrednictwem Lighthouse:

performance preact cli

Na razie wygląda to naprawdę obiecująco. Warto zauważyć, że nasza aplikacja na starcie jest aplikacją PWA.

Aby przekonać się o tym, jak w praktyce wygląda różnica między Preact a React i móc je odpowiednio porównać, takiej samej analizie poddajmy React CLI. Rezultaty analizy przestawione zostały poniżej:

performance react

Jak widzimy powyżej, bundle create-react-app waży 135kb. Dlaczego waga jest mniejsza? Aplikacja Preact posiada dodatkowe biblioteki, które w aplikacji React musimy jeszcze doinstalować. Ponadto dodatkowy kod powoduje, że nasza aplikacja jest PWA. Możemy również zauważyć jedną rzecz – pomimo tego, że aplikacja React jest odrobinę lżejsza na początku, to jej wydajność jest znacznie gorsza.

Oczywiście porównanie powinno być miarodajne. Pomoże nam w tym zmigrowanie aplikacji React do Preact. Tym samym zobaczymy, jak wygląda build aplikacji create-react-app ale z Preact’em.

preact react build create app

Wynik jest zaskakujący. Po zmigrowaniu całość buildu waży zaledwie 27kb! Wykonaliśmy więc niewielką zmianę, a dzięki temu nasza aplikacja stała się zdecydowanie bardziej wydajna.

Migracja z React do Preact

Widząc, jak wiele może zmienić migracja z React do Preact, sprawdźmy, jak to zrobić. Na szczęście posiadając już projekt napisany przy użyciu biblioteki React nie będziemy musieli całkowicie zmieniać struktury naszego projektu. Preact przygotował bowiem specjalną paczkę preact/compat. Dzięki niej nasze aplikacje napisane w React nie wymagają już skomplikowanych refaktorów, a my możemy cieszyć się wydajnością Preact.

Jak zmigrować aplikację do Preact?

Prześledźmy, w jaki sposób zmigrować aplikację React do Preact. Jeżeli korzystamy z CRA (create react app), to sprawa jest dość prosta i będzie od nas wymagała instalacji tylko jednej biblioteki. Wchodząc na repozytorium projektu cra-preact widzimy, że migracja takiej aplikacji jest dość prosta.

Na początek instalujemy bibliotekę w naszym projekcie:

npm i -D cra-preact

Następnie w pliku package.json zmieniamy skrypty dla build, start i test:

"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
+ "start": "cra-preact start",
+ "build": "cra-preact build",
+ "test": "cra-preact test",
  "eject": "react-scripts eject"
}

Po wszystkim możemy cieszyć się aplikacją wykorzystującą Preact. Prawda, jakie to proste?

Trudniej będzie w sytuacji, jeżeli nasza aplikacja nie korzysta z CRA i ma wyciągniętą konfigurację webpack. Nawet wtedy jednak procedura nie jest zbyt skomplikowana. Musimy podjąć następujące kroki:

npm i preact preact-compat

Następnie w pliku package.json usuwamy react i react-dom.

"dependencies": {
- "react-dom": "^16.11.0",
- "react-router-dom": "^6.2.2",
+ "preact": "^10.6.6",
+ "preact-compat": "^3.19.0",
}

Dobrze jest także usunąć cały katalog node_modules:

# Usunięcie katalogu z zależnościami
rm -rf node_modules/

# Instalacja zależności
npm i

Takie działanie daje nam pewność, że zależności związane z React są usunięte i podmienione. Pozostaje pytanie, jak w takim razie podmienić zależności w całym naszym projekcie? Na szczęście jest na to kilka sposobów. Jednym z nich może być np. podmiana zależności react na preact/compat, ale jako programiści z pewnością znajdziemy prostszy sposób na rozwiązanie takiego problemu.

Kolejnym sposobem będzie podmiana w konfiguracji webpack przekierowania na odpowiednią bibliotekę. Za pomocą resolve dajemy informację, że każde wywołanie react lub react-dom będzie tak naprawdę użyciem biblioteki preact/compat.

module.exports = {
    ...
    module: {
      ...
    },
+   "resolve": {
+     "alias": {
+        "react": "preact/compat",
+        "react-dom": "preact/compat"
+    }
+  },
    plugins: [
            new BundleAnalyzerPlugin({
                analyzerMode: "static",
            })
    ]
};

Teraz możemy już uruchomić naszą aplikację i zobaczyć czy wszystko działa poprawnie.

npm start

Jestem przekonany, że wszystko działa jak należy. Gratulacje! Teraz można sprawdzić, jak wygląda wydajność naszej aplikacji za pomocą narzędzi, które omówiliśmy już powyżej.

Na koniec tematu związanego z migracją, należy dodać jeszcze jedną ważną uwagę. Preact korzysta z preact-router i znacznie różni się od react-router-dom w wersji 5 lub 6. Jeżeli chcemy korzystać z routera do Preact, niestety musimy przerobić routing na standard Preact. W przykładach powyżej zostawiliśmy bibliotekę react-router-dom i nie migrowaliśmy jej.

Aplikacja PWA (Nextjs i Preact)

Budowanie aplikacji komercyjnej zazwyczaj nie jest związane z czystym Reactem lub Preactem. W tym celu służą odpowiednie frameworki. Jednym z najbardziej popularnych będzie tutaj np. NexJs. Jest to kompletny framework, który wykorzystuje React do budowania interfejsów użytkownika.

Poniżej przedstawię, jak stworzyć aplikację PWA w oparciu o NexJs i zmigrować ją do Preacta. Na początku zbudujmy naszą aplikację. Do tego celu wykorzystamy CLI:

npx create-next-app next-pwa-demo && cd next-pwa-demo

Teraz doinstalujmy bibliotekę next-pwa:

npm i next-pwa

Następnie musimy wygenerować ikonki pod PWA i wygenerować manifest.json. Korzystając z tego generatora, wystarczy wgrać ikonę i uzupełnić pola, a później wygenerować. Struktura plików w folderze public powinna wyglądać w ten sposób:

next manifest

Plik manifest.json wygląda teraz następująco:

{
  "name": "scaloapp",
  "short_name": "scalo",
  "theme_color": "#1976d2",
  "background_color": "#fafafa",
  "display": "standalone",
  "scope": "./",
  "start_url": "./",
  "icons": [
    {
      "src": "/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable any"
    }
  ]
}

Następnym krokiem będzie dodanie plik _document.js w katalogu pages

import Document, { Html, Head, Main, NextScript } from "next/document";

class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head>
          <link rel="manifest" href="/manifest.json" />
          <link rel="apple-touch-icon" href="/icon.png"></link>
          <meta name="theme-color" content="#fff" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

Aby wszystko działało poprawnie, dodajmy informację, że nasza aplikacja będzie aplikacją PWA. Zmieńmy nasz plik next.config.js na taki:

const withPWA = require("next-pwa");

module.exports = withPWA({
  pwa: {
    dest: "public",
    register: true,
    skipWaiting: true,
  },
});

Teraz możemy w końcu uruchomić naszą aplikację:

npm run dev

Dla pewności i porównania sprawdźmy, jak wygląda wydajność aplikacji. Do tego celu wykorzystajmy, jak w poprzednich przypadkach, Lighthouse.

performance next react

Wynik nie jest najgorszy, chociaż wydajność nie jest najlepsza. Mamy już za to aplikację PWA. Sprawdźmy, jak parametry będą wyglądać po zmigrowaniu do Preacta.

Zacznijmy od zainstalowania bibliotek preact i preact-compat:

npm i preact preact/compat

Następnie usuwamy z pliku package.json zależności react:

"dependencies": {
    "next": "12.1.0",
    "next-pwa": "^5.4.6",
+   "preact": "^10.6.6",
+   "preact-compat": "^3.19.0",
-   "react": "17.0.2",
-   "react-dom": "17.0.2"
  },

Oczywiście możemy usunąć nasz katalog node_modules i zainstalować zależności ponownie.

Zmieńmy plik next.config.js na taki, jak poniżej:

const withPWA = require('next-pwa')

module.exports = withPWA({
  pwa: {
    dest: 'public'
  },
  webpack: (config, { dev, isServer }) => {
    // if (!dev && !isServer) {
    Object.assign(config.resolve.alias, {
      react: 'preact/compat',
      'react-dom/test-utils': 'preact/test-utils',
      'react-dom': 'preact/compat',
    });
    // }

    return config;
  },
})

Po zmigrowaniu sprawdźmy, jak wygląda raport wygenerowany przez Lighthouse:

next preact performance

Widzimy, że wydajność aplikacji odrobinę wzrosła. Jestem przekonany że przy bardziej złożonej aplikacji ta różnica byłaby jeszcze większa.

Podsumowanie

Patrząc na powyższe, Preact wygląda na świetną alternatywę dla React. To biblioteka ze stale wzrastającą społecznością i ciesząca się coraz większą popularnością wśród użytkowników. Z pewnością Preact będzie doskonałym rozwiązaniem, jeżeli budujemy aplikację internetową z wymaganiami wysokiej wydajności lub aplikację mobilną z myślą o wolniejszych połączeniach internetowych.

Zgłębiając temat zauważyłem, że zespoły decydują się na Preact w większych aplikacjach, w których szybkość ładowania strony ma naprawdę ogromne znaczenie. Właśnie w przypadku takich aplikacji widzę bardzo duże możliwości w zastosowaniu Preact.

Należy jednak pamiętać, że zmiana React na Preact nie sprawi, że nasza aplikacja stanie się od razu mega wydajna, podobnie jak zjedzenie powiększonego zestawu w restauracji fast-food i popicie go colą light niewiele zmieni w ciężkości całego dania. Każda aplikacja, która jest przeładowana innymi dużymi bibliotekami będzie ciężka. Także ta z Preact.

Na pewno jest to rozwiązanie warte zainteresowania i przetestowania, do czego zachęcam.

baner

Z branżą IT związany jest nieprzerwanie od 2008 roku. W ciągu kilkunastu lat zdobył bogate doświadczenie w pracy z wieloma firmami z różnych sektorów, poczynając od startupów, poprzez prywatne firmy, a skończywszy na korporacjach. Od 2016 roku postanowił skupić się na technologiach frontendowych, rozpoczynając od Angular 2+, a następnie zdecydował się na pracę w środowisku React/Redux. Od tego czasu niezmiennie zakochany w React oraz możliwościach, jakie daje.

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://geek.justjoin.it/wprowadzenie-do-preact-poznajcie-lzejsza-alternatywe-reacta/" order_type="social" width="100%" count_of_comments="8" ]