Martin Michálek Martin Michálek  – 9. 10. 2019

Webpack je nástroj pro zpracování souborů a usnadnění práci vývojářů. Jde o kombinaci balíčkovače (module bundler jako je Browserify) se spouštěčem úloh (task runner jako jsou Gulp nebo Grunt).

Webpack je určený primárně pro svět JavaScripu, jeho modularizaci, izolaci proměnných a chytré distribuci pomocí dělení kódu (code splitting). Tam je vážně téměř nepostradatelný.

CSS, obrázky, webfonty na statických webech? Zvažte jiné nástroje

U všech souborů, které do Webpacku nacpete – a že jimi mohou být kromě JS i céeseska, obrázky, webfonty a cokoliv vás napadne – se předpokládá, že budou součástí výstupního javascriptového balíčku.

To chcete u javascriptových aplikací, ale asi většinou ne u statických webů, kde se předpokládá, že styly a spol. budou v samostatných souborech oddělených od JS.

Vyřešit se to ve Webpacku dá: Existuje hodně loaderů, zpracovávačů souborů. Jenže i tak to často bude jako se drbat levou nohou za pravým uchem.

Pro zpracování čehokoliv mimo JavaScript jsou prostě lepší tradiční spouštěče jako Grunt, Gulp, NPM skripty nebo třeba Make.

Podívejte se na video „Webpack“.

YouTube: youtu.be/nYg829xX8uo

Ale mě to stejně nedalo. Vyzkoušel jsem si nastavit Webpack tak, aby zpracoval styly psané v preprocesoru SCSS do samostatného CSS. Bolelo to. Ale vznikl díky tomu alespoň pěkný tutoriál pro začátečníky.

Tutoriál: Sass do CSS pomocí Webpacku

Pojďte čichnout k samotným základům tohodle silného nástroje. Budu to brát opravdu krok za krokem pro úplné začátečníky, ale věřím, že si leccos ujasní i zkušenější webpackeři.

Předpokládám, že znáte příkazovou řádku a základní nástroje typu NPM.

Krok 1: Předpoklady

Začneme úplně od nuly. Vezměme, že máme tohle jednoduché HTML uložené v index.html:

<!-- index.html: -->
<!DOCTYPE html>
<html>
  <head>
    <title>Webpack Demo</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <div id="app"></div>
    <script src="dist/main.js"></script>
  </body>
</html>

Dále jsme si vytvořili testovací javascriptový soubor, konkrétně do src/index.js:

// src/index.js:
console.log("hello world!");

To bude hlavní vstup pro Webpack.

Krok 2: Instalujeme Webpack

Pokud máme nainstalovaný balíčkovač NPM, můžeme teď inicializovat náš projekt:

npm init --yes

Oním --yes dáváme instrukci, aby NPM v konfiguraci ponechalo výchozí hodnoty. Výsledkem jsou připravené konfiguráky package.jsonpackage-lock.json.

Ty zatím s Webpackem nemají nic společného. Nainstalujeme si jej až teď:

npm install --save-dev webpack webpack-cli

Balíček webpack asi netřeba představovat. Ten druhý – webpack-cli – slouží k ovládání Webpacku z příkazové řádky. To se bude hodit.

NPM by nám mělo vrátit tohle:

+ [email protected]
+ [email protected]
added 453 packages from 237 contributors and audited 5286 packages in 98.758s
found 0 vulnerabilities

Uf! Proběhlo to dobře. Můžeme dál.

Krok 3: Spouštíme Webpack

Teď už máme splněné minimální požadavky na běh Webpacku. Je nainstalovaný a existuje soubor, který může zpracovávat.

Můžeme si jej tedy spustit v adresáři s projektem:

npx webpack

Pokud neznáte příkaz npx: Spustí NPM balíček, který nemáte nainstalovaný na svém kompjůtru nebo jej nemáte v aktuálním adresáři.

Pokud ale budete Webpack používat intenzivně, doporučuji jednorázovou globální instalaci: npm install webpack-cli -g. Pak je možné nástroj pouštět ze všech adresářů jednoduchým příkazem webpack.

Zpět k příkazové řádce. Vrátí se něco jako:

Hash: 4fa48f2cc331e12d15a4
Version: webpack 4.41.0
Time: 360ms
Built at: 2019-10-04 06:33:56
  Asset       Size  Chunks             Chunk Names
main.js  957 bytes       0  [emitted]  main
Entrypoint main = main.js
[0] ./src/index.js 28 bytes {0} [built]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

Asi jste si všimli, že jsme Webpacku neposkytli žádnou konfiguraci. V tomhle případě běží ve výchozím módu. Co přesně udělal?

  • Podíval se do adresáře src/, zda nenajde soubor index.js. A ano, byl tam.
  • Sestavil si interní strom závislostí, v tomto případě spíše bonsai závislostí.
  • Výstup uložil do dist/main.js, což je výchozí nastavení pro výstupní soubor.
  • Vypočítal hash, unikátní kód pro toto sestavení (4fa48f2cc331e12d15a4), a spolu s ním pro nás vypotil nějaké další statistiky.
  • Seřval nás, že si máme nastavit mód práce. Ve výchozím režimu předpokládá, že tvoří výstupy produkční prostředí, tedy veřejný běh webové aplikace.

Krok 4: Kompilujeme Sass

Vezměme, že máme dva jednoduché SCSS soubory, na kterých si ukážeme, jak ve Webpacku funguje kompilace kódu z preprocesoru Sass do CSS:

// src/styles.scss:

html {
  font-family: Verdana, Geneva, Tahoma, sans-serif;
}

@import "_component.scss";

// src/_component.scss:

.component {
  font-size: 2rem;
  padding: 1rem;
}

V dalším kroku si přidáme balíčky a jejich konfiguraci, které nám umožní kompilovat soubory. Nejprve instalace balíčků:

npm install css-loader sass-loader node-sass style-loader --save-dev

Co jsme nainstalovali?

  • node-sass - kompilátor pro Sass
  • sass-loader - Webpack „loader“ pro Sass
  • css-loader – převaděč direktiv @import z CSS do importů, kterým rozumí JavaScript
  • style-loader – vkládání CSS do DOMu

Pak zde máme minimální konfiguaci Webpacku. Najdete ji většinou v souboru webpack.config.js:

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "main-configured.js"
  }
};

Vysvětlíme:

  • Položka entry ukazuje na vstupní soubory. Může jich pochopitelně být více.
  • V output zase najdete výstup, tedy soubor kam Webpack ukládá.

Do konfigurace pak přidáme nový modul:

module: {
  rules: [
    {
      test: /\.scss$/,
      use: [
        'style-loader',
        'css-loader',
        'sass-loader'
      ]
    }
  ]
}  

Vytvořili jsme pravidlo (objekty uvnitř rules), které vezme soubory končící příponou .scss a aplikuje (use) na ně naše loadery v uvedeném pořadí.

Můžeme si teď zkusmo pustit příkaz webpack. Jenže se nic nestane.

Tohle je právě jeden z rozdílů mezi Gruntem, Gulpem a Webpackem. Webpack je JS-centrický, vše se u něj točí kolem javascriptových balíčků.

To, co jsme vytvořili, je CSS balíček připravený pro distribuci uvnitř JS balíčku.

Vytvořené CSS můžeme importovat do index.js:

import "./styles.scss";
console.log("hello world!");

Po dalším spuštění Webpacku se nám vložní dovnitř distrubučního JS balíčku nějak takhle:

function(e, t, n) {
  (e.exports = n(3)(!1)).push([
    e.i,
    "html{font-family:Verdana, Geneva, Tahoma, sans-serif}.component{font-size:2rem;padding:1rem}\n",
    ""
  ]);
},

Můžete s tím být spokojení, ale u běžných statických webů to asi nechcete. Musíte tedy zařídit ukládání do souboru.

Krok 5: Ukládáme CSS do souboru

Nainstalujeme si plugin pro extrakci CSS do souboru – mini-css-extract-plugin:

npm install --save-dev mini-css-extract-plugin

A nyní jej zadrátujeme do konfigurace Webpacku. Vzhledem k tomu, že jde o poslední krok, tady je celý finální webpack.config.js:

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: ["./src/index.js", "./src/styles.scss"],
  output: {
    filename: "main-configured.js"
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "style.css"
    }),
  ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader",
          "sass-loader"
        ]
      }
    ]
  }
};

Podívejme se, co jsme od minulé verze změnili:

  • Načteme a použijeme náš extrakční plugin: require("mini-css-extract-plugin").
  • Do položky entry pro vstupní soubory jsme přidali SCSS soubor: ["./src/index.js", "./src/styles.scss"].
  • V pravidle pro .scss soubory jsme odstranili style-loader, protože už nestojíme o vkládání CSS do DOMu. Naopak jsme přidali použití nového pluginu loader: MiniCssExtractPlugin.loader.

Pro vstřebání úplných základů by to mohlo stačit, nechci to komplikovat.

Celé demo si můžete projít na github.com/machal/webpack-demo.

Dále bychom mohli zapracovat například prohnání výsledného CSS Autoprefixerem, přidání HMR (Hot Module Reloadingu) – automatického obnovování stylů v prohlížeči, detekci produkčního a vývojového prostředí a spoustu dalších věcí.

Pojďme si teď ale zopakovat pojmy, kterými jsem vás během popisu tutoriálu zasypal.

Slovník pojmů k Webpacku

Entry (vstup)

Zdrojové soubory, nad kterými bude Webpack provádět své operace. Výchozí je index.js v adresáři src. Je možné zde použít jeden soubor…

entry: {
  entry: "./src/file.js"
}

… objekt:

entry: {
  app: "./src/app.js",
  adminApp: "./src/admin.js"
}

… nebo třeba pole:

entry: ["./src/index.js", "./src/styles.scss"],

Output (výstup)

Výstupní soubor nebo soubory, kam se má ukládat. Výchozí je main.js v adresáři dist/.

Můžete to ale nastavit mnoha způsoby:

const path = require("path");

module.exports = {
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "public"),
  }
};

Uvedený kód vezme aktuální složku a výstupní soubory bude ukládat do podsložky public/.

Loader

Loadery jsou určeny pro otevření a zpracování souborů.

Takový html-loader umí zpracovávat HTML kód. V příkladu výše jsme používali css-loadersass-loader, jejichž účel už asi nemusím vysvětlovat.

Plugin

Pluginem se ve Webpacku rozumí cokoliv, co má širší funkčnost než jen zpracování souborů. Pluginy se typicky integrují do procesu sestavování a nějak jej ovlivňují. To loadery neumí.

Plugin mini-css-extract-plugin z našeho příkladu zařídil ukládání stylů do zvláštního CSS souboru.

Modul

Modulem se rozumí kousek kódu, který slouží jako samostatná komponenta.

Nemusí jím být jen soubor volaný zápisem import v JavaScriptu, ale cokoliv podobného, i v jiných jazycích. Například @import v LESSu či Sassu nebo obrázek stahovaný díky tomu, že v HTML zapíšeme <img src="…">.

Dependency graph (strom závislostí)

Webpack si interně vede strom závislostí, tedy vztahy jednotlivých souborů. Netýká se to opět jen těch javascriptových, ale jakýchkoliv jiných, které se v aplikaci používají.

Hot Module Replacement

Tahle funkce Webpacku by se dala přeložit jako „rychlá náhrada modulů“. Jde o to, že vám při vývoji aplikace vyměňuje naživo v prohlížeči jen ty kousky kódu, které jste upravili.

Zároveň to vkládá všechny změny kódu rovnou do verze běžící v prohlížeči. Nemusíte tedy obnovovat stránku a je to při práci na projektu krásně rychlé. Více informací je na Webpack.js.org.

Mód běhu

Webpack umožňuje běh v produkčním režimu (production), kdy výstupní soubory například automaticky minifikuje. To se hodí pro běh v ostrých, veřejných prostředích.

Můžeme si to ale přepnout do vývojářského režimu (development), kdy se neminifikuje a obecně dovoluje snadnější ladění chyb.

V konfiguračním souboru to vypadá takto:

module.exports = {
  mode: 'development'
};

Při běhu na příkazovce pak následovně:

webpack --mode=development

Více informací najdete na Webpack.js.org.

Teď už jen pár odkazů k dalšímu studiu a končíme.

Odkazy

V češtině:

V angličtině:

Znáte nějaké další zajímavé zdroje k Webpacku? Neváhejte napsat do komentářů nebo na sociální sítě.