Введение

В этой статье я собираюсь рассмотреть создание очень простого 3-страничного веб-сайта на React с использованием Webpack для объединения. Это упражнение едва коснется того, что могут делать React и Webpack, но послужит демонстрацией того, как запустить и запустить проект, который можно построить и развернуть как часть конвейера CI / CD. Представим, что мы создаем строительные леса для веб-сайта крупной технологической компании (рис. 1). На этом этапе мы просто хотим запустить веб-сайт и иметь некоторую навигацию.

Реагировать

React - это библиотека с открытым исходным кодом для создания пользовательских интерфейсов, выпущенная Facebook в 2013 году. В отличие от Angular от Google (который в значительной степени исчез после катастрофического выпуска, оттолкнувшего многих разработчиков), Facebook широко использует React в своих собственных проектах, и, возможно, он стал самая популярная библиотека интерфейсных разработчиков в мире технологий, поддерживаемая Facebook и энергичным сообществом разработчиков с открытым исходным кодом.

Мы можем начать с установки React в наш проект:

npm i -D react
npm i -D react-dom

Webpack

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

Начало работы с Webpack

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

npm i -D webpack
npm i -D webpack-cli

Установив интерфейс командной строки Webpack, мы можем добавлять повторяющиеся команды в сценарий сборки в package.json. Например:

"build": "rm -rf dist/ && webpack --config webpack.config.js --mode production"

Загрузчики Webpack

Загрузчики используются для обработки файлов разных типов - например, для файлов CSS мы можем захотеть добавить минификацию. Для этого упражнения я установил четыре загрузчика:

npm i -D css-loader
npm i -D file-loader
npm i -D html-loader
npm i -D babel-loader

Самый интересный из них - babel-loader. Это позволяет нам преобразовывать файлы с помощью Babel, инструмента Javascript, часто используемого для преобразования ES6 в ES5 для повышения совместимости браузера, но его также можно использовать для преобразования файлов React JSX в Javascript.

Мы собираем все это вместе в webpack.config.js:

module: {
  rules: [{
    test: /\.css$/,
    exclude: /node_modules/,
    use: [{ loader: 'style-loader'},{ loader: 'css-loader'}]
  },
  {
    test: /\.jsx$/,
    exclude: /node_modules/,
    loader: 'babel-loader',
  },
  {
    test: /\.html?$/,
    exclude: /node_modules/,
    loader: 'html-loader',
  },
  {
    test: /\.(png|svg|jpg|gif)$/,
    loader: 'file-loader?name=images/[name].[ext]'
  }]
}

Эти четыре раздела резюмируются следующим образом:

  • Файлы CSS проходят через два загрузчика; style-loader и css-loader, которые используются вместе либо для вставки CSS в DOM (т. Е. В виде строки в тегах <style>...</style>) или через URL (т. Е. <link ... />).
  • Наш загрузчик Babel позволяет преобразовать наш JSX в Javascript с помощью Babel. Подробнее об этом позже.
  • Любые файлы HTML проходят через загрузчик HTML. Несмотря на то, что у него есть несколько функций, мы не используем ни одну из них.
  • Загрузчик файлов для копирования любых изображений в нашу выходную папку.

Прочие материалы о Webpack

Мы также собираемся определить точку входа для нашего приложения, папку вывода (и соглашения об именах файлов) и шаблон нашего веб-сайта:

entry: {
  index: './src/components/index.jsx'
},
output: {
  filename: '[name].js',
  chunkFilename: "[name].js",
  path: path.resolve(__dirname, 'dist')
},
plugins: [
  new HtmlWebpackPlugin({ template: './src/index.html' }),
]

Вавилон

Компоненты React могут быть созданы с использованием стандартного Javascript, но большинство разработчиков React предпочитают менее подробный синтаксис JSX, который представляет собой смесь Javascript и разметки. JSX необходимо «транспилировать» в Javascript, прежде чем браузер сможет что-либо с ним сделать. Для этого мы используем Babel и специальный процессор JSX. Сначала мы добавляем в наш проект Babel Core:

npm i -D @babel/core

Тогда нам понадобятся:

npm i -D @babel/preset-react

Это библиотека обработки, позволяющая нам писать наши компоненты на JSX. Мы также хотели бы иметь возможность анализировать import операторы в наших файлах, чтобы зависимости автоматически объединялись. Это похоже на то, как Webpack создает графы зависимостей для построения пакетов, и мы можем использовать эту библиотеку для достижения этой цели:

npm i -S @babel/plugin-syntax-dynamic-import

Мы добавляем их в файл .babelrc, который загрузчик Webpack автоматически подхватит:

{
  "presets": [
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import"
  ]
}

Веб-сайт

Я собираюсь создать базовый веб-сайт с 3 страницами, каждая из которых является «компонентом» React. Для этого примера мы предположим, что одна из страниц (О нас) содержит так много информации, что ее необходимо загрузить как отдельный модуль (чтобы продемонстрировать, как это можно сделать. «Лениво» - только когда компонент нужен). Файловая структура нашего проекта показана на рисунке 2:

Точка входа приложения (index.jsx), которая была определена в файле конфигурации Webpack, приведена ниже:

import ReactDOM from 'react-dom';
import React, { Suspense } from 'react';
import { Main } from './main.jsx';
const AboutUs = React.lazy(() => 
  import(/* webpackChunkName: "aboutUs" */ './aboutUs.jsx'));
import { Contact } from './contact.jsx';
import { BrowserRouter, Route, Link } from "react-router-dom";
import logo from '../images/googlelogo.png';
import './index.css';
ReactDOM.render(
  <BrowserRouter>
    <div>
      <div className="logo">
        <img src={logo} alt=""/>
      </div>
      <div className="links">
        <Link to="/">Main</Link> | <Link to="/aboutUs">About Us</Link> | <Link to="/contact">Contact</Link>
      </div>
    </div>
    <Route path="/" exact component={Main} />
    <Route path="/aboutUs" exact component={() =>
      <Suspense fallback={<div>Loading...</div>}>
        <AboutUs />
      </Suspense>
    } />
    <Route path="/contact" exact component={Contact} />
  </BrowserRouter>,
  document.getElementById('root')
);

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

const AboutUs = React.lazy(() => 
  import(/* webpackChunkName: "aboutUs" */ './aboutUs.jsx'));

Эта строка выполняет отложенную загрузку фрагмента только при необходимости, а не отключает его при загрузке страницы Main. В этом тривиальном примере это довольно бессмысленно, но в более крупном приложении потенциальные преимущества такого подхода должны быть очевидны. В этом примере щелчок по ссылке «О нас» является триггером для получения компонента с сервера.

Маршрутизация

Как вы можете видеть в предыдущем разделе, я использовал react-router-dom; в этой библиотеке используется так называемая динамическая маршрутизация, которая выполняет маршрутизацию на лету без большой предварительной настройки, как это было бы сделано с помощью статической маршрутизации. Маршрутизация с react-router-dom выполняется на стороне клиента, поэтому мы получаем приятное изменение адресной строки без запроса обратно на сервер (если только мы не загружаем компонент лениво, как мы делали ранее).

Чтобы разрешить создание закладок, вы можете настроить свой веб-сервер на пересылку всех запросов на index.html, после чего сработает клиентский маршрутизатор. В целях тестирования я использовал live-server, который поддерживает это, установив --entry-file=./index.html.

Последние мысли

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

Загрузчики позволяют объединять JSX-пакеты (выполняемые Babel) в значительной степени отделенными от Webpack, однако эти два инструмента, похоже, прекрасно работают вместе, поскольку пакеты Webpack соответствуют компонентному подходу React к построению представлений.

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