Анализ фронтенд-архитектуры ПК-сайта на основе React

Node.js внешний интерфейс JavaScript React.js
Анализ фронтенд-архитектуры ПК-сайта на основе React

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

последовательность

Когда я впервые столкнулся с интерфейсом, он начался с простых html, css и js.В то время преобладающей концепцией WEB было разделение структуры, стиля и поведения, то есть html, css и js были разделены, разрабатывались независимо и общались друг с другом через ссылки и скрипты.

В начале небольшие проекты, с которыми я столкнулся, заключались в прямом развертывании html, css, js и других статических ресурсов на сервере, а затем в ответ на разные html-файлы в соответствии с маршрутизацией запросов.

简单网站结构

Даже после изучения веб-пакета я все еще думаю, что роль веб-пакета заключается в сжатии файлов js и css, повышении скорости ответа сервера и оптимизации взаимодействия с пользователем, в то время как сжатые файлы min.css и min.js все еще развертываются на сервере.

Позже, после поступления на стажировку в компанию А, это действительно такой режим разработки.В то время, когда мы разрабатывали страницы h5, мы напрямую писали файлы html, css и js, а затем разворачивали их на сервер для прямого доступа к html.

Позже, поработав в компании Б, я постепенно соприкоснулся с тем, как выглядит настоящий фронтенд-инжиниринг.

Разделение передней и задней части

Часть бизнес-интерфейса некоторых традиционных крупномасштабных веб-сайтов для ПК использует архитектуру MVC, то есть после того, как каждый проект установлен, интерфейс и серверная часть согласовывают интерфейс и разрабатывают его отдельно (Java или PHP), а затем бэкэнд отвечает на запросы клиентов и возвращает определенные html-страницы.

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

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

Внешнее и внутреннее разделение обычно делятся на два типа:

  • В среднем слое нет разделения на интерфейс и сервер;
  • Существует переднее и заднее разделение среднего слоя. Здесь мы представим React, один из трех самых популярных фреймворков.

без промежуточного слоя Разделение интерфейса и сервера без промежуточного веб-слоя является относительно простым типом.Мы размещаем унифицированный шаблон html/pug и другие статические ресурсы, такие как css и js, на cdn.Каждый раз при доступе к странице шаблон напрямую возвращается пользователю. , а затем все узлы dom и другие данные в нем генерируются js.

无中间层的前后端分离

Однако такое разделение переднего и заднего концов без промежуточного слоя имеет много недостатков:

  • Время рендеринга первого экрана слишком велико;
  • Не оптимизировано для SEO.
  • со средним слоем

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

С момента появления Node в 2009 г. клиентская часть постепенно занялась серверной частью, однако из-за собственных ограничений надежности Node не подходит в качестве внутреннего сервера для крупномасштабных проектов. традиционный интерфейс и серверная часть, мы также называем эту архитектуру внешнего интерфейса + узла «большой интерфейс».

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

Я использовал несколько интерфейсных шаблонов, и тот, который мне больше всего понравился, — это шаблон pug (ранее известный как jade).

Синтаксис в PUG - это синтаксис JS, который очень дружелюбна для инженеров передней стороны, а функция мопса очень мощна. Его можно использовать в качестве HTML-промежуточного программного обеспечения и идеально поддерживается узлом. Рекомендуется научиться использовать его здесь.Get Started.

сшивание данных

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

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

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

数据拼接

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

Служба мониторинга

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

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

Но точно так же добавление уровня узла означает, что на веб-сайте есть еще один уровень мониторинга серверной части и вызова, и сложность работы значительно возрастет.

Рендеринг на стороне сервера

Можно сказать, что SSR (server-side-render) является одной из очень важных функций, она может помочь нам решить упомянутые выше проблемы, связанные со слишком большим временем рендеринга первого экрана и низкой поддержкой SEO.

Современные поисковые роботы обычно делятся на два типа:

  • Количество краулеров, поддерживающих синтаксический анализ js, относительно невелико, представлено Google;
  • Большинство краулеров, которые не поддерживают синтаксический анализ js, относятся к этому типу, и они в основном являются краулерами поисковых систем, отличных от Google. Для поисковых роботов Google не имеет значения, используется ли SSR в SEO, потому что в конечном итоге они могут сканировать обычные страницы.

Для поисковых систем, отличных от Google, нам нужно использовать SSR для отображения определенных узлов DOM для сканирования сканером.

И в этом тоже есть преимущество: пользователь может видеть содержимое страницы в процессе загрузки страницы, а не пустую страницу. Если вы не используете SSR, в процессе загрузки ресурсов на веб-странице она всегда будет для пользователя пустой, что может привести к потере пользователей.

B站SSR

Это картина, которую я вижу в первую секунду посещения станции B при скорости сети 50 кбит/с.Если станция B не использует технологию SSR, время может пройти после того, как пользователь увидит контент на первом экране.Пять или шесть секунд.

Вот простой код уровня узла, использующий SSR:

// 代码中使用了es6语法,不懂的可以先学习一下阮一峰老师的《ES6入门》
// 这个地方node如果没有使用babel的话,import会报错,可以直接使用require方法替换
import { renderToString } from 'react-dom/server';
import DemoContainer from 'containers/demo';
// 以koa2框架为例
module.exports = (ctx) => {
    const props = {...};
    // 这里的html就存放着我们组件render完之后的dom节点。
    const html = renderToString(<Demo >);
    // 这里以返回pug模板为例,第二个参数是要传入pug模板中的数据
    ctx.render('demo.pug', {
        __props: JSON.stringify(props),
        html
    });
};

Вот фрагмент кода от мопса:

// pug代码片段
body
    #root
        !{ html }
    script.
        window.__props = '!{ __props }'

При использовании SSR не забудьте убедиться, что интерфейсные и серверные компонентыpropsБудьте последовательны, так что здесь моя привычка ставить слой узлаpropsпрямой входящийwindowобъекта, а затем интерфейсные компоненты непосредственно изwindowприобретение объектаpropsВот и все.

Во время SSR компонент React будет выполняться толькоcomponentWillMount和renderДля создания структуры купола используются два жизненных цикла, а другие жизненные циклы и монтирование методов выполняются во внешнем интерфейсе.

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

Хотя SSR имеет много преимуществ, у него все же есть свои недостатки. Использование SSR означает, что вы заменяете некоторые функции, изначально принадлежащие пользовательскому клиенту, собственным сервером, что снизит производительность сервера и увеличит затраты.По сравнению с небольшими командами или командами с недостатком средств, вам следует тщательно выбирать, использовать ли SSR.

Внешний и внутренний изоморфизм

Говоря о SSR, мы должны упомянуть проблему изоморфизма интерфейсов и серверов. Изоморфизм означает, что интерфейс и нода используют один и тот же набор кода, первый экран рендерится сервером, а отрендеренный html напрямую передается браузеру для рендеринга, клиент отвечает за загрузку js, выполнение остальных жизненный цикл компонента и его монтирование из событий Define и т. д. Хороший набор внешнего и внутреннего изоморфного кода может значительно снизить нагрузку на обслуживание нашего кода и имеет очень эффективную эффективность выполнения.Как элегантно написать внешний и внутренний изоморфный код, также является технической задачей. и нам нужно планировать набор заранее.Внешняя архитектура.

例如:
import React, { Component } from "react";
import { Provider } from "react-redux";
import ReactDOM from "react-dom";
import Loadable from "react-loadable";
import { BrowserRouter, StaticRouter } from "react-router-dom";

// server side render
const SSR = App =>
  class SSR extends Component<{
    store: any;
    url: string;
  }> {
    render() {
      const context = {};
      return (
        <Provider store={this.props.store} context={context}>
          <StaticRouter location={this.props.url}>
            <App />
          </StaticRouter>
        </Provider>
      );
    }
  };

// client side render
const CLIENT = configureState => Component => {
  const initStates = window.__INIT_STATES__;
  const store = configureState(initStates);
  Loadable.preloadReady().then(() => {
    ReactDOM.hydrate(
      <Provider store={store}>
        <BrowserRouter>
          <Component />
        </BrowserRouter>
      </Provider>,
      document.getElementById("root")
    );
  });
};

export default function entry(configureState) {
  return IS_NODE ? SSR : CLIENT(configureState);
}

А с точки зрения изоморфизма у Али есть набор стратегий понижения. Когда нагрузка на сервер нормальная, сервер выполняет SSR для улучшения взаимодействия с пользователем. Когда пользовательский трафик резко возрастает, например, Double Eleven, сервер автоматически выполняет обработку понижения. Узел не выполняет SSR, и все конвертируются в клиент- боковой рендеринг для снижения нагрузки на сервер. .

выбрать кадр

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

В настоящее время существует три основных фреймворка: Express, koa1.0 и koa2.0.

Новичкам рекомендуется использовать koa2.0 непосредственно для обучения и развития среднего слоя.

Недостатки экспресса:

  • Слишком тяжелый, есть много модулей, которые мы можем не использовать; Ад обратных вызовов, даже использование Promises может только облегчить его. Недостатками koa1.0 являются:

  • должны сотрудничатьcoбиблиотека иgeneratorДля использования конфигурация сложна. Поскольку узел был обновлен до версии 7.6 или выше, увеличениеasync/awaitПосле синтаксического сахара мы можем использовать синтаксис KOA2 непосредственно в родном узле без какой-либо сторонней библиотеки.

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

и koa2 используетasync/awaitПосле синтаксического сахара код как бы выполняется синхронно, что очень подходит для логического мышления фронтендеров.

Вот пример кода для экспресс, обещание, koa2:

// express版本
module.exports = (req, res) => {
    const data1 = request.get('/api/demo1', (err, res) => {
        const data2 = request.get('/api/demo2', (err, res) => {
            const data3 = request.get('/api/demo3', (err, res) => {
                res.send(data1 + data2 + data3);
            })
        })
    })
}
// promise版本
module.exports = (req, res) => {
    new Promise((resolve, reject) => {
        request.get('/api/demo1', (err, res) => {
            resolve(res);
        }).then(res => {
            request.get('/api/demo2', (err, res2) => res + res2 );
        }).then(res2 => {
            request.get('/api/demo3', (err, res3) => res2 + res3)
        }).then((data) => {
            res.send(data);
        });
    })
}

Хотя он выглядит аккуратнее, он все еще очень громоздкий.

// koa1和koa2在写法上基本相同,区别在于koa1在使用之前要对co库和generator进行繁琐的配置。
// 每一个await的时候最好加上try-catch,防止因为一个异步请求失败而导致node进程崩溃,这里简化了写法。
module.exports = async (ctx) => {
    const data1 = await request.get('/api/demo1');
    const data2 = await request.get('/api/demo2');
    const data3 = await request.get('api/demo3');
    ctx.body = {
        data: data1 + data2 + data3
    };
}

koa2 очень удобен в использовании и очень подходит для логики мышления фронтенд-инженеров.

Хотя код koa2 выглядит так, как будто он выполняется синхронно, на самом деле он просто становится функцией промиса после компиляции, а весь код после await помещается в обратный вызов промиса и выполняется.

структура развития

После выбора фреймворка все остальное — разработка.Общий слой узлов имеет следующую структуру каталогов:

node

  • lib // хранить сторонние плагины
  • util // Сохраняем свои собственные служебные функции
  • промежуточное ПО // хранить промежуточное ПО
  • маршруты // сохраняем маршруты
  • контроллер // храним функцию обработчика маршрута
  • app.js // файл записи уровня узла Базовая архитектура нодового слоя здесь практически представлена, а остальные части фронтенда в целом всем знакомы. Структура каталогов внешнего интерфейса:

public

  • static
  • src
  • js
  • components
  • containers
  • routes
  • stores
  • actions
  • reducers
  • pages
  • css/scss/less
  • статический Здесь вы можете следовать обычной логике разработки React.

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

настроить

Онлайн-проект должен иметь два режима — режим производства и режим разработки.

Производственный режим — это наша онлайн-операционная среда.

Режим разработки — это наша обычная локальная среда разработки.

При необходимости можно настроить еще больше сред.

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

配置

автоматизированный тест

Автоматическое тестирование необходимо для полноценного крупного веб-сайта.

Хотя в настоящее время из-за быстрого роста клиентской области автоматизированное тестирование бизнес-уровня также стало нестабильным из-за быстрой итерации бизнеса, но некоторые базовые тесты все же необходимы.

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

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

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

Иногда нам также необходимо проводить стресс-тестирование и тестирование аварийного восстановления.

Для новичков тестирование — очень важная концепция и привычка, и обычно следует писать больше модульных тестов.