JavaScript: Webpack - krótkie wprowadzenie
Opublikowano ptk 26 czerwca 2020 w javascript • 4 min read
Wstęp
Webpack generuje tzw. pakiety (ang. bundles -> bundle.js) na podstawie wytworzonego tzw. drzewa zależności oraz dostosowanie ich do formatu czytelnego dla możliwie jak najszerszego zakresu przeglądarek internetowych - jest swego rodzaju kompilatorem powstałej treści na podstawie różnych formatów do takiego, który przyjmuje przeglądarka internetowa (js,html,css). W tym sensie działą podobnie do innych tzw. task runnerów (narzędzie do automatyzacji działań dokonywanych na plikach) jak Gulp
Istotną zaletą korzystania z Webpacka jest to, że każdy plik jest traktowany jako moduł (obraz, css, font, js etc). (CommonJS -> po stronie node.js i moduły z ES (klient) nie są dostępne dla wszystkich przeglądarek stąd potrzeba ich transpilacji)
Loader - przetwarza plik (nie-js) w ten sposób by mógł być dodane do drzewa zależności (np. css-loader, babel-loader, html-loader) - etap transpilacji
np. html-loader pozwala na modułowe tworzenie plików HTML (więcej na ten temat:SO - How can I provide parameters for webpack html-loader interpolation? )
Wtyczki - różnego rodzaju wtyczki pozwalają na osiągnięcie oczekiwanego efektu np. zapisanie reguł css do osobnego pliku css/po za plik bundle.js poprzez pracę na gotowych pakietach (np. extract text plugin [wydobywa css], webpack-uglify-js-plugin[miniaturyzuje js])
np. wtyczka purge-css pozbywa się nieużywanych klas CSS (więcej na ten temat: GH-repo purgecss-webpack-plugin)
Instalacja oraz użycie WebPacka
Inicjalizajca porojektu (stworzenie package.json)
npm init -y
Instalacja Wepacka w v.4 oraz cli v.4 jako developerska zależność
npm i webpack@4 --save-dev
npm i webpack-cli@3 --save-dev
Narzędzie nie jest dostępne globalnie zatem aby nie wywoływać go poprzez każdorazowe wprowadzeni ścieżki ./node_modules/.bin/webpack
można dodać webpacka do sekcji scripts w package.json
przypisując go do klucza np. start (powszechnie stosowana nazwa) + należy wskazać główny plik (wejścia) oraz nazwę pliku wyjścia (pod tą nazwą zostanie zapisany bundle)
{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "./node_modules/.bin/webpack app.js --output out.js"
}
}
Teraz wystarczy wpisać
npm start
::: Istnieje możliwość przeprowadzenia globalnej instalacji Webpacka, ale ta nie jest polecana (wówczas powyższy krok jest zbędny) npm i -g webpack
:::
Budowa paczki od punktu wejścia i dołącza odnaleziony kod do pliku wyjścia, a po drodze natrafia na instrukcję require(), która wskazuje na konkretne pliki i znajdujący się w nich kod -> w wyniku tego połączenia powstaje plik, który jest trudny do odczytu przez człowieka, ale jest czytelny dla node.js lub przeglądarki
Przykładowe użycie
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "./node_modules/.bin/webpack r2d2.js --output out.js"
},
// droidFinder.js
function findDroid(droid) {
console.log(`You: Is this ${droid}?\nObi Wan: This is not the droid you are looking for`);
}
module.exports = findDroid;
// r2d2.js
const findDroidFunc = require('./droidFinder');
findDroidFunc("R2D2")
//out.js
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){n(1)("R2D2")},function(e,t){e.exports=function(e){console.log(`You: Is this ${e}?\nObi Wan: This is not the droid you are looking for`)}}]);
-----------
>> node out.js
>> You: Is this R2D2?
Obi Wan: This is not the droid you are looking for
Tworzenie pliku konfiguracyjnego dla Webpacka
Istnieje możliwość konfiguracji Webpacka
przy pomocy odpowiedniego do tego utworzonego pliku = webpack.config.js
w którym należy zawrzeć informacje na temat wtyczek oraz zadań jakie powinny zostać przez to narzędzie wykonane
Prosta konfiguracja
Instalacja
npm i webpack@4 --save-dev
npm i webpack-cli@3 --save-dev
// webpack.config.js
const path = require('path'); // moduł node.js, który pozwala na pracę z module.exports
module.exports = { // konfiguracja eksportu
entry: './src/index.js', // wskazanie wejścia
output: { // wskazanie wyjścia
filename: 'main.js', // podanie nazwy pliku wyjściowego
path: path.resolve(__dirname, 'dist'), // moduł node.js wskazujący na ścieżkę pliku wyjściowego __dirname (przechowuje ścieżkę katalogu, w którym znajduje się plik)
},
};
więcej info na temat path.resolve() - zwraca bezwzględny adres na podstawie przekazanych argumentów (__dirname - przechowuje ścieżkę katalogu, w którym znajduje się plik, "nazwa_katalogu")
Tworzymy własną konfigurację w webpack.config.js
// package.json
>> wersja 1 <<
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --hot -d", // flaga --hot pozwala na zmianę modułów w trakcie pracy bez konieczności odświeżania -d -> debug
"build": "webpack -p" // webpack production [Minification using UglifyJsPlugin/Runs the LoaderOptionsPlugin]
},
=======================================
>> wersja 2 <<
"scripts": {
"start": "webpack --mode development --watch",
"build": "webpack --mode production",
"server": "webpack-dev-server --inline --hot"
},
>> Zależności <<
"devDependencies": {
"@babel/core": "^7...",
"@babel/preset-env": "^7...",
"babel-loader": "^8...",
"webpack": "^4...",
"webpack-cli": "^3...",
"webpack-dev-server": "^3...",
"style-loader": "...",
"css-loader": "...",
"saas-loader": "..."
}
Umożliwia zastsowowanie komend -> nmp start/ npm build/ npm server
więcej info na webpack production
//webpack.config.js
const path = require("path");
const entryPath = "sciezka/folderu/z_plikami";
const entryFile = "nazwa_pliku.js";
module.exports = {
watch: true, // obserwuj zmiany
entry: `./${entryPath}/js/${entryFile}`, // plik wejściowy
output: { // plik wyjściowy
filename: "out.js", // nazwa pliku wyjściowego
path: path.resolve(__dirname, `${entryPath}/build`) // folder wyjściowy/zapisu
},
devServer: { // tworzenie sewera (tu użyta zależność "webpack-dev-server")
contentBase: path.join(__dirname, `${entryPath}`), // informacja/ścieżka gdzie znajduje się statyczna treść np. index.html (path.join by stworzyć absolutną ścieżkę)
publicPath: "/build/", // stworzone pliki będą znajdować się w tym folderze
compress: true, // kompresja
port: 3001 // port na którym znajduje się serwer
},
module: { // właściwość modules z przypisanymi obiektami posiadającymi właściwość rules - te definiują sposób pracy z różnymi typami plików (tu użyta zależność "babel-loader"/"@babel/preset-env"/"@babel/core")
rules: [
{
test: /\.js$/, // zawiera wyrażenie regularne wskazujące na rodzaj pliku (rozszerzenia), które ma być objęte działaniem loadera
exclude: /node_modules/, // wykluczenie plików z folderu..
loader: "babel-loader"
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ] // css-loader importuje kod css do JS a style-loader - wstrzykuje CSS do HTML
},
{
test: /\.scss$/,
use: [ 'style-loader', 'css-loader', 'sass-loader' ] // saas-loader transpiluje saas na css
}
]
}
plugins: [ // wtyczki
new webpack.optimize.UglifyJsPlugin({ // wskazanie wtyczki
beautify: true, // konfiguracja
comments: false
})
]
};
opcjonalnie:
[...]
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
]
}
[...]
Źródła:
Webpack 3 tutorial PL by Overment
Zsh: command not found: webpack
Konfiguracja Webpack 2+ - część #3: pluginy