JavaScript

Разбираемся с настройкой Webpack для любого проекта

Spread the love

Большинство разработчиков так или иначе взаимодействовали с webpack при работе с проектами на React, Angular или Vue. В большинстве подобных ситуаций хватает настроек по умолчанию, поэтому освоение самого webpack как правило откладывается на потом. И если это так для вас, это может быть не правильно, так как уже базовые знания настроек webpack могут значительно улучшить процесс разработки.

В этом уроке мы покажем простой пример, того как настроить проект с использованием webpack с нуля, и покажем различные аспекты базовой конфигурации.

webpack — это мощный сборщик проектов, который может быть очень эффективным при правильном использовании.

Почему все используют webpack?

Альтернативой использованию webpack является использование комбинации менеджеров задач, таких как grunt или gulp, со сборщиком пакетов, подобным browserify. Но что заставляет разработчика выбирать webpack, а не использовать его альтернативы?

Webpack решает задачу сборки более интегрированным и естественным образом. В browserify для этого вам придется использовать gulp/grunt и длинный список дополнительных модификаторов и плагинов. Webpack предлагает достаточно обширный функционал по умолчанию уже из коробки.

Webpack работает на основание файла конфигурации, в отличие от gulp/grunt, где мы должны писать код для выполнения своих задач. В зависимости от конфигурации он может делать правильные предположения о том, что вам необходимо сделать; как работать с различными модулями JS, как компилировать код и как управлять активами и так далее. Так же есть функция горячей перезагрузки проекта live-reload. Возможность замены выходных имен файлов именами хеш-файлов которые позволяет браузерам легко обнаруживать измененные файлы путем включения в имя файла специфичного для сборки хэша. И это лишь некоторые основные моменты, которые делают webpack лучшим выбором.

Особенности webpack

Базовые функции, некоторые из которых мы обсудим далее:

  • Загрузчики (Loaders)
  • Плагины (Plugins)
  • Использование разных конфигураций для разных окружений
  • Отложенная загрузка модулей
  • Удаление с помощью tree shaking забытого кода
  • Горячая замена модуля, которая позволяет обновлять код во время выполнения без необходимости полного обновления
  • Кэширование путем подстановки имен файлов хэшами

Настройка проекта

Начальные условия

Для продолжения этого урока нам потребуется установленный Node.js, в котором так же должен быть установлен менеджер пакетов npm. Затем мы установим yarn, которая является альтернативой npm, что даст дополнительные функциональные возможности и улучшить скорость установки дополнительных пакетов.

$ npm install -g yarn

Начальная структура каталогов

Мы начнем с создания структуры каталогов. Создайте папку для тестового проекта Webpack-Setup. Внутри нее инициализируйте проект с помощью команды yarn init, которая создаст для нас файл package.json.

Далее в ней создайте папку src. Затем зайдите в папку src и там создайте еще три папки: app, public, style.

  • src: тут будет размещается исходный код проекта.
  • src/app: здесь будут размещаться наши файлы JavaScript.
  • src/public: эта папка будет содержать ресурсы проекта и статические файлы.
  • src/style: в этой папке будут глобальные стили проекта.

Далее создадим файлы проекта.

Создайте пустой файл src/app/index.js этот файл будет главной точкой входа в наш проект.

Файл src/public/index.html основной шаблон проекта

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Webpack Setup</title>
    </head>
    <body>
    <h3>Simple Webpack Setup</h3>
    <app></app>
    </body>
</html>

Создайте пустой файл src/style/app.scss он нам пригодится позже.

Начальная конфигурация

Мы начнем с создания простого файла конфигурации webpack, которую мы будем постепенно развивать, добавляя больше функциональных возможностей. Эта простая конфигурация будет содержать только один очень важный плагин HtmlWebpackPlugin.

HtmlWebpackPlugin упрощает создание файлов HTML и может автоматически вставлять модули JavaScript в наш основной шаблон HTML.

Первым делом установим основные модули: webpack и webpack-dev-server (облегченный веб сервер для разработки).

$ yarn add webpack webpack-dev-server html-webpack-plugin -D

Так же нам будет нужен webpack-cli:

yarn add webpack-cli -D 

Теперь создадим файл конфигурации webpack. В корне проекта создайте файл webpack.config.js со следующим содержимым:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // Require  html-webpack-plugin plugin

module.exports = {
  entry: __dirname + "/src/app/index.js", // webpack entry point. Module to start building dependency graph
  output: {
    path: __dirname + '/dist', // Folder to store generated bundle
    filename: 'bundle.js',  // Name of generated bundle after build
    publicPath: '/' // public URL of the output directory when referenced in a browser
  },
  module: {  // where we defined file patterns and their loaders
      rules: [ 
      ]
  },
  plugins: [  // Array of plugins to apply to build chunk
      new HtmlWebpackPlugin({
          template: __dirname + "/src/public/index.html",
          inject: 'body'
      })
  ],
  devServer: {  // configuration for webpack-dev-server
      contentBase: './src/public',  //source of static assets
      port: 7700, // port to run dev-server
  } 
};

Начальная конфигурация представляет собой скелет нашего проекта со следующими частями.

  • entry — Указывает на точку входа в проект, и откуда нужно начать построение графа внутренних зависимостей проекта.
  • output — Указывает куда будут отправляться создаваемые файлы сборки и как называть эти файлы.
  • devServer — Набор параметров для использования webpack-dev-server.

Далее добавим команду start в файл package.json.

...
"scripts": {
  "start": "webpack-dev-server --history-api-fallback --inline --progress"
},
"dependencies": {
...

Затем мы можем запустить наше приложение с:

$ yarn start

В консоле должно отобразиться что то типа такого:

Затем вы можете перейти по адресу http://localhost:7700/, чтобы увидеть наше приложение.

Загрузчики

Загрузчики (loaders) — это специальные модули, которые используются для «загрузки» других модулей (написанных на другом языке). Так же они позволяют предварительно обрабатывать файлы по мере их импорта или «загрузки».

Таким образом, загрузчики в некотором роде похожи на «задачи» в других инструментах сборки и предоставляют собой мощный способ обработки шагов сборки.

Загрузчики могут преобразовывать файлы с одного языка на другой, например TypeScript в JavaScript или из sass в css. Они могут даже позволить нам делать такие вещи, как импорт файлов CSS и HTML непосредственно в наши модули JavaScript. Для их использование необходимо прописать нужные загрузчики в разделе module.rules файла конфигурации.

babel-loader

Этот загрузчик использует Babel для загрузки файлов ES2015. Мы установим babel-core, в который входит babel-loader. Также подключим модуль babel-preset-env, который компилирует ES2015+ в ES5 путем автоматического определения необходимых Babel плагинов и полифайлов. Для этого с начало установим их, командой:

$ yarn add babel-core babel-loader@7 babel-preset-env -D

Затем создаем файл .babelrc, в корне проекта, и в нем пропишем пресеты.

//.babelrc
{ "presets": [ "env" ] }

Теперь мы можем включить наш загрузчик в нашу конфигурацию для преобразования файлов Javascript. Это позволит нам использовать синтаксис ES2015 + в нашем коде (который будет автоматически конвертироваться в ES5 в окончательной сборки).

Настройка конфигурации

//webpack.config.js
...
module: {
      rules: [
          {
            test: /\.js$/,
            use: 'babel-loader',
            exclude: [
              /node_modules/
            ]
          }
      ]
  }
...

Тестирование результата

Внесите следующий код в файл src/app/index.js:

//src/app/index.js
class TestClass {
    constructor() {
        let msg = "Using ES2015+ syntax";
        console.log(msg);
    }
}

let test = new TestClass();

Приведенный выше фрагмент кода отобразит сообщение в консоли браузера: Using ES2015+ syntax. Далее мы продемонстрируем работу нескольких загрузчиков с популярными фреймворками, включая Angular (1.5+) и React.

raw-loader

Это загрузчик, который позволяет нам импортировать файлы в виде строки. Мы покажем это, импортировав шаблон HTML для использования в качестве angular компонента.

Добавим в наш проект Angular и загрузчик raw-loader:

yarn add angular
yarn add raw-loader -D

Добавьте следующий код в файл конфигурации webpack

//webpack.config.js
...
module: {
      rules: [
         ...,
          {
              test: /\.html/,
              loader: 'raw-loader'
          }
      ]
  },
  ...

В файл src/app/index.js внесите следующий код:

//src/app/index.js
import angular from 'angular';
import template from './index.tpl.html';

let component = {
    template // Use ES6 enhanced object literals.
}

let app = angular.module('app', [])
    .component('app', component)

В файл src/public/index.html внесите следующий код:

<!DOCTYPE html>
<html ng-app="app" lang="en" ng-cloak>
    <head>
        <meta charset="utf-8">
        <title>Webpack Setup</title>
    </head>
    <body>
    <h3>Simple Webpack Setup</h3>
    <app></app>
    </body>
</html>

А так же в каталоге src/app/ создайте новый файл index.tpl.html

//src/app/index.tpl.html
<h3>Test raw-loader for angular component</h3>

sass-loader

Загрузчик sass-loader помогает нам использовать стиль scss в нашем приложении. Для этого требуется модуль node-sass, который позволяет нам скомпилировать файлы .scss в css . Рекомендуется использовать его вместе с css-loader, чтобы превратить его в модуль JS и загрузчик стилей, которые добавят CSS в DOM, внедряя тег style.

Начнем с установки модулей:

$ yarn add sass-loader node-sass css-loader style-loader -D

Внесите следующие изменения в файл настроек webpack

//webpack.config.js
...
module: {
      rules: [
         ...,
          {
            test: /\.(sass|scss)$/,
            use: [{
                loader: "style-loader" // creates style nodes from JS strings
            }, {
                loader: "css-loader" // translates CSS into CommonJS
            }, {
                loader: "sass-loader" // compiles Sass to CSS
            }]
          }
      ]
  },
  ...

Далее внесите следующие изменения в src/style/app.scss:

//src/style/app.scss
$primary-color: #2e878a;
body {
    color: $primary-color;
}

Использование стилей

Для этого нам достаточно импортировать стили в шаблон, как показано ниже:

//src/app/index.js
...
import '../style/app.scss';
...

Плагины

Плагины являются основой webpack, так как по сути вся его работа построена на системе плагинов. Они значительно расширяют возможности загрузчиков.

Загрузчики выполняют предварительную обработку файлов любого формата. Они работают на уровне отдельных файлов во время или до создания пакета. После того как отработают загрузчики наступает очередь плагинов. Плагины как правило отрабатывают только одну функцию.

Плагины работают на уровне пакета или блока и обычно запускаются в конце процесса генерации пакета.

Плагины также могут изменять способ создания самих пакетов сборки и имеют более полный контроль, над процессом сборки. На рисунке ниже показано, как работают загрузчики и плагины.

Мы уже использовали html-webpack-plugin, теперь я покажу, как использовать некоторые распространенные плагины в нашем проекте.

DefinePlugin

DefinePlugin позволяет вам создавать глобальные константы, которые можно использовать во время компиляции. Это очень полезно для управления конфигурациями импорта, такими как ключи API и другими константами, которые можно легко менять под разные окружения. Лучший способ использовать этот плагин — создать файл .env с разными константами и получить к ним доступ в конфигурации с помощью пакета dotenv, после чего мы сможем напрямую ссылаться на эти константы в нашем коде.

$ yarn add dotenv -D

Затем создайте файл в корне проекта .env со следующим содержимым.

//.env
API_KEY=1234567890

Настройка файла конфигурации webpack:

...
const webpack = require('webpack');
require('dotenv').config()
...
plugins: [
    new webpack.DefinePlugin({  // plugin to define global constants
          API_KEY: JSON.stringify(process.env.API_KEY)
      })
]

Далее добавьте следующую строку в src/app/index.js:

...
console.log('API Key from Define Plugin:', API_KEY);
...

Должно в итоге получится что то типа такого:

webpack-dashboard

Это редко используемая панель инструментов CLI для webpack-dev-server. Плагин добавляет «красоту и порядок» в среду разработки, и вместо обычных журналов консоли мы видим привлекательную, легко интерпретируемую панель инструментов.

Установим плагин

$ yarn add webpack-dashboard -D

Внесем изменения в файл конфигурации:

//webpack.config.js
...
const DashboardPlugin = require('webpack-dashboard/plugin');
...
plugins: [
      ...
      new DashboardPlugin()
  ],
...

Затем мы отредактируем наш package.json, чтобы использовать плагин.

//package.json
...
"scripts": {
    "start": "webpack-dashboard webpack-dev-server --history-api-fallback --inline --progress"
  }
...

После запуска проекта командой yarn start мы должны увидеть что то типа такого:

Среды разработки

В этом последнем разделе мы сосредоточимся на том, как мы можем использовать webpack для управления различными конфигурациями среды окружения. Мы покажем как использовать плагины в зависимости от среды, которые предназначены либо для тестирования, или для разработки, или для продакшин в зависимости от предоставленных переменных. Мы будем полагаться на пакет dotenv. В зависимости от окружения у нас будут различаться использование таких инструментов как devtool и плагины: extract-text-webpack-plugin, UglifyJsPlugin и copy-webpack-plugin и другие.

  • devtool— Управляет генерацией source map.
  • copy-webpack-plugin — Копирует отдельные файлы или целые каталоги в каталог сборки. Этот плагин рекомендуется для использования в продакшин, чтобы копировать все активы в выходную папку.
  • uglifyjs-webpack-plugin — Используется для минимизации кода проекта. Рекомендуется использовать в продакшин, чтобы уменьшить размер окончательной сборки.

Инсталяция плагинов:

$ yarn add copy-webpack-plugin uglifyjs-webpack-plugin -D

Настройка файла конфигурации

Мы немного изменим нашу конфигурацию, чтобы создать требуемую нам функциональность. Мы также удалим DashboardPlugin, который, может, вызывать некоторые проблемы при минимизации.

const HtmlWebpackPlugin = require('html-webpack-plugin'); // Require  html-webpack-plugin plugin

const CopyWebpackPlugin = require('copy-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

const webpack = require('webpack');
require('dotenv').config()

const ENV = process.env.APP_ENV;
const isTest = ENV === 'test'
const isProd = ENV === 'prod';

function setDevTool() {  // function to set dev-tool depending on environment
    if (isTest) {
      return 'inline-source-map';
    } else if (isProd) {
      return 'source-map';
    } else {
      return 'eval-source-map';
    }
}


const config = {
  entry: __dirname + "/src/app/index.js",
  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js',
    publicPath: '/' 
  },
  devtool: setDevTool(),
  module: { 
    rules: [ 
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: [
          /node_modules/
        ]
      },
      {
        test: /\.html/,
        loader: 'raw-loader'
      },
      {
        test: /\.(sass|scss)$/,
        use: [{
            loader: "style-loader" // creates style nodes from JS strings
        }, {
            loader: "css-loader" // translates CSS into CommonJS
        }, {
            loader: "sass-loader" // compiles Sass to CSS
        }]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: __dirname + "/src/public/index.html",
      inject: 'body'
    }),
    new webpack.DefinePlugin({  // plugin to define global constants
        API_KEY: JSON.stringify(process.env.API_KEY)
    }),
  ],
  devServer: {
      contentBase: './src/public',
      port: 7700,
  } 
}                                                           
                 
if (isProd) {
    config.plugins.push(
        new UglifyJSPlugin(),
        new CopyWebpackPlugin([{
          from: __dirname + '/src/public'
      }])
    );
}; 

module.exports = config;                                        

Теперь если добавьте в файл .env следующую переменную:

APP_ENV=prod

легко увидеть что разница между размерами пакетами сборки до и после минификации огромна.

Заключение

Webpack, безусловно, является мощным помощником для разработки, и его очень легко настраивать под любые задачи. Эта статья демонстрирует лишь некоторые базовые возможности из большого количества всех возможностей webpack. Не пожалейте времени на изучении всего на что способен этот очень полезного инструмент.

Оригинал статьи: Setting up webpack for Any Project

Была ли вам полезна эта статья?
[44 / 3.2]

Spread the love
Editorial Team

View Comments

  • C:\Users\Рустам\Desktop\new-app>yarn start
    yarn run v1.22.0
    $ react-scripts start

    There might be a problem with the project dependency tree.
    It is likely not a bug in Create React App, but something you need to fix locally.

    The react-scripts package provided by Create React App requires a dependency:

    "webpack-dev-server": "3.10.1"

    Don't try to install it manually: your package manager does it automatically.
    However, a different version of webpack-dev-server was detected higher up in the tree:

    C:\Users\Рустам\Desktop\new-app\node_modules\webpack-dev-server (version: 3.10.3)

    Manually installing incompatible versions is known to cause hard-to-debug issues.

    If you would prefer to ignore this check, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
    That will permanently disable this message but you might encounter other issues.

    To fix the dependency tree, try following the steps below in the exact order:

    1. Delete package-lock.json (not package.json!) and/or yarn.lock in your project folder.
    2. Delete node_modules in your project folder.
    3. Remove "webpack-dev-server" from dependencies and/or devDependencies in the package.json file in your project folder.
    4. Run npm install or yarn, depending on the package manager you use.

    In most cases, this should be enough to fix the problem.
    If this has not helped, there are a few other things you can try:

    5. If you used npm, install yarn (http://yarnpkg.com/) and repeat the above steps with it instead.
    This may help because npm has known issues with package hoisting which may get resolved in future versions.

    6. Check if C:\Users\Рустам\Desktop\new-app\node_modules\webpack-dev-server is outside your project directory.
    For example, you might have accidentally installed something in your home folder.

    7. Try running npm ls webpack-dev-server in your project folder.
    This will tell you which other package (apart from the expected react-scripts) installed webpack-dev-server.

    If nothing else helps, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
    That would permanently disable this preflight check in case you want to proceed anyway.

    P.S. We know this message is long but please read the steps above :-) We hope you find them helpful!

    error Command failed with exit code 1.
    info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

    C:\Users\Рустам\Desktop\new-app>

  • статья полное гавно. Просто описан процесс. Копируй сюда, копируй туда, вот тебе чето, может подойдет. Понимания никакого не дает. ДАже жопу не подтереть данным руководством.

  • шрифтовое оформление кодов подбешивает

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

11 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

11 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago