首屏预渲染方案

栏目: Node.js · 发布时间: 6年前

内容简介:该方案主要是为了解决,前端 spa (单页面应用),首屏渲染慢,白屏时间过长问题。通过 webpack 的 prerender-spa-plugin 编译应用中的静态页面,并将其输出到对应的索引目录。prerender-spa-plugin 利用了 Puppeteer 的爬取页面的功能。 Puppeteer 是 Google Chrome 团队官方的无界面(Headless)Chrome 工具,它是一个 Node 库,提供了一个高级的 API 来控制 DevTools 协议上的无头版 Chrome 。pre

该方案主要是为了解决,前端 spa (单页面应用),首屏渲染慢,白屏时间过长问题。

实现方法

通过 webpack 的 prerender-spa-plugin 编译应用中的静态页面,并将其输出到对应的索引目录。

prerender-spa-plugin 插件原理介绍

prerender-spa-plugin 利用了 Puppeteer 的爬取页面的功能。 Puppeteer 是 Google Chrome 团队官方的无界面(Headless)Chrome 工具,它是一个 Node 库,提供了一个高级的 API 来控制 DevTools 协议上的无头版 Chrome 。prerender-spa-plugin 原理是在 Webpack 构建阶段的最后,在本地启动一个 Puppeteer 的服务,访问配置了预渲染的路由,然后将 Puppeteer 中渲染的页面输出到 HTML 文件中,并建立路由对应的目录。

在 create-react-app 中配置 prerender-spa-plugin

create-react-app 配置未 eject 的情况:

在项目根目录添加 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 配置已经 eject 的情况:

修改 config 文件夹下的 webpack.config.js ,参考代码如下:

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 详细配置参考 官方文档

页面中使用方案推荐

纯静态页面,无接口数据情况:

在首页 react 组件的 didMount 事件中调用 document.dispatchEvent(new Event('custom-render-trigger'))

非静态页面,有接口数据情况:

方案一:

修改入口文件 index.js,

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

skeleton/index.js 将骨架组件或者 loading 组件输出到 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();
// 展示首页
...
复制代码

方案二:

首页数据未加载前,静态部分显示,动态部分显示骨架组件,参考代码如下:

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>
  )
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

How to Think About Algorithms

How to Think About Algorithms

Jeff Edmonds / Cambridge University Press / 2008-05-19 / USD 38.99

HOW TO THINK ABOUT ALGORITHMS There are many algorithm texts that provide lots of well-polished code and proofs of correctness. Instead, this one presents insights, notations, and analogies t......一起来看看 《How to Think About Algorithms》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器