7 listopada 2022 7 min. czytania

Webpack, Parcel, Babel, bla, bla… po co mi bundler modułów?

Bundler modułów jest bazą dla wielu projektów i frameworków. Zazwyczaj nie zwracamy uwagi na te podstawowe narzędzia. Ale może powinniśmy?

Zaktualizowano: 7 listopada 2022
Czarnobrązowy jamnik stojący w pudełku
Zdjęcie autorstwa Erda Estremera

Wszyscy znamy trzy składniki potrzebne do zbudowania strony internetowej: HTML, CSS, JavaScript. HTML jest jak rzeczowniki w zdaniach, CSS jak przymiotniki, a JavaScript jest jak czasowniki. HTML definiuje strukturę, CSS style, JavaScript funkcjonalność. Ale czy obecnie to wystarcza?

Pierwsze strony internetowe z lat 90. były proste. Były to statyczne dokumenty ze znikomą ilością styli czy funkcjonalności. Wystarczyło napisać trochę HTML-a, dołączyć arkusz stylów i skrypt (jeżeli w ogóle) i strona była gotowa. W latach 90. robiłem swoje pierwsze kroki (dosłownie), dlatego do moich pierwszych kroków w tworzeniu stron musiało minąć trochę czasu. Ale nawet dla mnie ten prosty sposób tworzenia jest znajomy. Przypomina mi o moich pierwszych stronach.

Jednakże, współczesne aplikacje internetowe są o wiele bardziej złożone. Są one wysoko interaktywne. Składają się z wielu assetów, zdjęć w wielu formatach, filmów, fontów i innych zewnętrznych modułów. Dodatkowo ludzie wykorzystują technologie takie jak Typescript, React czy SCSS zamiast tych podstawowych języków. Wiele plików o różnorodnych rozszerzeniach importuje się wzajemnie wraz z innymi assetami. Ale nie jest to dostępne natywnie w przeglądarce. Współczesne przeglądarki dopiero zaczęły wspierać funkcjonalności modułów. No i nie możesz importować assetów wewnątrz plików js. Potrzebujemy narzędzia, aby rozwiązać te problemy.

Czym jest bundler modułów?

Module bundler rozwiązuje wymienione problemy. U podstaw, taki bundler bierze wiele plików js (moduły) i łączy je w jeden plik (bundle), który buduje twoją aplikację w przeglądarce. Poza lokalnymi modułami, wszystkie zewnętrzne zależności także zostaną scalone. Te zależności mogą posiadać swoje zależności itd. Bundler modułów, taki jak webpack, tworzy graf zależności, aby je śledzić. Oczywiście to jest uproszczenie. Skonfigurujemy projekt wraz narzędziem webpack, aby się zagłębić i poznać więcej funkcjonalności.

W narzędziach CLI jak create-react-app lub frameworkach jak Gatsby, webpack jest już skonfigurowany. Nadal jednak uważam, że dobrze wiedzieć co się dzieje "pod maską".

Webpack

Na początek zainicjujmy nowy projekt npm.

🔴 🟡 🟢
npm init -y

Następnie zainstalujmy paczki webpack.

🔴 🟡 🟢
npm install -D webpack webpack-cli

Potrzebujemy czegoś do “spakowania”, więc dodajmy prosty plik JavaScript.

./src/index.jsJS
1const exampleFunction = () => {
2 console.log('Message')
3}

Webpack zadziała bez wcześniejszej konfiguracji. Po wpisaniu w terminalu webpack, połączy on twoje pliki wykorzystując domyślną konfigurację. Jednakże, najczęściej chcesz dodać własną konfigurację. Musimy dodać plik konfiguracyjny, aby dostosować jego zachowanie. Plik ten musi eksportować obiekt wraz z twoimi ustawieniami.

Entry

Entry jest jak punkt startowy twojej aplikacji. Ta opcja przyjmuje ścieżkę do modułu. Webpack wykorzysta ten moduł, aby zacząć budować graf zależności. Ustawimy tę wartość na ./src/index.js, która jest też domyślną wartością. Może ona także przyjąć obiekt dla wielu ścieżek i podziału kodu (code splitting).

webpack.config.jsJS
1module.exports = {
2 entry: './src/index.js'
3}

Output

Output ustawia, gdzie webpack powinien umieścić nasz bundle. Ta opcja przyjmuje dwa parametry: path i filename. Skonfigurujemy webpacka, aby zapisywał bundle w ./public/main.js.

webpack.config.jsJS
1const path = require('path')
2
3module.exports = {
4 entry: './src/index.js',
5 output: {
6 filename: 'main.js',
7 path: path.resolve(__dirname, 'public')
8 }
9}

Loaders

Powiedzmy, że chcemy także ostylować naszą aplikację. Stwórzmy plik CSS ze zmienną.

./src/style.cssCSS
1:root {
2 --eiffel-65: blue;
3}

Następnie zaimportujmy go do naszej aplikacji.

./src/index.jsJS
1import './style.css'

Być może cię to zaskoczy, jeżeli przywykłeś do frameworków, ale ta składnia nie zadziała. Potrzebujemy sposobu, żeby przekształcić nasz plik CSS w poprawny moduł. A webpack sam w sobie nie robi aż tak wiele. W domyśle wspiera tylko pliki JSON i JavaScript. Dlatego potrzebujemy loadera. Loader konwertuje różne typy plików na poprawne moduły. Potrzebujemy zainstalować dwa z nich, aby użyć naszych stylów.

🔴 🟡 🟢
npm install -D style-loader css-loader

Następnie musimy je skonfigurować. Loader przyjmuje dwie właściwości:

  • Właściwość test, która identyfikuje pliki do przekształcenia.
  • Właściwość use ustala, którego loadera użyć.

W naszym przypadku, użyjemy wyrażenia regularnego do zidentyfikowania plików CSS i użyjemy powyższych loaderów.

webpack.config.jsJS
1const path = require('path')
2
3module.exports = {
4 entry: './src/index.js',
5 target: ['web', 'es5'],
6 output: {
7 filename: 'main.js',
8 path: path.resolve(__dirname, 'public')
9 },
10 module: {
11 rules: [
12 {
13 test: /\.css$/,
14 use: ['style-loader', 'css-loader']
15 }
16 ]
17 }
18}

Babel

Pora na małą dygresję. Z naszym plikiem może być inny problem - konkretnie, funkcja strzałkowa. Podobnie jak Jahwe pomieszał ludziom języki, bogowie przeglądarek mieszają implementacje JavaScript. Pomimo że przeglądarki obsługują większość funkcjonalności specyfikacji ES6, wsparcie nie jest stuprocentowe. Powiedzmy, że chcemy wspierać Internet Explorera z jakiegoś powodu. Potrzebujemy sposobu na przekształcenie naszej składni. Moglibyśmy wykorzystać polyfill, ale wraz z nowym kodem i funkcjonalnościami, szybko stałoby się to kłopotliwe. JavaScript szybko się rozwija i nowa składnia pojawia się regularnie: async/await, operator spread, klasy itp. Kilka postów temu, sam napisałem o nowej, przydatnej funkcjonalności - optional chaining. W tym momencie, jak dar glosolalii od Boga, przychodzi Babel. Babel bierze współczesną składnię języka JavaScript i kompiluje ją do formy zrozumiałej przez różne przeglądarki. Babel wykorzystuje pluginy, aby przekształcać różne funkcjonalności języka takie jak plugin-proposal-optional-chaining. Pluginy są małe i nie chcemy ich instalować oddzielnie. Zamiast tego, zdefiniujemy preset z wieloma funkcjonalnościami. Wykorzystamy babel-preset-env. Pozwala on na definiowanie poziomu kompatybilności z przeglądarkami, które chcemy wspierać. Dodamy także preset dla biblioteki React.

🔴 🟡 🟢
npm install -D @babel/core @babel/preset-env @babel/preset-react babel-loader
🔴 🟡 🟢
npm install react react-dom

Babel może być używany niezależnie, ale my skonfigurujemy go z webpackiem. W tym celu musimy dodać loader wewnątrz tablicy rules. Tym razem musimy wykluczyć folder node_modules i dodać presety, dlatego właściwość use przyjmuje obiekt.

webpack.config.jsJS
1const path = require('path')
2
3module.exports = {
4 entry: './src/index.js',
5 target: ['web', 'es5'],
6 output: {
7 filename: 'main.js',
8 path: path.resolve(__dirname, 'public')
9 },
10 module: {
11 rules: [
12 {
13 test: /\.css$/,
14 use: ['style-loader', 'css-loader']
15 },
16 {
17 test: /\.js$/,
18 exclude: /(node_modules|bower_components)/,
19 use: {
20 loader: 'babel-loader',
21 options: {
22 presets: ['@babel/preset-env', '@babel/preset-react']
23 }
24 }
25 }
26 ]
27 }
28}

Teraz możemy stworzyć prosty komponent React.

./src/component.jsJSX
1import React from 'react'
2
3const Heading = () => {
4 return (
5 <h1 style={{ color: 'var(--eiffel-65)' }}>
6 This is heading with style variables
7 </h1>
8 )
9}
10
11export default Heading

I zaimportować go wraz ze stylami w naszym głównym pliku.

./src/index.jsJSX
1import React from 'react'
2import { createRoot } from 'react-dom/client'
3import './style.css'
4import Heading from './component'
5
6const root = createRoot(document.getElementById('root'))
7root.render(<Heading />)

Jeżeli skonfigurowaliśmy wszystko poprawnie, webpack powinien nadal działać. Nasz bundle powinien tym razem zawierać znacznie więcej kodu, ponieważ pakujemy także bibliotekę React. Możemy nawet sprawdzić z czego składa się nasz bundle.

Plugins

Pluginy są potężniejszymi wersjami loaderów. Możesz je wykorzystać do szerszego wachlarza zadań, takich jak optymalizacja całego procesu czy zarządzanie assetami. Chcieliśmy przeanalizować nasz bundle i szczęśliwie istnieje plugin, który możemy wykorzystać. Najpierw zainstalujmy go.

🔴 🟡 🟢
npm install -D webpack-bundle-analyzer

Następnie musimy dodać właściwość plguins do naszej konfiguracji. Przyjmuje ona tablicę ze wszystkimi pluginami. W tablicy stworzymy instancję naszego nowego obiektu.

webpack.config.jsJS
1const path = require('path')
2const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
3
4module.exports = {
5 entry: './src/index.js',
6 output: {
7 filename: 'main.js',
8 path: path.resolve(__dirname, 'public')
9 },
10 module: {
11 rules: [
12 {
13 test: /\.css$/,
14 use: ['style-loader', 'css-loader']
15 },
16 {
17 test: /\.js$/,
18 exclude: /(node_modules|bower_components)/,
19 use: {
20 loader: 'babel-loader',
21 options: {
22 presets: ['@babel/preset-env', '@babel/preset-react']
23 }
24 }
25 }
26 ]
27 },
28 plugins: [new BundleAnalyzerPlugin()]
29}

Po uruchomieniu webpacka, karta przeglądarki powinna się otworzyć. Powinieneś ujrzeć interaktywną mapę z proporcjonalnie przeskalowanymi prostokątami. Symbolizują one zależności i zawierają dodatkowe informacje. W mojej opinii - całkiem fajny plugin.

Webpack bundle analyzer

Podsumowanie

Teraz już wiemy dlaczego zaprzątamy sobie głowę tymi pobocznymi technologiami. Bundler modułów, taki jak webpack, potrafi przekształcić nasz kod, assety i sprawić, aby były kompatybilne z różnymi przeglądarkami. W tym wpisie skonfigurowaliśmy webpacka, ale istnieją alternatywy jak parcel czy rollup. Mogą się różnić detalami, ale podstawowa idea jest taka sama. Poprawnie skonfigurowany module bundler i Babel mogą zająć się różnymi dziwactwami języka/przeglądarek i uczynić nasze programistyczne życie mniej irytującym.

Newsletter, który rozpala ciekawość💡

Subskrybuj mój newsletter, aby otrzymywać comiesięczną dawkę:

  • Nowości, przykładów, inspiracji ze świata front-end, programowania i designu
  • Teorii naukowych i sceptycyzmu
  • Moich ulubionych źródeł, idei, narzędzi i innych interesujących linków
Nie jestem nigeryjskim księciem, aby oferować ci okazje. Nie wysyłam spamu. Anuluj kiedy chcesz.

Pozostań ciekawy. Przeczytaj więcej

Babeczki z turkusowym lukrem udekorowane posypką21 października 20239 min. czytania

TypeScript - dekoratory

Udekorujmy nasz tor... kod używając dekoratorów TypeScript. Dekoratory są smacznym dodatkiem do klas i zapewniają składnię do metaprogramowania.

Czytaj wpis
Zużyty, czarno-biały klaps filmowy14 czerwca 20238 min. czytania

Podejmij akcję i naucz się GitHub Actions!

Programiści uwielbiają automatyzować rzeczy. Ale automatyzacja jest korzystna tylko wtedy, gdy zabiera mniej czasu niż zwraca. Dzięki GitHub Actions może osiągniemy ten zysk.

Czytaj wpis
Joker na szczycie rozsypanych kart19 kwietnia 20239 min. czytania

TypeScript - typy generyczne

Typy generyczne nie istnieją w JavaScripcie, ale są jednym z podstawowych konceptów w TypeScripcie. Oferują to co najlepsze z obu światów: elastyczność i bezpieczeństwo typów.

Czytaj wpis