Tools Webpack

Π’Π΅Π³ΠΈ

ΠΏΠΎΠ»Π½Ρ‹ΠΉΠΊΠΎΠ½Ρ„ΠΈΠ³ - полная вСрсия ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° webpack

НаписаниС Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ прилоТСния

Π­Ρ‚ΠΎΡ‚ скрипт Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ сообщСния Π² JSON-Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅

Post.js

export default class Post {
   constructor(title, img) {
      this.title = title;
      this.img = img;
      this.date = new Date();
   }
 
   toString() {
      return JSON.stringify({
         title: this.title,
         date: this.date.toJSON(),
         img: this.img,
      });
   }
}

Π­Ρ‚ΠΎΡ‚ скрипт ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²ΡƒΡŽ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΡƒ сообщСния ΠΈ Π²Ρ‹Π²ΠΎΠ΄ Π² консоль

index.js

const post = new Post("Webpack Post Title");
 
console.log("post to string", post.toString);

Π£ΠΆΠ΅ этот скрипт Π½Π΅ связан с Ρ€Π°Π±ΠΎΡ‚ΠΎΠΉ самого сайта - ΠΎΠ½ считаСт ΠΊΠ»ΠΈΠΊΠΈ Π½Π° страницС ΠΈ позволяСт Π½Π°ΠΌ ΠΈΡ… вывСсти Π² Π½ΡƒΠΆΠ½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚

Analytics.js

function createAnalytics() {
   let counter = 0;
   let isDestroyed = false;
 
   const listener = () => counter++;
 
   document.addEventListener("click", listener);
 
   return {
      destroy() {
         document.addEventListener("click", listener);
         isDestroyed = true;
      },
      getClicks() {
         if (isDestroyed) {
            return "Analytics is destroyed";
         }
         return counter;
      },
    };
}
 
window.analytics = createAnalytics();

Π’ΡƒΡ‚ ΡƒΠΆΠ΅ Π² ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌ порядкС ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ скрипты ΠΈ создаём основу сайта

index.html

<!DOCTYPE html>
<html lang="en">
 
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Webpack</title>
   <script src="analytics.js"></script>
</head>
 
<body>
   <div class="container">
      <h1>WP Course</h1>
   </div>
 
   <script src="Post.js"></script>
   <script src="index.js"></script>
</body>
 
</html>

А Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ с этим ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π½Π΅ Ρ‚Π°ΠΊ:

  • Нам Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ ΠΎΡ‡Π΅Π½ΡŒ ΠΌΠ½ΠΎΠ³ΠΎ скриптов Π² наш index.html
  • Нам Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Π½Ρ‹Ρ… скриптов ΠΊ страницС (ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π² Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌ порядкС Π²Ρ‹Π»Π΅Π·Π΅Ρ‚ ошибка)

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ прилоТСния

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ node, Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈ установим Π² дальнСйшСм Webpack

npm init

Установка Webpack

УстанавливаСм webpack для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ (-D)

npm install -D webpack webpack-cli
  • webpack - это сам основной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» webpack
  • webpack-cli - это Π΅Π³ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Π² консоли

Базовая настройка Webpack

Π­Ρ‚ΠΎ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ для запуска webpack

ΠΏΠΎΠ»Π½Ρ‹ΠΉΠΊΠΎΠ½Ρ„ΠΈΠ³ webpack.config.js

// Π­Ρ‚ΠΎ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ…Ρ€Π°Π½ΠΈΡ‚ Π² сСбС ΠΏΡƒΡ‚ΡŒ Π΄ΠΎ нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°
const path = require("path");
 
// WP ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π² сСбя Ρ‚Π΅ ΠΎΠΏΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ сюда вставим ΠΈ ΠΏΠΎ Π½ΠΈΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ наш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚
module.exports = {
   // Π£ΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈ Π±ΡƒΠ΄Π΅Ρ‚ всё ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ
   entry: "./src/index.js",
   // ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π²Ρ‹Π²ΠΎΠ΄Π° webpack
   output: {
      // Имя Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π°
      filename: "bundle.js",
      // Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ: ΠΏΡƒΡ‚ΡŒ Π΄ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΈ имя ΠΏΠ°ΠΏΠΊΠΈ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π±ΡƒΠ΄ΡƒΡ‚ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ Ρ„Π°ΠΉΠ»Ρ‹
      path: path.resolve(__dirname, "dist"), //__dirname - систСмная пСрСмСнная, которая ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π½Π° Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
   },
};

Команда для Π΅Π΄ΠΈΠ½ΠΎΡ€Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π° компиляции webpack

webpack

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ послС ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° ΠΊ index.html webpack скомпилируСт Ρ„Π°ΠΉΠ» со всСми экспортами ΠΈ ΠΈΠΌΠΏΠΎΡ€Ρ‚Π°ΠΌΠΈ. ΠŸΠ΅Ρ€Π²Ρ‹ΠΌΠΈ Π² Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ всСгда ΠΈΠ΄ΡƒΡ‚ ΠΈΠΌΠΌΠΈΡ‚Π°Ρ†ΠΈΠΈ экспортов ΠΈ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΎΠ² ΠΈ сами exports/imports, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ Π΄Π΅Π»Π°Π»ΠΈ. Π£ΠΆΠ΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΡ‚ΠΎΠΌ ΠΈΠ΄Ρ‘Ρ‚ сам ΠΊΠΎΠ΄.

index.html

<script src="bundle.js"></script>

ΠŸΠ°Ρ‚Ρ‚Π΅Ρ€Π½Ρ‹

Но Π² ΠΏΡ€ΠΎΡˆΠ»ΠΎΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π΅ Ρƒ нас Π²Ρ‹ΠΏΠ°Π΄Π°Π» Ρ„Π°ΠΉΠ» Analytics.js, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΎΠ½ Π½Π΅ Π±Ρ‹Π» Π½ΠΈΠΊΠ°ΠΊ связан Ρ‡Π΅Ρ€Π΅Π· ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ с основной Ρ‚ΠΎΡ‡ΠΊΠΎΠΉ Π²Ρ…ΠΎΠ΄Π°. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡŽ, ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ нСсколько Ρ‚ΠΎΡ‡Π΅ΠΊ Π²Ρ…ΠΎΠ΄Π° (ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ нСсколько Ρ‡Π°Π½ΠΊΠΎΠ²) ΠΈ Π·Π°Π΄Π°Ρ‚ΡŒ ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ для ΠΈΠΌΠ΅Π½ΠΈ Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ²

webpack.config.js

module.exports = {
   mode: "development",
   entry: {
      // Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ нСсколько Ρ‚ΠΎΡ‡Π΅ΠΊ Π²Ρ…ΠΎΠ΄Π° Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
      main: "./src/index.js", // основной Ρ‡Π°Π½ΠΊ
      analytics: "./src/analytics.js", // ΠΏΠΎΠ±ΠΎΡ‡Π½Ρ‹ΠΉ Ρ‡Π°Π½ΠΊ
   },
   output: {
		// Π’ΡƒΡ‚ ΡƒΠΆΠ΅ задаётся ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ [name]
		filename: "[name].bundle.js",
		path: path.resolve(__dirname, "dist"),
   },
};

И Ρ‚Π°ΠΊ ΠΆΠ΅ Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ скриптов Π² HTML-Ρ„Π°ΠΉΠ»

Однако ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΡ‚ΡŒΡΡ с Ρ‚ΠΎΠΉ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΠΉ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΎΠ±Π½ΠΎΠ²ΠΈΠ»ΠΈ скрипт, Π° ΠΎΠ½ со своим ΠΈΠΌΠ΅Π½Π΅ΠΌ ΡƒΠΆΠ΅ Π·Π°Ρ…ΡΡˆΠΈΡ€ΠΎΠ²Π°Π»ΡΡ Ρƒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅ ΠΈ ΡƒΠΆΠ΅ Π½Π΅ обновляСтся - это ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ Π½Π΅ΠΎΠΆΠΈΠ΄Π°Π½Π½Ρ‹ΠΌ ΠΏΠΎΠ»ΠΎΠΌΠΊΠ°ΠΌ, поэтому стоит Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‰Ρ‘ ΠΎΠ΄ΠΈΠ½ ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡΠ½ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒΡΡ Π½Π° Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΌ содСрТимом Ρ„Π°ΠΉΠ»Π°

[contenthash] - Π±ΡƒΠ΄Π΅Ρ‚ Π΄Π°Π²Π°Ρ‚ΡŒ имя, ΠΎΡΠ½ΠΎΠ²Ρ‹Π²Π°ΡΡΡŒ Π½Π° Π΅Π³ΠΎ Ρ…ΡΡˆΠ΅

webpack.config.js

output: {
   filename: "[name].[contenthash].js",
   path: path.resolve(__dirname, "dist"),
},

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ Ρ„Π°ΠΉΠ»

ΠŸΠ»Π°Π³ΠΈΠ½Ρ‹

Для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° установим ΠΏΠ»Π°Π³ΠΈΠ½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт Π²Π΅Π±ΠΏΠ°ΠΊΡƒ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ JS-Ρ„Π°ΠΉΠ»Ρ‹, Π½ΠΎ ΠΈ HTML со всСми Π½ΡƒΠΆΠ½Ρ‹ΠΌΠΈ Π²Ρ…ΠΎΠ΄Π½Ρ‹ΠΌΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ

Установка ΠΏΠ»Π°Π³ΠΈΠ½Π°:

npm install -D html-webpack-plugin

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π°: webpack.config.js

const path = require("path");
 
// ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° Π² Π²Π΅Π±ΠΏΠ°ΠΊ
const HTMLWebpackPlugin = require("html-webpack-plugin");
 
module.exports = {
   mode: "development",
   entry: {
      // Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ нСсколько Ρ‚ΠΎΡ‡Π΅ΠΊ Π²Ρ…ΠΎΠ΄Π° Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
      main: "./src/index.js", // основной Ρ‡Π°Π½ΠΊ
      analytics: "./src/analytics.js", // ΠΏΠΎΠ±ΠΎΡ‡Π½Ρ‹ΠΉ Ρ‡Π°Π½ΠΊ
   },
   output: {
      filename: "[name].[contenthash].js",
      path: path.resolve(__dirname, "dist"),
   },
   // Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ Π·Π°Π΄Π°Ρ‘ΠΌ список ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π² Π²Π΅Π±ΠΏΠ°ΠΊ
   plugins: [
      new HTMLWebpackPlugin() // ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½ Π² Π²Π΅Π±ΠΏΠ°ΠΊΠ΅
   ]
};

Как ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ, сам ΠΏΠ»Π°Π³ΠΈΠ½ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ index.html ΠΈΠ· ΠΈΠΌΠ΅ΡŽΡ‰Π΅Π³ΠΎΡΡ Π² src ΠΈ подставляСт всС Π½ΡƒΠΆΠ½Ρ‹Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ скриптов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π² свою ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΡŽΡ‚ΡΡ со своим Ρ…Π΅ΡˆΠ΅ΠΌ

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ внутрСнности Ρ‚Π΅Π³ΠΎΠ² Π² HTML

webpack.config.js

plugins: [
   new HTMLWebpackPlugin({
      title: 'webpack valery' // Π΄Π°Π»ΠΈ Ρ‚Π°ΠΉΡ‚Π»
   })
]

Π Π°Π±ΠΎΡ‚Π° с HTML

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΠ»Π°Π³ΠΈΠ½Ρƒ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅Ρ‚ HTML, ΠΊΠ°ΠΊΠΎΠΉ Ρ„Π°ΠΉΠ» Π±ΡƒΠ΄Π΅Ρ‚ ΡΠ²Π»ΡΡ‚ΡŒΡΡ для Π½Π΅Π³ΠΎ Ρ‚Π΅ΠΌΠΏΠ»Π΅ΠΉΡ‚ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠ²Π»ΡΡ‚ΡŒΡΡ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ сайта. Бвойство template опрСдСляСт, Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΊΠ°ΠΊΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ основной HTML. Π’Π°ΠΊ ΠΆΠ΅ Π² основной HTML Π±ΡƒΠ΄ΡƒΡ‚ Π²Π»ΠΎΠΆΠ΅Π½Ρ‹ всС Π½ΡƒΠΆΠ½Ρ‹Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹

webpack.config.js

const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
 
module.exports = {
   mode: "development",
   entry: {
      main: "./src/index.js",
      analytics: "./src/analytics.js",
   },
   output: {
      filename: "[name].[contenthash].js",
      path: path.resolve(__dirname, "dist"),
   },
   plugins: [
      new HTMLWebpackPlugin({
         template: "./src/index.html", // ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ основной HTML
      })
   ]
};

ΠžΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ HTML Π² src (Π±Π΅Π· ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΎΠ²)

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Webpack</title>
</head>
<body>
   <div class="container">
      <h1>WP Course</h1>
   </div>
</body>
</html>

Π’ΠΎ , Ρ‡Ρ‚ΠΎ сгСнСрировал webpack (Π²Π΅Π±ΠΏΠ°ΠΊ сам Π΄ΠΎΠ±Π°Π²ΠΈΠ» ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ Π½Π° Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Π΅ скрипты)

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Webpack</title>
<script defer src="main.a4fbcc6c859c6c9cd2a2.js"></script><script defer src="analytics.b0d68796ad2563de4d6c.js"></script></head>
<body>
   <div class="container">
      <h1>WP Course</h1>
   </div>
</body>
</html>

ΠžΡ‡ΠΈΡΡ‚ΠΊΠ° ΠΏΠ°ΠΏΠΊΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

УстанавливаСм ΠΏΠ»Π°Π³ΠΈΠ½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ чистит ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΎΡ‚ Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ²

npm i -D clean-webpack-plugin

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π΅Π³ΠΎ

webpack.config.js

const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
 
// ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½-ΠΎΡ‡ΠΈΡΡ‚ΠΈΡ‚Π΅Π»ΡŒ
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
 
module.exports = {
   mode: "development",
   entry: {
      main: "./src/index.js",
      analytics: "./src/analytics.js",
   },
   output: {
      filename: "[name].[contenthash].js",
      path: path.resolve(__dirname, "dist"),
   },
   plugins: [
      new HTMLWebpackPlugin({
         template: "./src/index.html",
      }),
      // Новый ΠΏΠ»Π°Π³ΠΈΠ½
      new CleanWebpackPlugin(), // ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½
   ]
};

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π² ΠΏΠ°ΠΏΠΊΠ΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° чистятся Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹

Π‘Π±ΠΎΡ€ΠΊΠ° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°Π΄Π°Ρ‚ΡŒ свои собствСнныС ΠΊΠΎΠ½ΡΠΎΠ»ΡŒΠ½Ρ‹Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°Π±ΠΈΠ½Π΄ΠΈΡ‚ΡŒ ΠΏΠΎΠ΄ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠ΅ алиасы. ΠšΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ Π² Ρ„Π°ΠΉΠ»Π΅ package.json ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π² свойствС "scripts" Π·Π°Π΄Π°Ρ‚ΡŒ свои алисасы ΠΈ ΠΈΠΌ ΠΏΡ€ΠΈΡΠ²ΠΎΠΈΡ‚ΡŒ ΠΊΠΎΠ½ΡΠΎΠ»ΡŒΠ½ΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ

package.json

"scripts": {
	"dev": "webpack --mode development",
	"build": "webpack --mode production"
},

И Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ npm run ΠΌΡ‹ Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ запуск ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ скрипта (Ρ‚ΡƒΡ‚ - компиляция Π² development Ρ€Π΅ΠΆΠΈΠΌΠ΅)

npm run dev

автоматичСскаякомпиляция Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°Π΄Π°Ρ‚ΡŒ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡŽ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² Ρ„Π°ΠΉΠ»Π°Ρ…

"scripts": {
  "dev": "webpack --mode development",
  "build": "webpack --mode production",
  // создаём ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ, которая Π±ΡƒΠ΄Π΅Ρ‚ постоянно ΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΈ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹
  "watch": "webpack --mode development --watch"
},

ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚

ΠšΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ свойство context позволяСт Π½Π°ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ, ΠΎΡ‚ ΠΊΠ°ΠΊΠΎΠΉ Ρ‚ΠΎΡ‡ΠΊΠΈ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠ΄Ρ‚ΠΈ ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅. По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π²Π΅Π±ΠΏΠ°ΠΊ ориСнтируСтся ΠΎΡ‚ Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΉ ΠΏΠ°ΠΏΠΊΠΈ нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. Если ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ контСкст, Ρ‚ΠΎ всС ΠΏΡƒΡ‚ΠΈ, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ этого контСкста. Π­Ρ‚ΠΎ ΡƒΠ΄ΠΎΠ±Π½ΠΎ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΏΠΎΡ‡Ρ‚ΠΈ всС ΠΏΡƒΡ‚ΠΈ Π΄ΠΎ Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΌΡ‹ прописываСм Π²Π½ΡƒΡ‚Ρ€ΠΈ Ρ‚ΠΎΠΉ ΠΆΠ΅ ΠΏΠ°ΠΏΠΊΠΈ src

webpack.config.js

const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
 
module.exports = {
   // Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚, Π³Π΄Π΅ находятся исходники
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   output: {
      filename: "[name].[contenthash].js",
      path: path.resolve(__dirname, "dist"),
   },
   plugins: [
      new HTMLWebpackPlugin({
         template: "./index.html",
      }),
      new CleanWebpackPlugin(),
   ]
};

CSS-Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹

Π›ΠΎΠ°Π΄Π΅Ρ€Ρ‹ - это сущноси, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» Π²Π΅Π±ΠΏΠ°ΠΊΡƒ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ Π²ΠΈΠ΄Π°ΠΌΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²

УстанавливаСм ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ Π΄Π΅Π»ΠΎΠΌ Π΄Π²Π° Π»ΠΎΠ°Π΄Π΅Ρ€Π°

  • css-loader позволяСт ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ стили Π² JS
  • style-loader добавляСт стили Π² ΡΠ΅ΠΊΡ†ΠΈΡŽ HEAD Π² HTML
npm i -D style-loader css-loader

webpack.config.js

module.exports = {
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   output: {
      filename: "[name].[contenthash].js",
      path: path.resolve(__dirname, "dist"),
   },
   plugins: [
      new HTMLWebpackPlugin({
         template: "./index.html",
      }),
      new CleanWebpackPlugin(),
   ],
 
   // Π—Π°Π΄Π°Ρ‘ΠΌ Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹
   module: {
      rules: [
         {
			// Π’ΡƒΡ‚ задаётся ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ поиска Ρ„Π°ΠΉΠ»Π°
            // Ссли Π½Π°ΠΌ ΠΏΠΎΠΏΠ°Π΄Π°ΡŽΡ‚ΡΡ Ρ„Π°ΠΉΠ»Ρ‹ с Ρ‚Π°ΠΊΠΈΠΌ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ΠΌ
            test: /\.css$/,
            // Ρ‚ΠΎ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Π°ΠΊΠΈΠ΅ Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹
            // Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹ ΡΡ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ справа-Π½Π°Π»Π΅Π²ΠΎ
            // ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Π»ΠΎΠ°Π΄Π΅Ρ€ позволяСт ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ стили, Π²Ρ‚ΠΎΡ€ΠΎΠΉ добавляСт стили Π² ΡΠ΅ΠΊΡ†ΠΈΡŽ HEAD Π² HTML
            use: ['style-loader', 'css-loader'],
         }
      ],
   }
 
};

index.html

import Post from './Post';
import './styles/style.css';  // ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ стилСй
 
const post = new Post("Webpack Post Title");
 
console.log("post to string", post.toString);

style.css

.container {
    padding-top: 2rem;
    max-width: 1000px;
    margin: 0 auto;
}
 
h1 {
    text-align: center;
    color: red;
    font-weight: 700;
    font-size: 60px;
}

Π Π°Π±ΠΎΡ‚Π° с JSON

WP позволяСт Π½Π°ΠΌ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ json-Ρ„Π°ΠΉΠ»Ρ‹ Π±Π΅Π· Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… запросов ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΌ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΎΠΌ

// ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ JSON-Ρ„Π°ΠΉΠ»Π°
import json from './assets/json.json';
console.log('json: ', json);

Π Π°Π±ΠΎΡ‚Π° с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ

Π’ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ Π»ΠΎΠ°Π΄Π΅Ρ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Ρ„Π°ΠΉΠ»Ρ‹

npm install file-loader -g

Π’ΠΎ-Π²Ρ‚ΠΎΡ€Ρ‹Ρ…, Π½ΡƒΠΆΠ½ΠΎ ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ для Π½Π΅Π³ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»Π°. Π’ ΠΏΡ€Π°Π²ΠΈΠ»Π°Ρ… ΠΌΡ‹ ΡƒΠΊΠ°ΠΆΠ΅ΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°Ρ‚ΡŒΡΡ Π² нашСм ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅

webpack.config.js

module: {
   rules: [
      {
         test: /\.css$/,
         use: ['style-loader', 'css-loader'],
      },
      // ΠžΠΏΠΈΡΡ‹Π²Π°Π΅ΠΌ Π½ΠΎΠ²Ρ‹ΠΉ Π»ΠΎΠ°Π΄Π΅Ρ€ для WP
      {
		// ΠΏΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ:
         test: /\.(png|svg|jpg|gif)$/,
         // ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ:
         use: ['file-loader']
      }
   ],
}

ИспользованиС в JS

import WebpackLogo from './assets/webpack-logo.png';
 
const post = new Post("Webpack Post Title", WebpackLogo);

ИспользованиС Π² CSS (создаст Π² dist ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» с ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ)

.logo {
    background-image: url("../assets/webpack-logo.png");
    background-size: cover;
    height: 200px;
    width: 200px;
    margin: 0 auto;
}
<div class="logo"></div>

Π Π°Π±ΠΎΡ‚Π° со ΡˆΡ€ΠΈΡ„Ρ‚Π°ΠΌΠΈ

Π”ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° для Ρ€Π°Π±ΠΎΡ‚Ρ‹ со ΡˆΡ€ΠΈΡ„Ρ‚Π°ΠΌΠΈ: webpack.config.js

rules: [
   {
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
   },
   {
      test: /\.(png|jpe?g|gif)$/i,
      use: ['file-loader'],
   },
   // Π’ΡƒΡ‚ Π½ΡƒΠΆΠ½ΠΎ ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»Π° Ρ€Π°Π±ΠΎΡ‚Ρ‹ file-loader со ΡˆΡ€ΠΈΡ„Ρ‚Π°ΠΌΠΈ
   {
	   // Ρ‚ΠΈΠΏΡ‹ ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠ²
      test: /\.(ttf|eot|woff|woff2)$/,
      use: ['file-loader']
   }
],

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ стили с нашСго ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π° font.css

@font-face {
    font-family: 'Roboto';
    src: url('../assets/fonts/Roboto-Regular.ttf') format('truetype');
}

Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΠΌ Ρ„Π°ΠΉΠ» Π² наш основной. Π˜ΠΌΠΏΠΎΡ€Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΏΠΎΡ‡Ρ‚ΠΈ Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΊΠ°ΠΊ ΠΈ Π² WP style.css

@import "font.css";
 
body {
    font-family: 'Roboto', sans-serif;
}

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ CSS-Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ

ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ для css. Π­Ρ‚ΠΎ Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€ стилСй ΠΏΠΎΠ΄ Ρ€Π°Π·Π½Ρ‹Π΅ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹.

npm install normalize.css

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ Ρ‚Π°ΠΊ ΠΆΠ΅ Ρ‡Π΅Ρ€Π΅Π· ΠΈΠΌΠΏΠΎΡ€Ρ‚. ~ Π² Π½Π°Ρ‡Π°Π»Π΅ ΠΈΠΌΠ΅Π½ΠΈ модуля Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ Π½Π°ΠΌ ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ Π½ΡƒΠΆΠ½ΠΎ ΠΈΡΠΊΠ°Ρ‚ΡŒ Π² ΠΏΠ°ΠΏΠΊΠ΅: node_modules

@import "~normalize.css";

Π—Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π°

Π‘Ρ‚Π°Π½Π΄Π°Ρ€Ρ‚Π½ΠΎ наш ΠΏΠ°ΠΊΠ΅Ρ‚ ΠΈΠΌΠ΅Π΅Ρ‚ ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ Π²Ρ…ΠΎΠ΄Π½ΡƒΡŽ Ρ‚ΠΎΡ‡ΠΊΡƒ, которая ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π° Π² package.json, ΠΎΠ΄Π½Π°ΠΊΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°Ρ‰ΠΈΡ‚ΠΈΡ‚ΡŒΡΡ ΠΎΡ‚ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΎΠ΄Π½Ρƒ строчку

package.json

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",  // Π­Ρ‚ΠΎ свойство Π½ΡƒΠΆΠ½ΠΎ для ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ²
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "watch": "webpack --mode development --watch"
  },

А сСйчас наш ΠΏΠ°ΠΊΠ΅Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Ρ‰ΠΈΡ‰Ρ‘Π½ ΠΎΡ‚ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "private": true,  // Π­Ρ‚ΠΎ свойство Π΄Π΅Π»Π°Π΅Ρ‚ наш ΠΏΠ°ΠΊΠ΅Ρ‚ ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΌ
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "watch": "webpack --mode development --watch"
  },

Π Π°Π±ΠΎΡ‚Π° с XML-Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ

Установка Π»ΠΎΠ°Π΄Π΅Ρ€Π° XML

npm install -D xml-loader

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΡ€Π°Π²ΠΈΠ» Π½Π° XML

webpack.config.js

module: {
   rules: [
      {
         test: /\.css$/,
         use: ['style-loader', 'css-loader']
      },
      {
         test: /\.(png|jpe?g|gif)$/i,
         use: ['file-loader'],
      },
      {
         test: /\.(ttf|eot|woff|woff2)$/,
         use: ['file-loader']
      },
      // настройки для xml-loader
      {
         test: /\.xml$/,
         use: ['xml-loader']
      }
   ],
}

Π’Ρ‹Π²ΠΎΠ΄ Π² консоль ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

index.js

import json from './assets/json.json';
import xml from './assets/data.xml';
 
console.log('json: ', json);
console.log('XML: ', xml);

Π Π°Π±ΠΎΡ‚Π° с CSV-Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ

papaparse Π½ΡƒΠΆΠ΅Π½ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с парсингом Ρ„Π°ΠΉΠ»ΠΎΠ² csv-loader Π»ΠΎΠ°Π΄Π΅Ρ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΡƒΠΌΠ΅Π΅Ρ‚ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ csv Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ Ρ„Π°ΠΉΠ»ΠΎΠ²

npm i -d papaparse
npm i -D csv-loader

webpack.config.js

{
   test: /\.csv$/,
   use: ['csv-loader'],
}

Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ настройки

Бвойство resolve позволяСт Π½Π°ΠΌ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ для Webpack, Ρ‡Ρ‚ΠΎ Π΅ΠΌΡƒ Π½ΡƒΠΆΠ½ΠΎ ΠΈΡΠΊΠ°Ρ‚ΡŒ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. Π’ΠΎ Π΅ΡΡ‚ΡŒ, Ссли Π²Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ΅ свойство extensions Π±ΡƒΠ΄Π΅Ρ‚ пустоС, Ρ‚ΠΎ ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±ΡƒΠ΄Π΅ΠΌ всСгда ΠΏΡ€ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ Π² import Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ Ρ„Π°ΠΉΠ»ΠΎΠ². Если ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ Π² массив, Ρ‚ΠΎ WP Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΊΠ°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» с подходящим Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ΠΌ, Π΄Π°ΠΆΠ΅ Ссли Π² ΠΈΠΌΠΏΠΎΡ€Ρ‚Π΅ ΠΌΡ‹ Π΅Π³ΠΎ Π½Π΅ ΡƒΠΊΠ°ΠΆΠ΅ΠΌ

module.exports = {
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   output: {
      filename: "[name].[contenthash].js",
      path: path.resolve(__dirname, "public"),
   },
   resolve: {
      // Π’ΡƒΡ‚ ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡΠΊΠ°Π·Π°Ρ‚ΡŒ WP, ΠΊΠ°ΠΊΠΈΠ΅ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
      extensions: ['.js', '.json', '.png'],
   },
   devServer: {
      static: {
         directory: path.join(__dirname, 'public'),
      },
      compress: true,
      port: 9000,
      open: true
   },
// ....

Π‘ настройками Π²Ρ‹ΡˆΠ΅ наши ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π±Π΅Π· указания Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ

import Post from './Post';  // .js
import json from './assets/json';  // .json
import WebpackLogo from './assets/webpack-logo'; // .png

Π’Π°ΠΊ ΠΆΠ΅ присутствуСт свойство alias, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ позволяСт Π·Π°Π΄Π°Ρ‚ΡŒ псСвдоним для ΠΏΡƒΡ‚Π΅ΠΉ Π² Π½Π°ΡˆΠΈΡ… ΠΈΠΌΠΏΠΎΡ€Ρ‚Π°Ρ…

resolve: {
   extensions: ['.js', '.jsx', '.ts', '.tsx'],
   alias: {
      '@': path.resolve(__dirname, "src"),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utilities': path.resolve(__dirname, 'src/utilities'),
      '@modules': path.resolve(__dirname, 'src/modules')
   }
},
// ΠΈ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π΄Π°Ρ‚ΡŒ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΡƒΡ‚ΡŒ
import sayHi from './models/script';
// ΠΈΠ»ΠΈ Ρ‡Π΅Ρ€Π΅Π· алиасы ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½Ρ‹ΠΉ ΠΏΡƒΡ‚ΡŒ
import sayHic from '@models/script';
// @ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ src - Ρ‚Π°ΠΊ ΠΆΠ΅ сдСлаСт Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½Ρ‹ΠΉ ΠΏΡƒΡ‚ΡŒ
import sayHic from '@/models/script';

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ JS-Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ

npm i -S jquery

index.js

import * as $ from 'jquery';
$('pre').html(post.toString());

export default class Post {
   constructor(title, img) {
      this.title = title;
      this.img = img;
      this.date = new Date();
   }
 
   toString() {
      return JSON.stringify({
         title: this.title,
         date: this.date.toJSON(),
         img: this.img,
      }, null, 2); // Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ сюда ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π°
   }
}

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ

ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ρƒ нас Π΅ΡΡ‚ΡŒ Π΄Π²Π° Ρ„Π°ΠΉΠ»Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΡŽΡ‚ Π² сСбя jquery. ΠœΡ‹ столкнёмся с ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΠΉ, Ρ‡Ρ‚ΠΎ ΠΎΠ±Π° этих Ρ„Π°ΠΉΠ»Π° Π±ΡƒΠ΄ΡƒΡ‚ Π² сСбя ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ. Π­Ρ‚ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Ρ‚ ΠΊ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΏΡ€ΠΈΠ±Π°Π²ΠΊΠ°ΠΌ ΠΊ вСсу Ρ„Π°ΠΉΠ»ΠΎΠ²

index.js

import * as $ from 'jquery';
$('pre').html(post.toString());

analytics.js

import * as $ from 'jquery';
 
function createAnalytics() {
   let counter = 0;
   let isDestroyed = false;
 
   const listener = () => counter++;
 
   $(document).on("click", listener);
 
   return {
      destroy() {
         $(document).off("click", listener);
         isDestroyed = true;
      },
 
      getClicks() {
         if (isDestroyed) {
            return "Analytics is destroyed";
         }
         return counter;
      },
   };
}
 
window.analytics = createAnalytics();

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π² WP Π΅ΡΡ‚ΡŒ свойство, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ позволяСт Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. Π’ Π½Ρ‘ΠΌ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡ‚ΡŒ ΠΎΠ±Ρ‰ΠΈΠ΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ‡Π°Π½ΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΡΠ»ΡƒΠΆΠΈΡ‚ΡŒ своСго ΠΎΠ±Ρ€Π°Π·Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠΈ (Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ js, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ jquery)

module.exports = {
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   // ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ
   optimization: {
      splitChunks: {
         chunks: 'all'
      }
	},
// ....

Webpack-dev-server

devServer Π²Π΅Π±ΠΏΠ°ΠΊΠ° собираСт наш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΊΠ°ΠΊ ΠΈ ΠΏΡ€ΠΈ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΉ сборкС, Π½ΠΎ складываСт всС собранныС Ρ„Π°ΠΉΠ»Ρ‹ Π² ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΡƒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ позволяСт Π΅ΠΌΡƒ Π½Π΅ обновляя страницу ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ всС ΠΌΠΎΠ΄ΡƒΠ»ΠΈ ΠΈ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ измСнСния. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ сСрвСр WP ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹ΠΉ Π±ΠΈΠ»Π΄, Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ production сборку Π²Π΅Π±ΠΏΠ°ΠΊΠ°.

Если Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ, Ρ‚ΠΎ вмСсто -D Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ -g

npm i webpack-dev-server -D

Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ Π½ΠΎΠ²ΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ для запуска

package.json

"scripts": {
  "dev": "webpack --mode development",
  "build": "webpack --mode production",
  "watch": "webpack --mode development --watch",
  // Команда стартуСт сСрвСр Π²Π΅Π±ΠΏΠ°ΠΊΠ°
  "start": "webpack serve"
},

Π’ΡƒΡ‚ ΡƒΠΆΠ΅ достаточно для запуска Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ‚Π°ΠΊΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ:

npm start

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ процСсса, достаточно Π½Π°ΠΆΠ°Ρ‚ΡŒ ctrl+c

webpack.config.js

module.exports = {
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   output: {
      filename: "[name].[contenthash].js",
      path: path.resolve(__dirname, "public"),
   },
   // Бюда вставляСм Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΡŽ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΠ»Π°Π³ΠΈΠ½Π° devServer
   devServer: {
      static: {
         directory: path.join(__dirname, 'public'),
      },
      compress: true,  // Если Π½ΡƒΠΆΠ½ΠΎ компрСссия Ρ„Π°ΠΉΠ»Π°
      port: 9000,  // ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ ΠΏΠΎΡ€Ρ‚
      open: true // АвтоматичСски запускаСт страницу Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅
   },
   plugins: [
      new HTMLWebpackPlugin({
         template: "./index.html",
      }),
      new CleanWebpackPlugin(),
   ],
   module: {
      rules: [
         {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
         },
         {
            test: /\.(png|jpe?g|gif)$/i,
            use: ['file-loader'],
         },
         {
            test: /\.(ttf|eot|woff|woff2)$/,
            use: ['file-loader']
         },
         {
            test: /\.xml$/,
            use: ['xml-loader']
         }
      ],
   }
};

ΠšΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡ статичСских Ρ„Π°ΠΉΠ»ΠΎΠ²

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π½Π°ΡˆΠ΅ΠΌΡƒ WP ΠΊΡƒΠ΄Π° ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ статичСскиС Ρ„Π°ΠΉΠ»Ρ‹ (ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² HTML)

npm i -D copy-webpack-plugin
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Webpack</title>
   <link rel="stylesheet" href="styles/style.css">
   <!--добавляСм Ρ„Π°Π²ΠΈΠΊΠΎΠ½ΠΊΡƒ-->
   <link rel="icon" href="favicon.ico" type="image/icon">
</head>

webpack.config.js

// ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½
const CopyWebpackPlugin = require("copy-webpack-plugin");
 
// ....
 
plugins: [
   new HTMLWebpackPlugin({
      template: "./index.html",
   }),
   new CleanWebpackPlugin(),
   // И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ этот ΠΏΠ»Π°Π³ΠΈΠ½ пСрСнСсёт Ρ„ΠΎΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΡŽ Π² Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ
   new CopyWebpackPlugin({
      patterns: [
         {
            from: path.resolve(__dirname, 'src/favicon.ico'),
            to: path.resolve(__dirname, 'dist')
         }
      ],
   }),
],
 
// ....

Как ΠΈΡ‚ΠΎΠ³, ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ Ρ„Π°Π²ΠΈΠΊΠΎΠ½ΠΊΡƒ, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΠΈ Π² HTML

Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ CSS, HTML, JS

ΠœΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ CSS Π”Π°Π½Π½Ρ‹ΠΉ ΠΏΠ»Π°Π³ΠΈΠ½ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ CSS Ρ„Π°ΠΉΠ»Ρ‹ ΠΈ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎ ΠΈΡ… ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ

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

ΠŸΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΠΌ нСбольшиС настройки ΠΈ добавляСм ΠΏΠ»Π°Π³ΠΈΠ½ Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³

webpack.config.js

const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
 
// ....
 
plugins: [
   new HTMLWebpackPlugin({
      template: "./index.html",
   }),
   new CleanWebpackPlugin(),
   new CopyWebpackPlugin({
      patterns: [
         {
            from: path.resolve(__dirname, 'src/favicon.ico'),
            to: path.resolve(__dirname, 'dist')
         }
      ],
   }),
   // ДобавляСм ΠΏΠ»Π°Π³ΠΈΠ½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΌΠΈΠ½ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ CSS
   new MiniCSSExtractPlugin({
      // ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ ΠΈΠ· output ΠΏΡƒΡ‚ΡŒ ΠΈ мСняСм Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ Π½Π° '.css'
      filename: "[name].[contenthash].css",
}),
],
module: {
   rules: [
      {
         test: /\.css$/,
         // МСняСм 'style-loader' Π½Π° Π»ΠΎΠ°Π΄Π΅Ρ€ ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Π°
         use: [MiniCSSExtractPlugin.loader, 'css-loader']
      },
      {
         test: /\.(png|jpe?g|gif)$/i,
         use: ['file-loader'],
      },
      {
         test: /\.(ttf|eot|woff|woff2)$/,
         use: ['file-loader']
      },
      {
         test: /\.xml$/,
         use: ['xml-loader']
      },
      {
         test: /\.csv$/,
         use: ['csv-loader'],
      }
   ],
}

Π£Π±ΠΈΡ€Π°Π΅ΠΌ ΠΈΠ· ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ CSS, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΎΠ½ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒΡΡ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ

<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Webpack</title>
   <!--добавляСм Ρ„Π°Π²ΠΈΠΊΠΎΠ½ΠΊΡƒ-->
   <link rel="icon" href="favicon.ico" type="image/icon">
</head>

Π’ΠΎΡ‚ Ρ‚Π°ΠΊ выглядит Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ HTML-Ρ„Π°ΠΉΠ»

Π’ΡƒΡ‚ ΠΌΡ‹ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΠ»ΠΈ

  1. ΠΊΠ°ΠΊ сам ΠΏΠ»Π°Π³ΠΈΠ½, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π² Π½Π΅Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ
  2. Ρ‚Π°ΠΊ ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ Ρ€Π΅ΠΆΠΈΠΌΠ° для Π½Π°ΡˆΠΈΡ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈ Ссли ΠΌΡ‹ находимся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, Ρ‚ΠΎ Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ Π°ΠΊΡ‚ΠΈΠ²Π½Π° смСна ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ страницы

webpack.config.js

// Π­Ρ‚Π° пСрСмСнная Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² сСбС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ состояния, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ находится сайт Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
const isDev = process.env.NODE_ENV === "development";
 
// ...
 
devServer: {
   static: {
      directory: path.join(__dirname, 'dist'),
   },
   compress: true,
   port: 9000,
   open: true,
   // ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ страницу Ссли находимся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
   hot: isDev,
},
 
module: {
   rules: [
      {
         test: /\.css$/,
        // Π’Π°ΠΊ ΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π±ΠΎΠ»Π΅Π΅ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΠ»Π°Π³ΠΈΠ½, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ ΠΎΠ½ позволяСт Π² сСбя ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с самим Π»ΠΎΠ°Π΄Π΅Ρ€ΠΎΠΌ ΠΈ Π΅Π³ΠΎ опциями
         use: [{
            loader: MiniCSSExtractPlugin.loader,
            options: {
		// hot module reload - мСняСт сущности Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ
	    // Если находимся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°, Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ
               hmr: isDev,
               reloadAll: true
            }
         }, 'css-loader']
      },
 
// ....

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ смСны ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΉ, Π½ΡƒΠΆΠ½ΠΎ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠΌ для ΠΈΡ… смСны:

npm i -G cross-env

Π‘Ρ‚Ρ€ΠΎΡ‡ΠΊΠ°ΠΌΠΈ cross-env NODE_ENV=development ΠΌΡ‹ опрСдСляСм срСду нашСй Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ (ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½ ΠΈΠ»ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°). Π­Ρ‚ΠΎΡ‚ ΠΊΠΎΠ΄ Π² скриптах ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ Π½Π°ΠΌ всСгда ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ срСду, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΌΡ‹ находимся ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π½Π°ΡˆΠΈΡ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π²Π΅Π±ΠΏΠ°ΠΊΠ°

package.json

"scripts": {
  "dev": "cross-env NODE_ENV=development webpack --mode development",
  "build": "cross-env NODE_ENV=production webpack --mode production",
  "watch": "cross-env NODE_ENV=development webpack --mode development --watch",
  "start": "cross-env NODE_ENV=development webpack serve"
},

Π‘Π°ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½ для ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ CSS:

npm install css-minimizer-webpack-plugin --save-dev
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
 
// Π­Ρ‚Π° пСрСмСнная Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² сСбС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ состояния, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ находится сайт Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";
 
const optimization = () => {
   const config = {
      splitChunks: {
         chunks: 'all'
      }   }
 
   // Если Ρ€Π΅ΠΆΠΈΠΌ ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½Π°
   if (isProd) {
	   // Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ свойство minimizer с ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠΌ ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ
      config.minimizer = [
         new CssMinimizerPlugin() // сам ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ CSS
      ]
   }
 
   return config;
}
 
// ....
 
module.exports = {
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   // Π’ΡƒΡ‚ Π½ΡƒΠΆΠ½ΠΎ Π²Π»ΠΎΠΆΠΈΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая сгСнСрируСт наш ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ
   optimization: optimization(),
 
// ....

ΠœΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ JS

npm install terser-webpack-plugin --save-dev

webpack.config.js

// ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ JS
const TerserPlugin = require("terser-webpack-plugin");
 
// Π­Ρ‚Π° пСрСмСнная Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² сСбС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ состояния, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ находится сайт Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";
 
const optimization = () => {
   const config = {
      splitChunks: {
         chunks: 'all'
      }   }
 
   if (isProd) {
      config.minimizer = [
         new TerserPlugin(), // ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ JS
         new CssMinimizerPlugin(),
      ]
   }
 
   return config;
}

ΠœΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ HTML Π£ΠΆΠ΅ этот ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ ΠΌΠΈΠ½ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ HTML ΠΊΠΎΠ΄ ΠΏΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½Π°

webpack.config.js

// Если Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ Π² ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ½ Ρ€Π΅ΠΆΠΈΠΌΠ΅...
const isProd = process.env.NODE_ENV === "production";
 
// ....
 
plugins: [
   new HTMLWebpackPlugin({
	   template: "./index.html",
	   // Π’ΡƒΡ‚ ΡƒΠΆΠ΅ настраиваСм ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡŽ
	   minify: {
		   // ...Ρ‚ΠΎ сТимаСм всС ΠΏΡ€ΠΎΠ±Π΅Π»Ρ‹ Π² ΠΊΠΎΠ΄Π΅
	      collapseWhitespace: isProd
	   }
	}),
 
// ...

ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡ Less ΠΈ Sass

УстанавливаСм сам less, sass ΠΈ ΠΈΡ… Π΅Π³ΠΎ Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹ Π² наш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚

npm install less less-loader --save-dev
npm install sass-loader sass webpack --save-dev

Π”Π°Π»Π΅Π΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ less ΠΈ sass

ΠΏΠΎΠ»Π½Ρ‹ΠΉΠΊΠΎΠ½Ρ„ΠΈΠ³ wenpack.config.js

const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
 
// Π­Ρ‚Π° пСрСмСнная Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² сСбС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ состояния, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ находится сайт Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";
 
const optimization = () => {
   const config = {
      splitChunks: {
         chunks: 'all'
      }   }
 
   if (isProd) {
      config.minimizer = [
         new TerserPlugin(),
         new CssMinimizerPlugin(),
      ]
   }
 
   return config;
}
 
// эта функция Π±ΡƒΠ΄Π΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π°ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π°
const filename = ext => isDev ? `[name].${ext}` : `[name].[hash].${ext}`;
 
module.exports = {
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   optimization: optimization(),
   output: {
      filename: filename('js'),
      path: path.resolve(__dirname, "dist"),
   },
   resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
      alias: {
         '@': path.resolve(__dirname, "src"),
         '@components': path.resolve(__dirname, 'src/components'),
         '@utilities': path.resolve(__dirname, 'src/utilities')
      }
   },
   devServer: {
      static: {
         directory: path.join(__dirname, 'dist'),
      },
      compress: true,
      port: 9000,
      open: true,
      hot: isDev, // ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ страницу Ссли находимся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
   },
   plugins: [
      new HTMLWebpackPlugin({
         template: "./index.html",
         minify: {
            collapseWhitespace: isProd
         }
      }),
      new CleanWebpackPlugin(),
      new CopyWebpackPlugin({
         patterns: [
            {
               from: path.resolve(__dirname, 'src/favicon.ico'),
               to: path.resolve(__dirname, 'dist')
            }
         ],
      }),
      new MiniCSSExtractPlugin({
         // ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ ΠΈΠ· output
         filename: filename('css'),
      }),
   ],
   module: {
      rules: [
         {
            test: /\.css$/,
            use: [MiniCSSExtractPlugin.loader, 'css-loader']
         },
         // Π’ΡƒΡ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ SASS/SCSS
         {
            test: /\.s[ac]ss$/i,
            use: [
               "style-loader", // ΠΈΠ»ΠΈ MiniCSSExtractPlugin.loader
               "css-loader",
               "sass-loader",
            ],
         },
         // А Ρ‚ΡƒΡ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ LESS
         {
            test: /\.less$/i,
            use: [
               // compiles Less to CSS
               "style-loader", // ΠΈΠ»ΠΈ MiniCSSExtractPlugin.loader
               "css-loader",
               "less-loader",
            ],
         },
         {
            test: /\.(png|jpe?g|gif)$/i,
            use: ['file-loader'],
         },
         {
            test: /\.(ttf|eot|woff|woff2)$/,
            use: ['file-loader']
         },
         {
            test: /\.xml$/,
            use: ['xml-loader']
         },
         {
            test: /\.csv$/,
            use: ['csv-loader'],
         }
      ],
   }
};

Π‘Ρ‚ΠΈΠ»ΠΈ Less

@border: 1px solid #ccc;
 
.box {
  padding: 1rem;
  border-radius: 5px;
  margin-top: 1rem;
  border: @border;
 
  h2 {
    text-align: center;
    color: darkblue;
  }
}

Π‘Ρ‚ΠΈΠ»ΠΈ SCSS

$border: 1px solid #ccc;
 
.card {
  padding: 1rem;
  border-radius: 5px;
  margin-top: 1rem;
  border: $border;
 
  h2 {
    text-align: center;
    color: darkred;
  }
}

ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ стили Π² Ρ„Π°ΠΉΠ» скрипта index.js

import './styles/style.css';
import './styles/less.less';
import './styles/scss.scss';

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ

Π§Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠΊΡ€Π°Ρ‚ΠΈΡ‚ΡŒ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡŽΡ‰ΠΈΠΉΡΡ ΠΊΠΎΠ΄, ΠΌΠΎΠΆΠ½ΠΎ вынСсти Π΅Π³ΠΎ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π²ΠΊΠ»Π°Π΄Ρ‹Π²Π°Ρ‚ΡŒ измСнСния

ΠΏΠΎΠ»Π½Ρ‹ΠΉΠΊΠΎΠ½Ρ„ΠΈΠ³ webpack.config.js

const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
 
// Π­Ρ‚Π° пСрСмСнная Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² сСбС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ состояния, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ находится сайт Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";
 
const optimization = () => {
   const config = {
      splitChunks: {
         chunks: 'all'
      }   }
 
   if (isProd) {
      config.minimizer = [
         new TerserPlugin(),
         new CssMinimizerPlugin(),
      ]
   }
 
   return config;
}
 
// Π­Ρ‚Π° функция Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° Π² свойство, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Ρ…Ρ€Π°Π½ΠΈΡ‚ свСдСния ΠΎ Π»ΠΎΠ°Π΄Π΅Ρ€Π°Ρ… для ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»Π°Ρ…
const cssLoaders = (extra) => {
   const loader = [
      MiniCSSExtractPlugin.loader,
      'css-loader',
   ];
 
	// Ссли Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π΅ΡΡ‚ΡŒ, Ρ‚ΠΎ ΠΏΡƒΡˆΠΈΠΌ Π΅Π³ΠΎ Π² массив
   if(extra) loader.push(extra);
 
   return loader;
}
 
// эта функция Π±ΡƒΠ΄Π΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π°ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π°
const filename = ext => isDev ? `[name].${ext}` : `[name].[hash].${ext}`;
 
module.exports = {
   context: path.resolve(__dirname, "src"),
   mode: "development",
   entry: {
      main: "./index.js",
      analytics: "./analytics.js",
   },
   optimization: optimization(),
   output: {
      filename: filename('js'),
      path: path.resolve(__dirname, "dist"),
   },
   resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
      alias: {
         '@': path.resolve(__dirname, "src"),
         '@components': path.resolve(__dirname, 'src/components'),
         '@utilities': path.resolve(__dirname, 'src/utilities')
      }
   },
   devServer: {
      static: {
         directory: path.join(__dirname, 'dist'),
      },
      compress: true,
      port: 9000,
      open: true,
      hot: isDev, // ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ страницу Ссли находимся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
   },
   plugins: [
      new HTMLWebpackPlugin({
         template: "./index.html",
         minify: {
            collapseWhitespace: isProd
         }
      }),
      new CleanWebpackPlugin(),
      new CopyWebpackPlugin({
         patterns: [
            {
               from: path.resolve(__dirname, 'src/favicon.ico'),
               to: path.resolve(__dirname, 'dist')
            }
         ],
      }),
      new MiniCSSExtractPlugin({
         // ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ ΠΈΠ· output
         filename: filename('css'),
      }),
   ],
   module: {
      rules: [
         {
            test: /\.css$/,
            // Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ ΠΌΡ‹ просто Π²Ρ‹Π·Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π²ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π½ΡƒΠΆΠ½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³
            use: cssLoaders(),
         },
         {
            test: /\.s[ac]ss$/i,
            // Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ ΠΌΡ‹ просто Π²Ρ‹Π·Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π²ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π½ΡƒΠΆΠ½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€
            use: cssLoaders('sass-loader'),
         },
         {
            test: /\.less$/i,
            // Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ ΠΌΡ‹ просто Π²Ρ‹Π·Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π²ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π½ΡƒΠΆΠ½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€
            use: cssLoaders('less-loader'),
         },
         {
            test: /\.(png|jpe?g|gif)$/i,
            use: ['file-loader'],
         },
         {
            test: /\.(ttf|eot|woff|woff2)$/,
            use: ['file-loader']
         },
         {
            test: /\.xml$/,
            use: ['xml-loader']
         },
         {
            test: /\.csv$/,
            use: ['csv-loader'],
         }
      ],
   }
};

Babel

УстанавливаСм Π½ΡƒΠΆΠ½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ babel

npm install -D babel-loader @babel/core @babel/preset-env webpack

Π’Π°ΠΊ ΠΆΠ΅ Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΠΈΡ„ΠΈΠ»Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΈΡ‚ΡŒ соврСмСнныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ (async/await, get/set) ΠΏΠΎΠ΄ старыС стандарты

npm install --save @babel/polyfill

Ну ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π½ΠΎΠ²Ρ‹Π΅ ΠΏΡ€Π°Π²ΠΈΠ»Π° для Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ Ρ€Π°Π±ΠΎΡ‚Ρ‹ babel Π²Π½ΡƒΡ‚Ρ€ΠΈ webpack

webpack.config.js

// ....
 
module.exports = {
   context: path.resolve(__dirname, 'src'),
   mode: 'development',
   entry: {
	   // Ρ‚ΡƒΡ‚ ΠΊΠ°ΠΊ Ρ‚ΠΎΡ‡ΠΊΡƒ Π²Ρ…ΠΎΠ΄Π° опрСдСляСм массив, ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±ΡƒΠ΄ΡƒΡ‚ ΡΠ²Π»ΡΡ‚ΡŒΡΡ ΠΏΠΎΠ»ΠΈΡ„ΠΈΠ»Ρ‹ babel
      main: ['@babel/polyfill', './index.js'],
      analytics: './analytics.js',
   },
 
// ....
 
{
	// ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ js-Ρ„Π°ΠΉΠ»Ρ‹
	test: /\.m?js$/,
	// ΠΈΡΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π½ΠΎΠ΄-ΠΌΠΎΠ΄ΡƒΠ»ΠΈ ΠΈΠ· компиляции
	exclude: /node_modules/,
	use: {
		// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π»ΠΎΠ°Π΄Π΅Ρ€ babel
		loader: "babel-loader",
		options: {
			// Π² опциях опрСдСляСм прСсСты
			presets: ['@babel/preset-env']
		}
	}
}

package.json

{
  "name": "webpack",
  // ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π»ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ 0,25% Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ΠΎΠ², Π° всС ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ - ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π»ΠΈΡΡŒ
  "browserList": ">0.25%, not dead",
  "version": "1.0.0",
  "description": "",
// ...

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² для Babel

npm install --save-dev @babel/plugin-proposal-class-properties
{
   test: /\.m?js$/,
   exclude: /node_modules/,
   use: {
      loader: 'babel-loader',
      options: {
         presets: ['@babel/preset-env'],
         plugins: [
            '@babel/plugin-proposal-class-properties',
         ]
      },
   },
},
class Util {
   static id = Date.now();
}
 
console.log(Util.id); // Π²Ρ‹Π²Π΅Π΄Π΅Ρ‚ Π΄Π°Ρ‚Ρƒ

ΠŸΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½Ρ‹ΠΉ Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΏΠ»Π°Π³ΠΈΠ½ ΡƒΠΆΠ΅ Π²Ρ…ΠΎΠ΄ΠΈΡ‚ Π² preset-env

ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡ TypeScript

Для Π½Π°Ρ‡Π°Π»Π° компиляции Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ прСсСт Π½Π° Π’Π‘

npm install --save-dev @babel/preset-typescript

Π”Π°Π»ΡŒΡˆΠ΅ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ΄ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³

// ...
 
module.exports = {
   context: path.resolve(__dirname, 'src'),
   mode: 'development',
   entry: {
      main: ['@babel/polyfill', './index.js'],
      // Ρ‚ΡƒΡ‚ Π² качСствС Π²Ρ‚ΠΎΡ€ΠΎΠΉ Ρ‚ΠΎΡ‡ΠΊΠΈ Π²Ρ…ΠΎΠ΄Π° ΠΏΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ts (Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ этот Ρ„Π°ΠΉΠ» ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π»ΠΈ Π² ts ΠΈΠ· js)
      analytics: './analytics.ts',
   },
 
// ...
 
// Π­Ρ‚ΠΎ ΡƒΠΆΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»Π° для компиляции ts
{
   test: /\.ts$/,
   exclude: /node_modules/,
   use: {
      loader: 'babel-loader',
      options: {
         presets: [
            '@babel/preset-env',
            // добавляСм прСсСт Π½Π° ts
            '@babel/preset-typescript',
         ],
      },
   },
},
 
// ...

Π­Ρ‚ΠΎ сама Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠ°, пСрСдСланная Π² TS

import * as $ from 'jquery';
 
function createAnalytics(): Object {
   let counter = 0;
   let isDestroyed: boolean = false;
 
   const listener = (): number => counter++;
 
   $(document).on('click', listener);
 
   return {
      destroy() {
         $(document).off('click', listener);
         isDestroyed = true;
      },
 
      getClicks() {
         if (isDestroyed) {
            return 'Analytics is destroyed';
         }
         return counter;
      },
   };
}
 
window['analytics'] = createAnalytics();

Π’Π°ΠΊ ΠΆΠ΅ ΠΊΠ°ΠΊ ΠΈ Π² ΠΏΡ€ΠΎΡˆΠ»Ρ‹Ρ… случаях, Ρ‚ΡƒΡ‚ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³

// Π­Ρ‚ΠΎ ΠΎΠΏΡ†ΠΈΠΈ ΠΏΠΎΠ΄ Ρ‚ΠΈΠΏΡ‹ прСсСтов babel
const babelOptions = (ext) => {
   const options = {
      presets: [
         '@babel/preset-env',
      ],
   }
   if (ext) options.presets.push(ext);
   return options;
}
 
// ...
 
{
   test: /\.m?js$/,
   exclude: /node_modules/,
   use: {
      loader: 'babel-loader',
      options: babelOptions(),
   },
},
{
   test: /\.ts$/,
   exclude: /node_modules/,
   use: {
      loader: 'babel-loader',
      options: babelOptions('@babel/preset-typescript'),
	},
},

ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡ React JSX

npm install --save-dev @babel/preset-react
npm i react react-dom

webpack.config.js

entry: {
	// Ρ‚ΠΎΡ‡ΠΊΡƒ Π²Ρ…ΠΎΠ΄Π° Π² Π²Π΅Π±ΠΏΠ°ΠΊΠ΅ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Π½Π° '.jsx'
   main: ['@babel/polyfill', './index.jsx'],
   analytics: './analytics.ts',
},
 
// ....
// Π­Ρ‚ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»Π° для Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΈ компиляции JSX
{
   test: /\.jsx$/,
   exclude: /node_modules/,
   use: {
      loader: 'babel-loader',
      // УстанавлвиаСм прСсСт
      options: babelOptions('@babel/preset-react'),
   },
},

index.jsx

import './babel';
 
import './styles/style.css';
import './styles/less.less';
import './styles/scss.scss';
 
import React, { Component } from 'react';
import ReactDOM from 'react-dom/client';
 
 
class App extends Component {
   render() {
      return (
         <div className='container'>
            <h1>WP Course</h1>
            <hr />
            <div className='logo' />
            <hr />
            <hr />
            <pre />
            <hr />
            <div className='box'>
               <h2>Less</h2>
            </div>
            <hr />
            <div className='card'>
               <h2>SCSS</h2>
            </div>
         </div>
      );
   }
}
 
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(
   <React.StrictMode>
      <App />
   </React.StrictMode>,
);

Devtool

Π’Π°ΠΊ ΠΆΠ΅ Π² WP ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌΡ‹ компиляции ΠΏΠΎ ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Π΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ

Π’ ΠΊΠΎΠ½Ρ„ΠΈΠ³ WP Π½ΡƒΠΆΠ½ΠΎ Π²ΠΏΠΈΡΠ°Ρ‚ΡŒ свойство devtool, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ ΠΏΠΎ ΡƒΡΠ»ΠΎΠ²ΠΈΡŽ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΊΠΎΠΌΠΏΠ°ΠΉΠ»Π° ΠΊΠ°Ρ€Ρ‚

webpack.config.js

module.exports = {
   context: path.resolve(__dirname, 'src'),
   mode: 'development',
   // Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° Π±ΡƒΠ΄Π΅ΠΌ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚Ρ‹
   devtool: isDev ? 'source-map' : 'eval-cheap-source-map',

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΊΠ°Ρ€Ρ‚Ρ‹ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚, Π² ΠΊΠ°ΠΊΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ Π±Ρ‹Π»ΠΈ созданы стили ΠΈ Π½Π° ΠΊΠ°ΠΊΠΎΠΉ строкС ΠΎΠ½ΠΈ Ρ€Π°ΡΠΏΠΎΠ»Π°Π³Π°ΡŽΡ‚ΡΡ (ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ позволяСт Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ спСцифичСских Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ ΠΈΠ· Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π°)

И Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ исходник Π² самом Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅

ESLint

УстанавливаСм сам eslint ΠΈ babel-парсСр для Сслинта

npm i -D eslint-loader
 
npm i -D babel-eslint

Π”ΠΎΠ±Π°Π²ΠΈΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹ для JS ΠΈ Π·Π°ΠΊΠΈΠ½Π΅ΠΌ eslint-loader Π² ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡŽ JS

webpack.config.js

// Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Π΅ Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹
const jsLoaders = ext => {
   const loaders = [
      {
         loader: ['babel-loader'],
         options: babelOptions(),
      },
   ];
 
   if (ext) loaders.push(ext);
 
   return loaders;
};
 
// ....
 
{
   test: /\.js$/,
   exclude: /node_modules/,
   use: jsLoaders('eslint-loader'),
},

babel.js - создадим для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° ΠΎΠ΄Π½Ρƒ Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ

const unused = 10;

.eslintrc - создаём Π² ΠΊΠΎΡ€Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

{
	// Назначим парсСр ΠΏΠΎΠ΄ бэйбСль
  "parser": "babel-eslint",
  // Π‘ΠΊΠ°ΠΆΠ΅ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ΠΏΠ°Π΄Π°Π»ΠΈ Π²Π°Ρ€Π½ΠΈΠ½Π³ΠΈ, Ссли Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½Ρ‹ Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅
  "rules": {
    "no-unused-vars": "warn"
  },
  // Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ ES6
  "env": {
    "es6": true,
    "browser": true
  },
  "extends": [
    "eslint:recommended"
  ]
}

ДинамичСскиС ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° простых Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ

npm i -D lodash

ДинамичСскиС ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ Π½Π°ΠΌ Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ Π² любом участкС ΠΊΠΎΠ΄Π° ΠΈ сразу ΠΆΠ΅ Π΅Ρ‘ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ

babel.js

import('lodash').then(_ => {
   console.log('Lodash: ', _.random(10, 11, true));
});

Анализ Ρ„ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ сборки

npm iΒ webpack-bundle-analyzer -D
// ....
 
// ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ анализирования ΠΊΠΎΠ½Ρ„ΠΈΠ³Π°
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
 
// Π­Ρ‚ΠΎ список Π½Π°ΡˆΠΈΡ… ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π²ΠΈΡΠ΅Ρ‚ΡŒ ΠΎΡ‚
const plugins = () => {
   const base = [
      new HTMLWebpackPlugin({
         template: './index.html',
         minify: {
            collapseWhitespace: isProd,
         },
      }),
      new CleanWebpackPlugin(),
      new CopyWebpackPlugin({
         patterns: [
            {
               from: path.resolve(__dirname, 'src/favicon.ico'),
               to: path.resolve(__dirname, 'dist'),
            },
         ],
      }),
      new MiniCSSExtractPlugin({
         // ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ ΠΈΠ· output
         filename: filename('css'),
      }),
   ];
 
   if (isProd) base.push(new BundleAnalyzerPlugin());
 
   return base;
};
 
// ....
 
module.exports = {
   plugins: plugins(),
 
// ....

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Ρ‚ΡƒΡ‚ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ, сколько Π·Π°Π½ΠΈΠΌΠ°ΡŽΡ‚ мСста Ρ€Π°Π·Π½Ρ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π² нашСм ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅

Π›ΠΈΠ±ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ этого ΠΏΠ»Π°Π³ΠΈΠ½Π° Ρ‡Π΅Ρ€Π΅Π· скрипт

package.json

"scripts": {
  "stats": "webpack --json > stats.json && webpack-bundle-analyzer stats.json"

ΠŸΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ сборки

Папка ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:

ΠšΠΎΠ½Ρ„ΠΈΠ³:

const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
 
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
 
// Π­Ρ‚Π° пСрСмСнная Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² сСбС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ состояния, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ находится сайт Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
const isDev = process.env.NODE_ENV === 'development';
const isProd = process.env.NODE_ENV === 'production';
 
// эта функция опрСдСляСт ΠΏΠΎΠ΄ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ‚ΠΈΠΏ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ свою ΠΌΠΈΠ½ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡŽ Ρ„Π°ΠΉΠ»ΠΎΠ²
const optimization = () => {
   const config = {
      splitChunks: {
         chunks: 'all',
      },
   };
 
   if (isProd) {
      config.minimizer = [new TerserPlugin(), new CssMinimizerPlugin()];
   }
 
   return config;
};
 
// эта функция Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΎΠΏΡ†ΠΈΠΈ Π»ΠΎΠ°Π΄Π΅Ρ€ΠΎΠ²
const cssLoaders = extra => {
   const loader = [MiniCSSExtractPlugin.loader, 'css-loader'];
 
   if (extra) loader.push(extra);
 
   return loader;
};
 
// Π­Ρ‚ΠΎ ΠΎΠΏΡ†ΠΈΠΈ ΠΏΠΎΠ΄ Ρ‚ΠΈΠΏΡ‹ прСсСтов babel
const babelOptions = ext => {
   const options = {
      presets: ['@babel/preset-env'],
   };
 
   if (ext) options.presets.push(ext);
 
   return options;
};
 
// Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Π΅ Π»ΠΎΠ°Π΄Π΅Ρ€Ρ‹
// const jsLoaders = ext => {
//     const loaders = [
//        {
//           loader: ['babel-loader'],
//           options: babelOptions(),
//        },
//     ];
//
//     if (isDev) loaders.push(ext);
//
//     return loaders;
// };
 
// эта функция Π±ΡƒΠ΄Π΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π°ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π°
const filename = ext => (isDev ? `[name].${ext}` : `[name].[hash].${ext}`);
 
const plugins = () => {
   const base = [
      new HTMLWebpackPlugin({
         template: './index.html',
         minify: {
            collapseWhitespace: isProd,
         },
      }),
      new CleanWebpackPlugin(),
      new CopyWebpackPlugin({
         patterns: [
            {
               from: path.resolve(__dirname, 'src/favicon.ico'),
               to: path.resolve(__dirname, 'dist'),
            },
         ],
      }),
      new MiniCSSExtractPlugin({
         // ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ ΠΈΠ· output
         filename: filename('css'),
      }),
   ];
 
   if (isProd) base.push(new BundleAnalyzerPlugin());
 
   return base;
};
 
module.exports = {
   context: path.resolve(__dirname, 'src'),
   mode: 'development',
   devtool: isDev ? 'source-map' : 'eval-cheap-source-map',
   entry: {
      main: ['@babel/polyfill', './index.jsx'],
      analytics: './analytics.ts',
   },
   optimization: optimization(),
   output: {
      filename: filename('js'),
      path: path.resolve(__dirname, 'dist'),
   },
   resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
      alias: {
         '@': path.resolve(__dirname, 'src'),
         '@components': path.resolve(__dirname, 'src/components'),
         '@utilities': path.resolve(__dirname, 'src/utilities'),
      },
   },
   devServer: {
      static: {
         directory: path.join(__dirname, 'dist'),
      },
      compress: true,
      port: 9000,
      open: true,
      hot: isDev, // ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ страницу Ссли находимся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
   },
   plugins: plugins(),
   module: {
      rules: [
         {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
               loader: 'babel-loader',
               options: babelOptions(),
            },
         },
         {
            test: /\.ts$/,
            exclude: /node_modules/,
            use: {
               loader: 'babel-loader',
               options: babelOptions('@babel/preset-typescript'),
            },
         },
         {
            test: /\.jsx$/,
            exclude: /node_modules/,
            use: {
               loader: 'babel-loader',
               options: babelOptions('@babel/preset-react'),
            },
         },
         {
            test: /\.css$/,
            use: cssLoaders(),
         },
         {
            test: /\.s[ac]ss$/i,
            use: cssLoaders('sass-loader'),
         },
         {
            test: /\.less$/i,
            use: cssLoaders('less-loader'),
         },
         {
            test: /\.(png|jpe?g|gif)$/i,
            use: ['file-loader'],
         },
         {
            test: /\.(ttf|eot|woff|woff2)$/,
            use: ['file-loader'],
         },
         {
            test: /\.xml$/,
            use: ['xml-loader'],
         },
         {
            test: /\.csv$/,
            use: ['csv-loader'],
         },
      ],
   },
};