Предисловие

Изучение тонкостей работы Babel, Webpack или Hot Module Replace выходит за рамки этой статьи. Я бы порекомендовал прочитать документацию, доступную в Интернете, если вам интересно узнать больше о том, как работают эти инструменты. Вот несколько ссылок для начала:

1 Начало работы

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

.
+-- react-app
  +-- public
  | +-- index.html
  +-- src
  | +-- App.css
  | +-- App.jsx
  | +-- index.js
  +-- .babelrc
  +-- webpack.config.js

Далее давайте инициализируем наш проект с помощью npm и установим некоторые необходимые зависимости для разработки.

npm init -y
npm install -D babel-loader @babel/core @babel/cli @babel/preset-react @babel/preset-env style-loader css-loader webpack webpack-cli webpack-dev-server

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

  • babel-loader: позволяет транспилировать файлы JavaScript с помощью babel и webpack.
  • @babel/core:основной пакет babel, необходимый для любых преобразований.
  • @babel/cli:позволяет компилировать файлы из командной строки.
  • @babel/preset-react: позволяет использовать синтаксис JSX.
  • @babel/preset-env:позволяет вам использовать новейший синтаксис JavaScript без необходимости микроуправления тем, какие преобразования синтаксиса необходимы вашей целевой среде (средам).
  • style-loader: позволяет внедрить CSS в модель DOM. Например, import './styles.css' в файлах JavaScript вашего компонента React.
  • css-loader: интерпретирует @import и url() как import/require() и разрешает их.
  • webpack: сборщик модулей.
  • webpack-cli: позволяет запускать webpack из командной строки.
  • webpack-dev-server: позволяет запускать сервер разработки, который облегчает перезагрузку в реальном времени.

2 Вавилон

Babel — это компилятор JavaScript, который позволяет вам писать синтаксис JSX, ES6+ и гарантирует, что написанный вами код работает в нескольких браузерах.

Из коробки Babel ничего не делает. Он в основном действует как const babel = code => code;, анализируя код, а затем снова генерируя тот же код. Вам нужно будет добавить плагины для Babel, чтобы делать что-либо (это то, что мы установили на шаге выше).

2.1 Настройка Бабеля

Обновите файл .babelrc, чтобы он выглядел так:

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

2.2 Проверка работы Babel

Обновите файл index.js, чтобы он выглядел так:

const text = 'Babel';
console.log(`Hello ${text}`);

Запустите следующую команду npx babel src/index.js и наблюдайте за выводом в своем терминале, который должен выглядеть примерно так, как показано ниже:

"use strict";
var text = 'Babel';
console.log("Hello ".concat(text));

Обратите внимание, как Babel скомпилировал код и использовал предустановки, указанные в .babelrc, для преобразования синтаксиса!

3 Веб-пакет: базовая конфигурация

3.1 Настройка веб-пакета

Обновите файл webpack.config.js, чтобы сообщить webpack, как загружать и компилировать наши модули. Ваш файл должен выглядеть примерно так:

const path = require('path');
const REGEX_JS = /\.(js|jsx)$/;

module.exports = {
  entry: './src/index.js',
  mode: 'development',
  module: {
    rules: [
      {
        test: REGEX_JS,
        exclude: /(node_modules)/,
        loader: 'babel-loader',
      }
    ]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist/',
  }
};

Если вам интересно понять, как работает файл конфигурации, вы можете прочитать доступные параметры конфигурации веб-пакета на их веб-сайте.

3.2 Проверка работы Webpack

Выполните следующую команду npx webpack, и должен быть создан файл react-app/dist/bundle.js. Содержимое файла bundle.js немного грубовато, но если команда заработала без проблем, значит, вы все делаете правильно и готовы к следующему шагу!

4 Добавление React в микс

До сих пор мы писали базовый JavaScript. Пришло время реагировать! Начнем с установки некоторых зависимостей для React.

npm install react react-dom

4.1 Обновление файлов

Во-первых, нам нужно обновить наш статический файл index.html, чтобы у React была точка входа для загрузки всех наших компонентов. Как правило, это будет единственный html-файл во всем приложении, поскольку React в основном написан с использованием JSX. Обновите файл index.html, чтобы он выглядел следующим образом:

<!-- sourced from https://raw.githubusercontent.com/reactjs/reactjs.org/master/static/html/single-file-example.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>React Application</title>
</head>
<body>
  <div id="root"></div>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <script src="../dist/bundle.js"></script>
</body>
</html>

Затем мы обновим наш файл index.js, чтобы отобразить наше приложение React. Здесь нет ничего необычного, и приведенный ниже код должен показаться вам знакомым, если вы раньше использовали React.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
  <App />,
  document.getElementById('root')
);

После обновления index.js нам нужно обновить содержимое нашего файла App.jsx, чтобы он стал компонентом React. Мы также добавим стиль в App.css, чтобы убедиться, что наш css-загрузчик работает в веб-пакете. Обновите файл App.css, добавив стиль:

.App {
  color: #303C6C;
}

Обновите файл App.jsx, сделав его базовым функциональным компонентом, который может выглядеть следующим образом:

import React from 'react';
import './App.css';
const App = () => (
  <h1 className="App">
    React!
  </h1>
);
export default App;

Наконец, нам нужно обновить конфигурацию нашего веб-пакета, чтобы (1) указать веб-пакету, где разрешать наши модули, и (2) сообщить веб-пакету, как загружать наши модули css. Если вы сейчас попытаетесь запустить npx webpack, вы столкнетесь с ошибкой и не сможете связать свое приложение.

Обновите файл webpack.config.js, чтобы он выглядел следующим образом:

const path = require('path');
const REGEX_JS = /\.(js|jsx)$/;
const REGEX_CSS = /\.css$/;                   // LINE ADDED
module.exports = {
  entry: './src/index.js',
  mode: 'development',
  module: {
    rules: [
      {
        test: REGEX_JS,
        exclude: /(node_modules)/,
        loader: 'babel-loader',
      },
      {                                       // LINE ADDED
        test: REGEX_CSS,                      // LINE ADDED
        use: ['style-loader', 'css-loader'],  // LINE ADDED
      }                                       // LINE ADDED
    ]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist/',
  },
  resolve: {                                 // LINE ADDED
    extensions: ['.js', '.jsx', '.css']      // LINE ADDED
  }                                          // LINE ADDED
};

Убедитесь, что до этого момента все работает, выполнив следующую команду npx webpack. Если команда выполнилась без проблем, значит, вы все делаете правильно!

4.2 Добавление сервера разработки с помощью Webpack

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

Обновите файл webpack.config.js, чтобы он выглядел следующим образом:

const path = require('path');
const REGEX_JS = /\.(js|jsx)$/;
const REGEX_CSS = /\.css$/;
module.exports = {
  entry: './src/index.js',
  mode: 'development',
  module: {
    rules: [
      {
        test: REGEX_JS,
        exclude: /(node_modules)/,
        loader: 'babel-loader',
      },
      {
        test: REGEX_CSS,
        use: ['style-loader', 'css-loader'],
      }
    ]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist/',
  },
  resolve: {
    extensions: ['.js', '.jsx', '.css']
  }
  devServer: {                                     // LINE ADDED
    open: 'Google Chrome',                         // LINE ADDED
    contentBase: path.join(__dirname, 'public/'),  // LINE ADDED
    port: 3000,                                    // LINE ADDED
    publicPath: 'http://localhost:3000/dist/'      // LINE ADDED
  }                                                // LINE ADDED
};

Мы также обновим наш файл package.json с помощью команды сценария npm, которая позволит нам запустить сервер разработки веб-пакетов. Добавьте следующую команду в часть «scripts» вашего файла package.json:

"scripts": {
  "start:dev": "webpack serve"
}

Теперь мы можем запустить наше приложение React! Используйте команду npm run start:dev, чтобы сообщить Webpack, что нужно связать ваш код и запустить сервер разработки. После того, как код будет объединен, Webpack должен автоматически открыть новую вкладку/окно Google Chrome и отобразить ваше приложение React!

Вы также должны иметь возможность обновить файл App.css или файл App.jsx, а затем сохранить файл и просматривать обновления вашего приложения React в режиме реального времени без повторного использования команды npm run start:dev.

Поздравляем тех, кто зашел так далеко! Вы просто настраиваете свой собственный проект React, не используя команду create-react-app.

4.3 Горячая замена модуля

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

С нашей текущей конфигурацией мы потеряем все состояние нашего приложения при выполнении полной перезагрузки. В частности, если мы обновим наши файлы .jsx. Это может показаться проблемой, которую не стоит решать, но использование замены горячего модуля может значительно повысить вашу производительность при разработке и сэкономить много времени при создании приложения React.

В этой статье мы будем использовать React Hot Loader, который устарел и, как ожидается, будет заменен на React Fast Refresh, но на момент написания этой статьи React Fast Refresh для Webpack находится на экспериментальной стадии и не является на 100% стабильным.

Теперь давайте настроим горячую замену модуля! Во-первых, нам нужно установить две новые зависимости:

npm install react-hot-loader @hot-loader/react-dom

Во-вторых, нам нужно обновить нашу конфигурацию Babel и Webpack. Обновите файл webpack.config.js, включив в него псевдоним, и установите для параметра devServer hot значение true.

module.exports = {
  // ...
  resolve: {
    alias: {                                          // LINE ADDED
      'react-dom': '@hot-loader/react-dom',           // LINE ADDED
    },                                                // LINE ADDED
    extensions: ['.js', '.jsx', '.css']
  },
  devServer: {
    open: 'Google Chrome',
    contentBase: path.join(__dirname, 'public/'),
    port: 3000,
    publicPath: 'http://localhost:3000/dist/',
    hot: true                                         // LINE ADDED
  }
};

Далееобновите .babelrc и добавьте подключаемый модуль react-hot-loader/babel.

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ],
  "plugins": ["react-hot-loader/babel"]             // LINE ADDED
}

Наконец, пометьте корневой компонент как горячеэкспортируемый. Убедитесь, что react-hot-loader требуется перед react и react-dom . Обновите файл App.jsx, чтобы он выглядел так:

import { hot } from 'react-hot-loader/root';       // LINE ADDED
import React from 'react';
import './App.css';
const App = () => (
  <h1 className="App">
    React!
  </h1>
);
export default hot(App);                          // LINE ADDED

Все сделано :)

Теперь вы можете добавлять состояние в свое приложение React, сохранять файлы, и в большинстве случаев вы не потеряете состояние своего приложения. Если у вас возникнут проблемы с настройкой React Hot Loader, пожалуйста, обратитесь к их документации на Github.