Схема пререндеринга первого экрана

Webpack
Схема пререндеринга первого экрана

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

Реализация

Скомпилируйте статические страницы в приложении через prerender-spa-plugin вебпака и выведите их в соответствующую директорию index.

Введение в принцип prerender-spa-plugin

Плагин prerender-spa-plugin использует возможности Puppeteer для сканирования страниц. Puppeteer — это официальный безголовый инструмент Chrome от команды Google Chrome, представляющий собой библиотеку Node, которая предоставляет высокоуровневый API для управления безголовой версией Chrome по протоколу DevTools. Принцип prerender-spa-plugin заключается в локальном запуске службы Puppeteer в конце фазы сборки Webpack, доступе к предварительно обработанному маршруту, а затем выводе страницы, отображаемой в Puppeteer, в файл HTML и создании каталога, соответствующего маршрут.

Настройте prerender-spa-plugin в приложении create-реагировать

Конфигурация приложения create-реагировать не выбрасывается:

Добавьте файл конфигурации config-overrides.js в корневой каталог проекта. Эталонная конфигурация выглядит следующим образом:

const PrerenderSpaPlugin = require('prerender-spa-plugin');
const path = require('path');

module.exports = (config, env) => {
  if (env === 'production') {
    config.plugins = config.plugins.concat([
      new PrerenderSpaPlugin({
        staticDir: path.join(__dirname, 'build'),
        routes: ['/'],
        renderer: new PrerenderSpaPlugin.PuppeteerRenderer({
          injectProperty: '__PRERENDER_INJECTED',
          inject: {
            prerender: true
          },
          // 这个是监听 document.dispatchEvent 事件,决定什么时候开始预渲染
          // document.dispatchEvent(new Event('render-event'))
          renderAfterDocumentEvent: 'custom-render-trigger',
        })
      })
    ]);
  }

  return config;
};
Конфигурация Create-React-App была извлечена ситуация:

Измените WebPack.config.js в папке Config, справочный код выглядит следующим образом:

plugins: [
  // 预渲染插件
  isEnvProduction && new PrerenderSpaPlugin({
    staticDir: path.join(__dirname, '../build'),
    routes: ['/'],
    renderer: new PrerenderSpaPlugin.PuppeteerRenderer({
      injectProperty: '__PRERENDER_INJECTED',
      inject: {
        prerender: true
      },
      renderAfterDocumentEvent: 'custom-render-trigger',
    })
  }),
  ...
]

подробный справочник по настройке prerender-spa-pluginофициальная документация

Рекомендации по использованию на странице

Чистая статическая страница, ситуация с данными интерфейса отсутствует:

Вызовите document.dispatchEvent(new Event('custom-render-trigger')) в событии didMount компонента реакции домашней страницы

Нестатическая страница, есть случай интерфейсов данных:

Вариант первый:

Измените файл ввода index.js,

//判断是否是预渲染环境
if(window.__PRERENDER_INJECTED && window.__PRERENDER_INJECTED.prerender){
  // loading 组件
  import('./skeleton/index.js');
}else{
  // 原先的入口文件
  import('./page.js');
}

скелет/index.js выводит компонент скелета или загружаемый компонент в index.html. Код ссылки выглядит следующим образом:

// 创建loading容器
const container = document.createElement("div");
container.className = 'prerender-loading';
document.body.appendChild(container);

// 渲染骨架组件或者 loading 组件
ReactDOM.render(
  <div style={{padding: '16px'}}>
    <Skeleton/>
  </div>, 
container);

В компоненте домашней страницы, когда данные загружены, вызовите:

// 移除 loading 或者骨架组件
document.querySelector('.prerender-loading').remove();
// 展示首页
...

Вариант 2:

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

export default function Index() {
  const [data, setData] = useState(null)

  useMount(() => {
    document.dispatchEvent(new Event('custom-render-trigger'));
  });

  // 模拟getdata
  useTimeout(() => {
    setData({...});
  }, 200)

  return (
    <div className='Index'>
      <div>静态ui</div>
      {
        data === null
        ? <Skeleton>骨架ui</Skeleton> 
        : <div>动态数据ui</div>
      }
    </div>
  )
}