Это отрывок из Программы React.js. Если вам нравится этот материал, ознакомьтесь с самой программой и, в частности, с курсом React.js Fundamentals, поскольку он совершенно бесплатный и содержит 12 видео, текст и актуальную учебную программу для работы. Это более линейный подход к изучению React.js и экосистемы React.js.

Позвольте мне предварить этот раздел, сказав, что Webpack - это сложно. Отчасти потому, что это чрезвычайно мощный инструмент, а отчасти потому, что документация ужасна. Если у вас есть опыт работы с другими инструментами, такими как Gulp или Grunt, это немного проще, но если нет, просто подождите, и станет легче. В этом курсе мы сосредоточимся на реальной сути Webpack и перейдем к более продвинутым функциям в других курсах.

Первые вопросы, которые вы должны задать себе, когда используете новый инструмент, - это «Почему эта штука существует?» и «Какую проблему решает эта штука?». Если вы не можете в конце концов ответить на эти два вопроса, вероятно, вам это не нужно. Итак, давайте ответим на эти вопросы с точки зрения Webpack.

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

Какую проблему решает эта штука? Подумайте, сколько раз нам нужно взять наш код и изменить его, чтобы он соответствовал тому, для чего используется браузер (обычный HTML, CSS и JavaScript). Если вы когда-либо использовали препроцессор CSS, такой как SASS или LESS, вы знаете, что вам нужно преобразовать код SASS / LESS в обычный CSS. Если вы когда-либо использовали CoffeeScript или какой-либо компилятор на языке JavaScript, вы знаете, что там также есть этап преобразования. Итак, в чем действительно проявляется Webpack, так это в том, что вы можете сообщить ему все преобразования, которые необходимо выполнить вашему коду, и он выполнит их и выведет для вас файл пакета, полный этих изменений (и некоторых других полезных вещей, таких как минификация, если вы хотите ).

В этом конкретном курсе мы собираемся сделать наши конфигурации Webpack довольно простыми, но в будущих курсах мы перейдем к более сложным темам.

Если вы думаете о процессе, о котором мы говорили выше, об идее взять ваш код и каким-то образом преобразовать его, а затем выплеснуть его - на самом деле есть три основных шага и три основные вещи, которые необходимо знать Webpack.

1) Webpack должен знать начальную точку вашего приложения или ваш корневой файл JavaScript.

2) Webpack необходимо знать, какие преобразования нужно сделать в вашем коде.

3) Webpack необходимо знать, в какое место он должен сохранить новый преобразованный код.

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

Первое, что нам нужно сделать, это создать файл, который будет содержать наши конфигурации Webpack. Удобно, чтобы этот файл назывался webpack.config.js и располагался в корневом каталоге нашего проекта.

Теперь, когда у нас есть файл, нам нужно убедиться, что этот файл экспортирует объект, который будет представлять наши конфигурации для Webpack. Если вы не знакомы с модулями JavaScript, я настоятельно рекомендую эту серию блогов от Preethi.

// In webpack.config.js
module.exports = {}

Теперь давайте пройдемся по нашему списку этих трех элементов и преобразуем их в код. Во-первых, сообщаем веб-пакету, где находится точка входа в наше приложение. Это довольно прямолинейно и выглядит так:

// In webpack.config.js
module.exports = {
  entry: [
    './app/index.js'
  ]
}

Все, что мы делаем, это присваиваем нашему объекту свойство entry и значение, которое представляет собой массив со строкой, которая указывает на наш корневой файл JavaScript в нашем приложении. Вы можете спросить, почему это массив, а не просто строка. Webpack позволяет вам иметь одну или несколько точек входа в ваше приложение. Если у вас есть только один, вы можете просто использовать строку. Если у вас есть больше, вы можете использовать массив. Я всегда по умолчанию использую массив, поэтому при необходимости могу легко добавить позже.

Теперь, когда мы сказали Webpack, с чего начать, нам нужно сказать ему, какие преобразования необходимо произвести. Здесь пригодятся загрузчики.

Допустим, мы почему-то все еще пишем CoffeeScript в 2016 году (ZING!). Нам понадобится способ превратить наш CoffeeScript в обычный JS. Похоже, идеальное место для загрузчика CoffeeScript. Первым делом нам нужно установить нужный нам загрузчик. Для этого мы будем использовать npm. В своем терминале вы должны запустить npm install - save-dev coffee-loader, который затем сохранит coffee-loader как зависимость разработчика в файле package.json. Затем нам нужно настроить наш файл webpack.config.js, чтобы он знал об этом конкретном преобразовании. Для этого нам сначала нужно добавить свойство module к объекту, который мы экспортируем в webpack.config.js, а затем это свойство модуля будет иметь свойство загрузчики, представляющие собой массив.

// In webpack.config.js
module.exports = {
  entry: [
    './app/index.js'
  ],
  module: {
    loaders: []
  }
}

Внутри этого массива загрузчиков мы (очевидно) собираемся поместить все наши различные загрузчики или преобразования, которые мы хотим выполнить.

Каждый загрузчик должен состоять из трех частей. Во-первых, для какого типа файла запускать конкретное преобразование. Например, мы не хотим выполнять преобразования CSS в файле JavaScript и наоборот. Следующий пункт - какие каталоги следует включить или исключить из преобразования. Например, мы не хотим запускать наши преобразования для чего-либо в нашей папке node_modules, поэтому у нас будет путь node_modules в качестве исключенного значения. Последнее, что мы хотим запустить - это конкретный загрузчик. Давайте посмотрим, как это выглядит.

// In webpack.config.js
module.exports = {
  entry: [
    './app/index.js'
  ],
  module: {
    loaders: [
      {test: /\.coffee$/, include: __dirname + '/app', loader: "coffee-loader"}
    ]
  },
}

Первое, что вы, вероятно, заметите, - это раздел test: / \. Js $ /. Это выглядит пугающе, если вы не привыкли к регулярным выражениям, но все, что он делает, это указывает Webpack запускать загрузчик кофе для всех расширений, которые заканчиваются на .coffee.

Затем include сообщает Webpack, какие каталоги нужно включить в наши преобразования. Вместо исключения node_modules я решил мыслить позитивно и включить каталог, который мы хотели бы преобразовать. Последний шаг очевиден. загрузчик сообщает Webpack, какое преобразование запускать для всех путей, соответствующих test RegEx и находящихся в включить каталог.

Как видите, шаги по включению дополнительных загрузчиков довольно просты. NPM устанавливает конкретный загрузчик, а затем добавляет новый объект в массив загрузчиков.

Теперь, когда мы выполнили шаги 1 и 2, у нас остался еще один шаг. На этом последнем шаге указывается, куда Webpack должен выводить новый преобразованный код.

// In webpack.config.js
module.exports = {
  entry: [
    './app/index.js'
  ],
  module: {
    loaders: [
      {test: /\.coffee$/, include: __dirname + '/app', loader: "coffee-loader"}
    ]
  },
  output: {
    filename: "index_bundle.js",
    path: __dirname + '/dist'
  },
}

Опять же, код здесь довольно понятен. filename - это имя файла, который собирается создать Webpack, который содержит наш новый преобразованный код. путь - это конкретный каталог, в который будет помещено новое имя файла (index_bundle.js). Если вы никогда раньше не видели __dirname, это просто ссылка на имя каталога, в котором находится исполняемый в данный момент скрипт.

Итак, теперь, когда запускается Webpack, наш код будет преобразован, и на него можно будет ссылаться в ourApp / dist / index_bundle.js. Что ж, это здорово, но теперь нам нужно разработать план, чтобы наш HTML-код ссылался на этот конкретный файл. Есть несколько вариантов, но большинство ужасно. Если мы посмотрим, как обычно структурированы обычные приложения, то обычно получается примерно следующее.

/app
  - components
  - containers
  - config
  - utils
  index.js
  index.html
/dist
  index.html
  index_bundle.js
package.json
webpack.config.js
.gitignore

Как видите, наш код, с помощью которого мы разрабатываем, находится в папке app, а наш преобразованный код - в папке dist папку. Теперь вы можете визуально увидеть проблему. Мы хотим изменить index.html, расположенный в папке app, но index .html файл, который браузер фактически будет использовать, находится в папке dist (потому что именно там мы также сообщили webpack выплюнуть трансформированный JS файл).

Первый способ решить эту проблему - просто управлять двумя файлами index.html, и всякий раз, когда вы меняете файл, расположенный в / app, копируйте / вставляйте его в файл, расположенный в / dist. Хотя это сработает, я больше не смогу смотреть жене в глаза, если мы это сделаем.

Второй вариант, мы могли бы найти способ, чтобы при запуске webpack наш /app/index.html копировался в / dist / index .html. Это звучит намного лучше, и окончательное решение будет похоже на это.

Как вы, наверное, догадались, уже существует инструмент Webpack, который позволяет нам делать нечто подобное. Вместо фактического копирования нашего файла index.html он просто будет использовать этот файл в качестве шаблона и создать новый файл index.html. Этот плагин является html-webpack-plugin. Как всегда, перед использованием вам необходимо запустить npm install - save-dev html-webpack-plugin. Теперь нам просто нужно указать webpack, что мы хотим с ним делать.

Во-первых, нам нужно создать новый экземпляр HTMLWebpackPlugin, и нам нужно будет указать три вещи. Во-первых, мы можем дать ему шаблон того, как мы хотим, чтобы новый созданный файл выглядел. Во-вторых, мы даем ему имя_файла или, ну, название того нового файла, который он создает. В-третьих, WebpackPluginConfig будет достаточно умен, чтобы определить имя файла выходных данных преобразованного кода (в данном случае мы вызываем index_bundle.js), а затем внедрить скрипт в ‹head› или ‹body› файла вновь созданный файл index.html. Итак, третий вариант - inject, и именно в него вы хотели бы внедрить этот скрипт - в «голову» или «тело».

Посмотрим, как выглядит весь код.

// In webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin')
var HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/index.html',
  filename: 'index.html',
  inject: 'body'
});
module.exports = {
  entry: [
    './app/index.js'
  ],
  module: {
    loaders: [
      {test: /\.coffee$/, include: __dirname + '/app', loader: "coffee-loader"}
    ]
  },
  output: {
    filename: "index_bundle.js",
    path: __dirname + '/dist'
  },
  plugins: [HTMLWebpackPluginConfig]
};

Вы заметите, что мы добавили еще несколько шагов. В верхней части файла мы создаем новый экземпляр HtmlWebpackPlugin и даем ему три варианта. template указывает на наш обычный файл index.html, расположенный в каталоге нашего приложения. filename просто говорит, что мы хотим сохранить имя index.html. inject указывает, что нужно внедрить скрипт, который ссылается на имя выходного файла (index_bundle.js) наших загрузчиков, и поместить его в тело этого вновь созданного HTML-файла. Наконец, мы добавляем созданную нами переменную HTMLWebpackPluginConfig как элемент массива подключаемых модулей в конфигурацию нашего веб-пакета.

Теперь, когда мы запускаем webpack из командной строки, внутри нашей папки dist будут два файла. index_bundle.js и index.html. index_bundle.js - это результат использования нашего кода entry и его прогона через наши загрузчики. Хотя index.html создавался "на лету" с помощью HTMLWebpackPluginConfig.

Давайте посмотрим, как выглядит наш файл index.html внутри нашей папки app, а затем на то, что наш недавно созданный файл index.html внутри dist похоже.

app / index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My App</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div id="app"></div>
</html>

dist / index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My App</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div id="app"></div>
  <script src="index_bundle.js"></script>
</html>

Вы заметите, что единственная разница между двумя файлами заключается в том, что в файле dist (который был создан с помощью HTMLWebpackPlugin) теперь есть тег скрипта, указывающий на index_bundle.js. Опять же, единственная настоящая магия здесь заключается в том, что HTMLWebpackConfig достаточно умен, чтобы обнаруживать вывод filename вашего только что созданный файл из Webpack, и он автоматически добавит его как скрипт в ваш новый файл index.html. Итак, в нашем примере мы использовали index_bundle.js в качестве выходного файла, чтобы вы могли видеть в созданном индексе .html выше, теперь у нас есть ‹script src =” index_bundle.js ”› ‹/script› внутри тела. Если бы мы изменили вывод конфигурации нашего веб-пакета на OUR-AWESOME-JS-FILE.js, то внутри тела нашего вновь созданного файла index.html мы будет ‹script src =” OUR-AWESOME-JS-FILE.js ”› ‹/script›

Теперь единственная другая важная часть информации - это то, как на самом деле заставить webpack запускаться.

Если вы установили веб-пакет глобально (запустив npm install -g webpack), у вас есть доступ к интерфейсу командной строки веб-пакета. (Если вы этого не сделали, применяются те же правила, что и ниже, но для их запуска вам просто нужно запустить скрипт npm).

В корневом каталоге вашего приложения (или где угодно, где находится webpack.config.js) вы можете запустить webpack со своего терминала, и это выполнит однократный запуск настройки вашего веб-пакета. Однако это может быть своего рода болью, когда приходится запускать команду снова и снова всякий раз, когда вы что-то меняете. Чтобы исправить это, запустите webpack -w, и он будет следить за вашими файлами и повторно запускать webpack всякий раз, когда любой из файлы Webpack заботятся об изменениях. Наконец, если вы хотите отправить в производственную среду, вы можете запустить webpack -p, и это выполнит обычные преобразования, а также минимизирует ваш код.

Итак, теперь вы, вероятно, думаете: «Привет, Тайлер. Это круто и все такое, но я пришел сюда ради React и до сих пор ничего этого не видел ». Во-первых, успокойся. Во-вторых, это справедливо. Хорошая новость в том, что у вас уже есть все знания о Webpack, необходимые для работы с React. Теперь нам просто нужно взглянуть на инструмент под названием babel и добавить его в качестве загрузчика.

Babel.js - замечательный инструмент для компиляции вашего JavaScript. С помощью Webpack вы указываете ему, какие преобразования нужно сделать в вашем коде, а Babel - это само преобразование. Что касается React, Babel позволит нам преобразовать наш JSX (который вы скоро увидите) в настоящий JavaScript. Что хорошо в Babel, так это то, что его можно использовать не только для JSX- ›JS-преобразований. Вы также можете выбрать будущие версии JavaScript (ES2015, 2016 и т. Д.) И использовать Babel для преобразования будущего JavaScript в современный JavaScript, чтобы браузер мог его понять. Давайте посмотрим, как это выглядит.

Как всегда, нам нужно будет кое-что установить с помощью NPM. Babel имеет модульную структуру, поэтому сначала нам нужно установить несколько вещей. Если вы следуете инструкциям, можете запустить npm install - save-dev babel-core babel-loader babel-preset-react. babel-core - это сам babel, babel-loader - это загрузчик веб-пакетов, который мы будем использовать, а babel-preset-response - это преобразование JSX в ›JS.

У вас может возникнуть соблазн добавить новый загрузчик в webpack для каждого типа преобразования Babel, который мы хотим сделать, но это не так. Вместо этого вы просто даете Webpack единственный babel-loader, который мы установили, тогда этот загрузчик будет обращаться к .babelrc файл, который мы создадим для каждого из преобразований вавилок, которые вы хотите сделать.

Во-первых, в том же каталоге, где находится файл webpack.config.js (обычно это корневой каталог), нам нужно создать файл . babelrc, который выглядит следующим образом

{
  "presets": [
    "react"
  ]
}

Опять же, все, что делает этот файл, - это инструктирует наш загрузчик бабел-файлов, какие именно преобразования бабел-файлов нужно выполнять. На данный момент все, что нас волнует, - это преобразование реакции. Это работает, потому что мы ранее установили babel-preset-react.

Теперь все, что нам нужно сделать, это добавить babel-loader в качестве загрузчика в наш файл webpack.config.js.

// In webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin')
var HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/index.html',
  filename: 'index.html',
  inject: 'body'
});
module.exports = {
  entry: [
    './app/index.js'
  ],
  output: {
    path: __dirname + '/dist',
    filename: "index_bundle.js"
  },
  module: {
    loaders: [
      {test: /\.js$/, include: __dirname + '/app', loader: "babel-loader"}
    ]
  },
  plugins: [HTMLWebpackPluginConfig]
};

Вы заметите, что здесь все то же самое, но вместо нашего уродливого загрузчика кофейных скриптов мы не используем наш загрузчик babel.

Вот и все! Я понимаю, что это много шагов, но вы, вероятно, уже поняли, что код для этих шагов на самом деле не сложен, это просто собрать все, что есть, по кусочкам.

Если вам понравился этот пост, ознакомьтесь с программой React.js. Это программа, которую я создал, чтобы облегчить боль знакомства с экосистемой React (включая Redux, Immutable, React Native, Universal React и т. Д.)

Часть I: Полное руководство по созданию приложений с помощью React.js.
Часть 1.5 (БОНУС): Использование Webpack и Babel для создания приложения React.js
Часть II: Создание приложений React.js с Gulp и Browserify.
Часть III: Архитектура приложений React.js с помощью Flux.