Итак, вы хотите использовать свой причудливый компонент React на веб-сайте AMP и хотите знать, как это сделать. Я приглашаю вас присоединиться ко мне в моем путешествии, пытаясь заставить его работать.

Ускоренные мобильные страницы

Но сначала давайте напомним себе, что такое AMP на самом деле.

AMP (первоначально аббревиатура от Accelerated Mobile Pages) - это структура веб-компонентов и технология публикации веб-сайтов, разработанная Google, цель которой - «предоставлять формат, ориентированный на пользователя, для веб-контента».

Возможно, AMP ориентирован на пользователя, но в Интернете можно найти множество доказательств того, что это не совсем платформа, ориентированная на разработчиков. AMP имеет очень строгие правила, он накладывает существенные ограничения и лимиты на содержание страницы. Например, до недавнего времени было невозможно использовать пользовательский JavaScript на страницах AMP, но был добавлен тег amp-script, чтобы «разрешить запуск пользовательского JavaScript для визуализации пользовательского интерфейса».

Говоря об ограничениях, в нашем проекте некоторые страницы уже достигли ограничения на общий размер стиля (размер правил CSS, которые мы включаем на страницу), поэтому мы решили попробовать отрендерить довольно большое навигационное меню с помощью amp-script. Наше меню было реализовано как компонент React, в нем была изрядная логика и стиль для разных брендов. Мы надеялись повторно использовать существующий код и сэкономить время на его повторной реализации с использованием собственных решений AMP.

И это то, что я узнал, пытаясь заставить это работать.

Обратите внимание, что это сообщение в блоге не является учебным пособием, и ваш результат может отличаться.

amp-скрипт

Согласно документации:

amp-script запускает ваш пользовательский JavaScript в Web Worker, который содержит виртуальную модель DOM. Когда ваш код JavaScript изменяет эту виртуальную модель DOM, amp-script пересылает эти изменения в основной поток и применяет их к поддереву элемента amp-script.

Чтобы загрузить пользовательский JavaScript на свою страницу, вы должны использовать тег amp-script с атрибутом src.

<amp-script layout="container" src="https://example.com/hello-world.js">
  <button>Hello amp-script!</button>
</amp-script>

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

Довольно аккуратно, но давайте проверим ограничения:

Здесь вы можете увидеть первую проблему: минимизированный размер React Core + React DOM составляет 109 КБ (согласно измерениям для v16), и если вы добавите styled-components, который мы используем для наших компонентов, вы получите более 160 КБ.

Итак, должны ли мы отказаться от надежды на повторное использование кода и снова обвинить разработчиков Google? Может быть, но не обязательно!

Как насчет Preact?

По данным preactjs.com:

Preact - это быстрая альтернатива React объемом 3 КБ с тем же современным API.

3кб? Звучит многообещающе! И самое главное Preact совместим с компонентами React благодаря модулю preact/compat.

Конечно, добавление дополнительной структуры к вашей кодовой базе реакции может усложнить процесс сборки, но мы хотим повторно использовать наш код, верно?

Для начала создадим простой компонент с помощью Preact:

import { Component } from 'preact';
export default class App extends Component {
  render() {
    return (
      <div id="app">
        Hi there!
      </div>
    );
  }
}

После того, как мы соберем бандл и свяжем его с amp-script

<amp-script
  layout="container"
  src="http://localhost:8000/js/amp.80f7b.js"
>
   <div className="app">loading...</div>
</amp-script>

мы получаем это:

Потрясающий! И размер нашего бандла по-прежнему невелик: 16кб.

Как я уже упоминал, в проекте мы используем styled-components, поэтому давайте попробуем его в действии:

import { Component } from 'preact';
import styled from 'styled-components';
const StyledHeader = styled('h1')`
 color: green;
`;
export default class App extends Component {
 render() {
  return (
   <div id="app">
    <StyledHeader>Hi there!</StyledHeader>
   </div>
  );
 }
}

Как ни странно, мы получаем сообщение об ошибке: «Uncaught TypeError: невозможно прочитать свойство childNodes of undefined».

styled-components создать стиль для каждого стилизованного компонента в head, но amp-script отображает содержимое в какой-то «песочнице», а document.head в ней не существует, поэтому это не удается.

Для этого есть решение styled-components@v5 (сейчас в бета-версии), позволяющее указывать цель для его стилей:

import { Component } from 'preact';
import styled, { StyleSheetManager } from 'styled-components';
const StyledHeader = styled('h1')`
 color: green;
`;
export default class App extends Component {
render() {
  return (
   <div id="app">
    <StyleSheetManager disableCSSOMInjection target={window.document.body}>
     <StyledHeader>Hi there!</StyledHeader>
    </StyleSheetManager>
   </div>
  );
 }
}

Сейчас ошибок нет, но стиль не применялся (текст должен был иметь зеленый цвет):

Очевидно, amp-script фильтрует style теги, и в результате на страницу не добавляются никакие стили.

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

export default class App extends Component {
render() {
  return (
   <div id="app">
    <StyleSheetManager disableCSSOMInjection target={window.document.body}>
     <ThemeProvider market="uk">
      <ConfigProvider>
       <Menu
        {...menuProps}
       />
      </ConfigProvider>
     </ThemeProvider>
    </StyleSheetManager>
   </div>
  );
 }
}

Все работает локально, как ожидалось, поэтому мы добавляем наш пакет на страницу AMP и снова получаем сообщение об ошибке: [amp-script] Превышен максимальный общий размер скрипта (150000).

В нашем пакете JavaScript теперь 177 КБ! Тогда это не шанс ...

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

Что все это значит для нас? Может быть, мы будем использовать amp-script для чего-нибудь еще.