Next.js页面渲染的优化方案

Souleigh ✨ 等级 1198 0 0
标签: domreact前端

Next.js页面渲染的优化方案

在过去一年的工作中我所使用的js框架是Next.js,尽管这个框架在前后端同构方面有着绝佳的体验,但是当页面js文件过大以及preload过多的时候还是会出现页面跳转卡顿和渲染阻塞等比较糟糕的用户体验问题。由于我之前既不知道这个框架的工作原理,自然也就不知道如何去优化它。乘着农历春节前工地活少所以稍微研究一下。

第一个问题:宣称前后台同构的Next.js为何会出现卡顿现象?

Next.js 中的特有生命周期hook 函数 getInitialProps会在页面渲染的时候判断浏览器是否为首次渲染,如果是则是服务端渲染网页,如果不是则是客户端渲染。在页面首次渲染的时候,会加载commons.xxxxx.js文件,这个文件中打包了react.js、next.js 以及相关的框架代码也就是如果是客户端渲染打包后的commons.xxxxx.js负载了整个前端的页面逻辑,这个文件相对比较大一般会在180kb以上。如果仅从文件大小角度来说,这个文件并不算大,就算利用了next.js 的 preload机制把文件大小放到300kb以上,也还行。但是一旦这个文件阻塞了页面的渲染,页面的渲染要等到commons.xxxxx.js加载完毕之后才渲染,那问题就来了。

在next7中使用的打包工具是webpack4,这在打包和加载过程有一个比较蠢的机制(或许仅仅是我个人观点),那就是但凡React DOM上绑定了style 这些DOM都不会在服务端渲染出来,而是打包抽离成一个小的js文件,在commons.xxxxx.js加载完毕之后,再加载这个js,将DOM和内联style渲染到HTML。这就在某种程度上导致了next.js首次渲染是SSR失效了,更为糟糕的是卡顿感十足。

可能有人会说,那就不要写内联style不就好了。但是事实是在大量的后台数据动态渲染页面和用户自定义页面的情况下,不可能做到完全不写内联样式,而去傻乎乎地写一堆className。

所以我们要解决一个问题那就是如何保证,内联style的react dom在首次渲染页面的时候是服务器端直接输出后扔给后台,而不是让commons.xxxxx.js卡卡卡卡卡,然后砰的一下蹦出来。

要解决上一个问题,首先要了解Next.js是如何渲染页面的?

在Next.js的规则中,所有页面级的代码都是写在pages文件夹中,比如/pages/home:

export default () => (<div>你瞅啥?这是home页</div>)

而其框架内置的Document组件中,已经帮开发者配置好传统的HTML文件的<head>,<body>这些标签作为静态资源的外壳。Document组件中有一个renderPage()方法,如果代码正常运行,该方法就会将pages文件夹中的代码和它外部同步渲染到浏览器中。如果开发者希望自定义Document组件只需添加/pages/_document.js文件即可。

renderPage()本质是一个回调函数,它的作用只有一个那就是执行React源码中渲染逻辑同步加载到Next.js的Document组件中形成DOM节点。

import Document, { Head, Main, NextScript } from 'next/document'

export default class MyDocument extends Document {
  static getInitialProps ({ renderPage }) {
    // renderPage()位于next.js特有生命周期函数getInitialProps中。 
    return renderPage();
  }

  render () {    
    return (
      <html>
        <Head>
          <title>没见过标题党吗?</title>
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}

服务端渲染样式

为了能让服务器端渲染样式,我们首先得先做两件事:

  1. 在页面首次加载的时候,也就是所谓的SSR.能让renderPage方法在服务器端就能对React Dom进行解析,让HTML归HTML,CSS归CSS;

  2. 能让Document组件在页面切换时,能及时更新<head>,这样不同的页面就能加载自己所需的script,style。


解决方案的登场

隆重介绍神器styled-components出场,styled-components在github上目前为止已经超过1万stars,它的设计初衷在于在服务端渲染的时候,同时渲染出一个ServerStyleSheet,然后把这个ServerStyleSheet送入React DOM树中。它主要就做两件事:

  1. 把组件中styles抽离到<style>标签中;
  2. <style>标签放到<head>

下面就是一段如何正确使用ServerStyleSheet的姿势步骤:

 import { ServerStyleSheet } from "styled-components";

  static getInitialProps ({ renderPage }) {
    const sheet = new ServerStyleSheet()
    const transform = (App) => {
      return sheet.collectStyles(<App />);      
    }
    const styleTags = sheet.getStyleElement()
    const page = renderPage(transform);
    return { ...page, styleTags };
  }

  render(){
      return(
       <html lang="zh-Hans">
        <Head>
          <meta name="viewport" content="initial-scale=1.0, width=device-width" />
          <meta name="description" content="Kanseefoil"/>
          <link rel="shortcut icon" href="/static/favicon.ico"></link>
          {this.props.styleTags}
        </Head>
        </html>
       );
  }

上面的代码已经完美跟大家展示了如何将内联style抽离出dom,然后通过<link style>的方法渲染样式, 那么问题来了,如何在打包解析react dom时,给服务器一个"纯洁、干净、无暇"的DOM呢?

这个时候就需要使用babel-plugin-styled-components包,在babel中进行解析。

代码如下:

{
    "presets": [
        "next/babel"
    ],
    "plugins": [
        ["styled-components", { "ssr": true, "displayName": true, "preprocess": false } ]
    ]
}

这个时候在去打开next.js页面就会发现,那家伙、那场面渲染速度嗖嗖的。至于负责前端逻辑的commons.xxxxx.js,您老人家就安静地慢慢地加载吧。

收藏
评论区

相关推荐

React 之Virtual DOM 及内核
什么是 Virtual DOM?Virtual DOM 是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。这一过程叫做。这种方式赋予了 React 声明式的 API:您告诉 React 希望让 UI 是什么状态,React 就确保 DOM 匹
03. react 初次见面
    与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。 1、将元素渲染到 DOM 中 --------------     首先我们在一个 HTML 页面中添加一个 id="root" 的 <div>: <div id="root">
06. react 初次见面
    React 元素的事件处理和 DOM元素的很相似。但是有一点语法上的不同: * React事件绑定属性的命名采用驼峰式写法,而不是小写。 * 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM元素的写法)     例如,传统的 HTML: <button onclick="activateLas
Nerv
![](https://oscimg.oschina.net/oscnet/1adc9f3b5b42317562590c398e4f3cce7d7.jpg) Nerv 是一款由京东凹凸实验室打造的高性能类 React 前端框架。目前已广泛运用在京东商城(JD.COM)核心业务及TOPLIFE全站。Nerv 基于React标准,使用 Virtual Dom
React Hook
用React Hook写一个简单的登录表单示例,两种方式: 第一种: import React, { useState } from "react"; import ReactDOM from "react-dom"; function LoginForm() { const [username, setUsern
React Portals
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。常见场景:对话框、悬浮卡以及提示框! 定义一个 模态框组件: import React, { useRef, useEffect, } from 'react'; import ReactDOM from 'react-do
React Router 4.x 开发,这些雷区我们都帮你踩过了
前言 -- 在前端框架层出不穷的今天,React 以其虚拟 DOM 、组件化开发思想等特性迅速占据了主流位置,成为前端开发工程师热衷的 Javascript 库。作为 React 体系中的重要组成部分:React Router 也成为开发者首选的路由库,其主要功能是通过管理 url 实现组件的切换和状态的变化。 正文 -- 在 React Router
React 入门及学习笔记
React 构建用户界面的JavaScript库,主要用于构建UI界面。Instagram,2013年开源。 特点: --- 1. 声明式的设计 2. 高效,采用虚拟DOM来实现DOM的渲染,最大限度的减少DOM的操作。 3. 灵活,跟其他库灵活搭配使用。 4. JSX,俗称JS里面写HTML,JavaScript语法的扩展。 5. 组件化,模
React 服务端渲染完美的解决方案
最近在开发一个服务端渲染工具,通过一篇小文大致介绍下服务端渲染,和服务端渲染的方式方法。在此文后面有两中服务端渲染方式的构思,根据你对服务端渲染的利弊权衡,你会选择哪一种服务端渲染方式呢? 什么是服务器端渲染 --------- 使用 React 构建客户端应用程序,默认情况下,可以在浏览器中输出 React 组件,进行生成 DOM 和操作 DOM。Re
React.render和reactDom.render的区别
这个是react最新版api,也就是0.14版本做出的改变。主要是为了使React能在更多的不同环境下更快、更容易构建。于是把react分成了react和react-dom两个部分。这样就为web版的react和移动端的React Native共享组件铺平了道路。也就是说我们可以跨平台使用相同的react组件。  新的react包包含了React.crea
React应用渲染界面的入口
jsx代码: var React = require('react'); var ReactDOM = require('react-dom'); var MyButtonController = require('./components/MyButtonController'); ReactDOM.render
React的虚拟DOM
上一篇文章中,DOM树的信息可以用JavaScript对象来表示,反过来,可以根据这个用JavaScript对象表示的树结构来真正构建一颗DOM树。 用JavaScript对象表示DOM信息和结构,当状态变更的时候,重新渲染这个JavaScript的对象结构,当然这样做,其实并没有更新到真正的页面上。 但是可以用新渲染的对象树和旧的树进行对比,记录这两棵树
React篇(005)
答案: 1、**React 速度很快**:它并不直接对 DOM 进行操作,引入了一个叫做虚拟 DOM 的概念,安插在 javascript 逻辑和实际的 DOM 之间,性能好。 2、**跨浏览器兼容**:虚拟DOM帮助我们解决了跨浏览器问题,它为我们提供了标准化的 API,甚至在 IE8 中都是没问题的。 3、**一切都是 co
React:react
使用react构建单页面应用:   实现方法:(1)react-router        (2)react-router-dom `react-router`: 实现了路由的核心功能,而react-router-dom依赖react-router, `react-router-dom`: 基于`react-router`,加入了在浏览器运行环境下的
阿里巴巴前端练习生学习笔记
字符串引擎和Javascript引擎的区别:是否对于DOM进行全部改变? 相关资料链接• Wiki MVC • Wiki MVVM • Mustach • Handlebars • React • Angular • Vue • Bootstrap • Ant Design • Fusion Des