Webpack: Loader ve Plugin Kullanımları

Webpack giriş yazısında kurulum ve yapılandırma işlemlerine temel bir şekilde değinmiş ve bir örnekle de süreci pratiğe dökmeye çalışmıştık.

AA

Bu yazıda ise kaldığımız yerden devam ederek, ilgili örneğin kapsamını biraz daha genişletecek, loader ve plugin kullanımıyla detaylandırmaya çalışacağım.

Webpack: Loader ve Plugin

Webpack’in temel çekirdek konseptler (core concepts) dahilinde yetenekler sunduğunu ve bu yeteneklerin geliştirilebildiğine daha önce değinmiştim. Bu konseptlerden ilk olarak loader kullanımını örneğimize dahil edelim.

Loader

Webpack'in yapısal olarak JavaScript merkezinde hareket ettiğinden daha önce bahsetmiştim. Bu nedenle CSS (.css), SCSS (.scss) veya TS (.ts) gibi diğer kaynakların paketlenmesini istediğimizde webpack için harici derleme ve paketleme desteğine ihtiyaç duyarız. İş destek webpack için loader’lar ile sağlanır. Loader’lar webpack için belirtilen kaynakların compile ve/veya transform edilmesi işlemlerini yürüten ve bundle edilebilen node tabanlı (node-based) JavaScript modülleridirler. Diğer yandan, Vue yazı dizisine de atfen, Vue loader ile vue single-page component’leri (*.vue) de farklı loader yapılandırmaları ile ele almak mümkündür1.

Plugin’ler webpack için belkemiği (backbone) olarak ifade edilmektedirler ve webpack’in kendisi de webpack yapılandırmalarında kullanılan eklenti sistemi üzerine kuruludur. Loader’ların eksik kaldığı, müdahale edemediği her türlü durum için destek özelliği gösterirler. Dolayısıyla loader ve plugin kullanımı birbirini tamamlayan webpack özellikleridirler. Plugin tanımamaları da yine loader’lar gibi webpack.config.js içeriğinde gerçekleştirilir. Plugin’ler (eklentiler) argümanlar / opsiyonlar (arguments / options) alırlar2. Elbette bu işlemler yeni instance ile tanımlanır. Örnek olarak aşağıda bir eklenti tanımı iletitorum.

const HtmlWebpackPlugin = require('html-webpack-plugin'); // npm veya yarn ile indirilir
const webpack = require('webpack'); // ön tanımlı (built-in) eklentilere erişim sağlar
const path = require('path');

module.exports = {
  module: {
    rules: [
      {
        ... // loader tanımları
      }
    ]
  },
  plugins: [
    new webpack.ProgressPlugin(), // ön tanımlı (built-in) eklenti
    new HtmlWebpackPlugin({template: './src/index.html'}) // HtmlWebpackPlugin ile eriştiğimiz html-webpack-plugin eklentisi ayarları
  ]
};

Proje Yapılandırması

Kısa tanımların ardından, bir önceki yazıda geliştirmeye başladığımız örnek projemize loader ve plugin ekleyerek teorik bilgileri pratiğe dönüştürelim.

Dosya ve klasör yapımız son durumda (node modülleri; node_modules hariç) şu şekildeydi.

.
├── dist
│   ├── bundle.js
│   ├── css
│   ├── img
│   ├── js
│   └── view
├── package-lock.json
├── package.json
├── src
│   ├── css
│   ├── img
│   ├── index.js
│   ├── js
│   │   ├── bar.js
│   │   └── foo.js
│   └── layout
├── webpack.config.js
└── yarn.lock

10 directories, 8 files

Örnek işlemler için Bulma CSS framework ile ilerleyeceğim. İşleme alacağımız yeni klasörler ve dosyalarımızı oluşturalım. Son durumda proje içeriğimiz şöyle olsun:

.
├── dist
│   ├── bundle.js
│   ├── css
│   │   └── main.bundle.css
│   ├── img
│   ├── index.html
│   └── js
├── index.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── src
│   ├── img
│   │   └── logo.png
│   ├── index.js
│   ├── js
│   │   ├── bar.js
│   │   ├── foo.js
│   │   └── main.jsx
│   ├── layouts
│   │   ├── header.pug
│   │   ├── main.pug
│   │   └── top.pug
│   ├── sass
│   │   └── style.scss
│   └── templates
│       └── index.html
├── webpack.config.js
└── yarn.lock

10 directories, 19 files
git clone git@gitlab.com:ceaksan/webpack-test.git
yarn install
# ya da
npm install

Kısa tanımların ardından, bir önceki yazıda geliştirmeye başladığımız örnek projemize bir loader ekleyerek teorik bilgileri pratiğe dönüştürelim.

Webpack Bulma CSS Örneği
npm install bulma html-webpack-plugin mini-css-extract-plugin node-sass webpack webpack-cli --save-dev

Şimdi, ilgili loader’ları sırayla indirebiliriz.

npm install css-loader html-loader postcss-loader sass-loader style-loader babel-loader --save-dev

ELbette plugin ve loader indirme işlemlerinin yanı sıra bazı bağımlılıkların da yapılandırılması ve package.json dosyasına eklenmesi gerekmekte:

{
  "name": "webpack-test",
  "version": "1.0.0",
  "description": "webpack-test-example",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "webpack --mode development ./src/index.js",
    "build": "webpack --mode production ./src/index.js",
    "start": "webpack-dev-server --mode development --open"
  },
  "repository": {
    "type": "git",
    "url": "git://gitlab.com/ceaksan/webpack-test.git",
    "private": false
  },
  "dependencies": {
    "@babel/core": "^7.4.5",
    "@babel/preset-env": "^7.4.5",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.6",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "bulma": "^0.7.5",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^5.0.3",
    "css-loader": "^3.0.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.7.0",
    "node-sass": "^4.12.0",
    "postcss-loader": "^3.0.0",
    "react": "^16.0.0",
    "react-dom": "^16.8.6",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.34.0",
    "webpack-dev-server": "^3.7.1"
  },
  "devDependencies": {
    "webpack-cli": "^3.3.4"
  }
}

Bir sonraki aşamada webpack.config.js dosyasının loader ve plugin’ler için düzenlenmesi gerekiyor.

const path = require("path")
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.join(__dirname, "dist"),
    publicPath: 'http://localhost:8080'
  },
  devServer: {
    contentBase: "./dist"
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].bundle.css',
      template: './src/css/style.css',
    }),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './src/templates/index.html',
    }),
  ],
  module: {
    rules: [{
        test: /\.(js|jsx|mjs)$/,
        exclude: /node_modules/,
        use: [{
          loader: 'babel-loader',
          options: {
            presets: ["@babel/preset-env", "@babel/react"]
          }
        }],
      },
      {
        test: /\.s?[ac]ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false,
              sourceMap: true
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              config: {
                path: 'postcss.config.js'
              }
            }
          }
        ]
      },
      {
        test: /\.html$/,
        use: ['html-loader'],
      }
    ],
  },
  mode: "development"
}

Bu kurulumların ve yapılandırmaların ardından src klasörü içeriğindeki dosyalar dist içeriğine yapılandırılarak aktarılacaklardır. loader kullanımında, loader ilgili dosyanın okunmasını sağlarken plugin’ler ile projenin yapılandırılması sağlanır.

const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

Ek olarak, bağımlılıklar için ayrıca konfigürasyon dosyalarının da düzenlenmesi gerekmekte. .babelrc ve postcss.config.js dosyaları bu proje örneği için gerekli olan yapılandırmaları içermektedir. postcss.config.js içeriği şu şekildedir:

module.exports = {};

.babelrc içeriği ise şöyle:

{
  "presets": [
    "@babel/preset-env", "@babel/react"
  ]
}

Bu örnek sürecinde, ayrıca main.jsx dosyası üzerinden react dom ile index.html dosyasına şu eklemeyi yapabiliriz.

import React from "react";
import ReactDOM from "react-dom";

function tick() {
  const element = <strong>It is {new Date().toLocaleTimeString()}.</strong>;
  ReactDOM.render(element, document.getElementById("impl"));
}

setInterval(tick, 1000);

Örnek ile ilgili diğer tüm işlemler ve kod incelemeleri için GitLab reposu incelenebilir. Ayrıca aşağıda örnek ile ilişkili olarak bazı ek yazılar ve örnekler iletiyorum.

Örnekler

İleri Okumalar