Подробный React SSR [почти 1W слов] + 2 актуальных проекта

React.js

CSR & SSR

Рендеринг на стороне клиента

  • Процесс рендеринга CSR:
    React CSR.png

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

  • относится к размещению одностраничного приложения (SPA) вСервис-терминалПроцесс рендеринга фрагментов HTML, отправки их в браузер, а затем передачи их в браузер для связывания состояний и событий, чтобы стать полностью интерактивной страницей. (PS: содержимое SSR в этой статье касается изоморфных приложений.)
  • Процесс рендеринга SSR:

React SSR.jpg

  • Сервер отвечает только за первый «рендеринг» (в прямом смысле только браузер может отображать страницу, сервер фактически генерирует HTML-контент), а затем возвращает его клиенту, клиентперениматьВзаимодействие со страницей (логика, такая как привязка событий), а затем при переключении маршрутизации на стороне клиента соответствующий контент отображается непосредственно через код JS, и рендеринг на стороне сервера больше не требуется (требуется только при обновлении страницы).

Зачем использовать ССР

преимущество:

  • Более высокая скорость загрузки в верхней части страницы: не нужно ждать, пока JavaScript завершит загрузку и выполнение, прежде чем отобразить содержимое, быстрее увидеть полностью отрендеренную страницу и улучшить взаимодействие с пользователем.
  • более дружественный к SEO:
    • Сканер может напрямую захватить отображаемую страницу. HTML-документ, возвращенный CSR в первый раз, представляет собой пустой узел (корень) и не содержит контента. Сканер не может проанализировать, какой контент содержится на вашем веб-сайте, поэтому он не может дать вам хороший рейтинг . SSR возвращает обработанный HTML-фрагмент с полным содержимым, чтобы поисковые роботы могли лучше анализировать и индексировать его.


  • На основе старой версии поисковой системы: мы добавим заголовок и описание в html, чтобы сделать простую сео-оптимизацию, эти два не улучшат поисковый рейтинг по сути, но улучшат коэффициент конверсии сайта. Предоставьте веб-сайту больше описаний, чтобы у пользователей было желание кликнуть, тем самым улучшив рейтинг.
<title>首页标题</title>
<meta name="description" content="首页描述"></meta>
  • На основании новой версии поисковой системы (полнотекстовый поиск): Недостаточно полагаться на два вышеупомянутых, чтобы дать веб-сайту хороший рейтинг, поэтому SSR необходим для предоставления большего количества контента веб-сайта.

недостаток:

  • Высокое потребление производительности сервера
  • Сложность проекта становится выше, и проблемы нужно искать между фронтендом, нодой и бэкендом
  • Необходимо учитывать эксплуатацию и техническое обслуживание, применение и расширение машины SSR, что увеличивает стоимость эксплуатации и обслуживания (можно решить с помощью Serverless).

Что такое изоморфное применение

  • Набор кода, который может выполняться как на сервере, так и на клиенте, называется изоморфным приложением.
  • Создавайте визуализированный контент на сервере, чтобы пользователи могли видеть информативные страницы как можно раньше. В дополнение к чисто статическому контенту полное приложение также включает в себя различные реакции на события, взаимодействие с пользователем и многое другое. Это означает, что сценарии JavaScript должны выполняться на стороне браузера для завершения событий привязки, обработки асинхронных взаимодействий и т. д.
  • С точки зрения производительности и взаимодействия с пользователем, рендеринг на стороне сервера должен отображать самую важную, основную и самую основную информацию о странице, в то время как на стороне браузера необходимо выполнять дополнительные расширенные функции, такие как рендеринг страницы и привязка событий для взаимодействия. Так называемый изоморфизм означает, что передняя и задняя части имеют общий набор кода или логики, и в этом наборе кода или логики идеальная ситуация состоит в том, чтобы судить о существующей структуре DOM и структуре, которая должна быть отображена в процессе дальнейшей обработки. рендеринг на стороне браузера.То же самое, если это то же самое, структура DOM не будет перерисовываться, и требуется только привязка событий.
  • С этой точки зрения изоморфизм и рендеринг на стороне сервера различны. Изоморфизм больше похож на пересечение рендеринга на стороне сервера и рендеринга на стороне браузера. кода или Логика работает в унисон. Ядром изоморфизма является «тот же набор кодов», который представляет собой другое измерение с точки зрения двух концов.

Вручную создайте структуру SSR

  • адрес проекта:https://github.com/yjdjiayou/react-ssr-demo
  • В исходном коде проекта уже есть много комментариев, поэтому я не буду вводить здесь слишком много.

использоватьNext.js(Зрелая структура SSR)

Установить

npx create-next-app project-name

Посмотреть package.json

{
  "name": "next-demo-one",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    // 默认端口 3000,想要修改端口用 -p  
    "dev": "next dev -p 4000",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "9.1.4",
    "react": "16.12.0",
    "react-dom": "16.12.0"
  }
}

Head

  • Следующая / главная роль - дать каждому набору страницы<head>Содержимое тега эквивалентно react-helmet
import Head from 'next/head'

export default () =>
  <div>
    <Head>
      <title>My page title</title>
      <meta name="viewport" content="initial-scale=1.0, width=device-width" />
    </Head>
    <p>Hello world!</p>
  </div>

getInitialProps

  • Next.js имеет собственный набор спецификаций для получения данных, и запросы данных нужно размещать вgetInitialPropsВнутри, вместо того, чтобы быть помещенным в жизненный цикл компонента, он должен следовать его спецификациям.
  • getInitialPropsСвойства входного объекта следующие:
    • pathname- часть пути URL
    • query- Запросная часть URL, которая преобразуется в объект.
    • asPath- фактический путь (включая часть запроса), отображаемый в браузере, какStringТипы
    • req- Объект HTTP-запроса (только на стороне сервера)
    • res- Объект возврата HTTP (только на стороне сервера)
    • jsonPageRes - Получить объект ответа данных(только на стороне клиента)
    • err- любые ошибки при рендеринге
  • Когда страница загружается изначально,getInitialPropsбудет вызываться только на стороне сервера. Только когда трасса прыгает(LinkПереход к компоненту или переход к методу API), клиент выполнитgetInitialProps.онлайн демо
  • Только компоненты, размещенные в каталоге pages, его getInitialProps будет вызываться, подкомпоненты используют getInitialProps это недействительно
    • Поскольку все компоненты в каталоге pages по умолчанию являются перенаправленными компонентами, будут обрабатываться только перенаправленные компоненты. Next.js сначала вызовет компонент маршрутизации наgetInitialPropsметод, получить возвращенные данные какpropsПередайте его компоненту маршрутизации и, наконец, визуализируйте компонент маршрутизации.онлайн демо
    • Самый прямой способ получения данных дочерними компонентами выглядит следующим образом:
function PageA(props){
    const {childOneData,childTwoData} = props;
    return <div>
        <ChildOne childOneData/>
        <ChildTwo childTwoData/>
    </div>;
}
PageA.getInitialProps = async ()=>{
    // 在父组件中的 getInitialProps 方法里,调用接口获取子组件所需要的数据
    const childOneData = await getPageAChildOneData();
    const childTwoData = await getPageAChildTwoData();
    return {childOneData, childTwoData}
};
  • Когда структура страницы сложна, несколько подкомпонентов должны одновременно запрашивать данные или подкомпоненты должны загружаться динамически, приведенное выше решение может не подойти. Не думайте о запросе данных в жизненном цикле дочерних компонентов, следуйте спецификациям Next.js. Лучший способ — разбить эти подкомпоненты на подмаршруты и назвать их компонентами маршрутизации.getInitialPropsметод получения данных

маршрутизация

  • конвенционная маршрутизация
    • По умолчанию вpagesв каталоге.jsВсе файлы являются маршрутами первого уровня.
    • Если вы хотите использовать вторичную маршрутизацию, просто вpagesкаталог создать новую папку

image.png

  • в Next.jsLinkкомпонент, который ничего не отображает по умолчанию (например, a тег), необходимо указать содержимое рендеринга, и внутри должен быть элемент верхнего уровня, а два родственных элемента не могут появляться одновременно. Он просто слушает то, что мы указываем click событие, затем перейти к указанному пути
import Link from 'next/link'
const Index = () => {
  return (
    <>
        <Link href="/a?id=1">
            <div>
                <Button>AAA</Button>
                <Button>BBB</Button>
            </div>
        </Link>
    </>
  )
};
  • Маршруты в Next.js генерируются путем согласования структуры каталогов файлов, поэтому их нельзя определитьparams,Динамическая маршрутизация может быть выполнена только черезqueryвыполнить
import Router from 'next/router'
import Link from 'next/link'

const Index = () => {
  // 通过 API 跳转
  function gotoTestB() {
    Router.push(
      {
        pathname: '/test/b',
        query: {
          id: 2,
        },
      }
    )
  }
  return (
    <>
        <Link href="/test/b?id=1" >
                <Button>BBB</Button>
        </Link>
    </>
  )
};
  • Если вы хотите, чтобы маршрут выглядел лучше в браузере (например:/test/id, вместо/test?id=123456),Можно использоватьКарта маршрута
import Router from 'next/router'
import Link from 'next/link'

const Index = () => {
  // 通过 API 跳转
  function gotoTestB() {
    Router.push(
      {
        pathname: '/test/b',
        query: {
          id: 2,
        },
      },
      '/test/b/2',
    )
  }
  return (
    <>
        <Link href="/test/b?id=1" as="/test/b/1" >
            <div>
                <Button>BBB</Button>
            </div>
        </Link>
    </>
  )
};
  • Однако, когда вышеуказанная страница обновляется, страница будет 404. Поскольку это приложение SPA, интерфейс может изменить маршрут браузера без обновления страницы, но когда страница обновляется и файл, соответствующий маршруту, повторный запрос, сервер не может найти файл, соответствующий пути. Поэтому вам нужно использовать инфраструктуру Node (например, Koa2), чтобы заменить сервер по умолчанию, который поставляется с Next.js.
const Koa = require('koa');
const Router = require('koa-router');
const next = require('next');
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = new Koa();
  const router = new Router();
  
  router.get('/a/:id', async ctx => {
    const id = ctx.params.id;
    await handle(ctx.req, ctx.res, {
      pathname: '/a',
      query: { id },
    });
  });
  
  server.listen(3000, () => {
    console.log('koa server listening on 3000')
  });
}

  • Перехватчик маршрутизации
import Router from 'next/router'

Router.beforePopState(({ url, as, options }) => {
  // I only want to allow these two routes!
  if (as !== "/" || as !== "/other") {
    // Have SSR render bad routes as a 404.
    window.location.href = as
    // 返回 false,Router 将不会执行 popstate 事件
    return false
  }

  return true
});

  • перенаправленные события
    • routeChangeStart(url)- Срабатывает, когда маршрут начинает переключаться
    • routeChangeComplete(url)- Запускается, когда переключение маршрута завершено
    • routeChangeError(err, url)- Запускается, когда переключатель маршрута сообщает об ошибке
    • beforeHistoryChange(url)- браузерhistoryСрабатывает, когда режим начинает переключаться
    • hashChangeStart(url)- начать переключениеhashЗапускается, когда значение не переключается на маршрут страницы
    • hashChangeComplete(url)- завершить переключениеhashЗапускается, когда значение не переключается на маршрут страницы
    • здесьurlзначит отображается в браузереurl. если вы использовалиКарта маршрута, что в браузереurlпокажетasзначение
import React from 'react';
import Router from 'next/router'

class User extends React.Component {

    handleRouteChange = url => {
        console.log('url=> ', url);
    };

    componentDidMount() {
        Router.events.on('routeChangeStart', (res) => {
            console.log(res);
        });
        Router.events.on('routeChangeComplete', (res) => {
            console.log(res);
        });
        Router.events.on('routeChangeError', (res) => {
            console.log(res);
        });
    }

    componentWillUnmount() {
        Router.events.off('routeChangeStart', (res) => {
            console.log(res);
        });
        Router.events.off('routeChangeComplete', (res) => {
            console.log(res);
        });
        Router.events.off('routeChangeError', (res) => {
            console.log(res);
        });
    }

    render() {
        return <div>User </div>;
    }
}

style jsx

  • В Next.js есть различные CSS-решения, интегрированные по умолчанию.styled-jsx
const A = ({ router, name}) => {
  return (
    <>
      <Link href="#aaa">
        <a className="link">
          A {router.query.id} {name} 
        </a>
      </Link>
      <style jsx>{`
        a {
          color: blue;
        }
        .link {
          color: ${color};
        }
      `}</style>
    </>
  )
};

Динамическая загрузка ресурсов и компонентов

import { withRouter } from 'next/router'
import dynamic from 'next/dynamic'
import Link from 'next/link'

const LazyComp = dynamic(import('../components/lazy-comp'));

const A = ({time }) => {

  return (
    <>
      <div>Time:{time}</div>
      <LazyComp />
    </>
  )
};

A.getInitialProps = async ctx => {
  // 动态加载 moment,只有到了当前页面的时候才去加载它,而不是在页面初始化的时候去加载
  const moment = await import('moment');

  const promise = new Promise(resolve => {
    setTimeout(() => {
      resolve({
        name: 'jokcy',
        // 默认加载的是 ES6 模块
        time: moment.default(Date.now() - 60 * 1000).fromNow(),
      })
    }, 1000)
  });

  return await promise
};

export default A;

_app.js

  • новый./pages/_app.jsфайл, пользовательский модуль приложения
  • Настройка в Next.js может иметь следующие преимущества:
    • Реализовать общий макет для каждой страницы - Макет
    • Сохраняйте некоторое публичное состояние (используя избыточность) при изменении маршрутов
    • Передайте некоторые пользовательские данные на страницу
    • использоватьcomponentDidCatchпользовательская обработка ошибок
// lib/my-context
import React from 'react'
export default React.createContext('')

// components/Layout
// 固定布局
    xxx
    xxx
    xxx

// _app.js
import 'antd/dist/antd.css';
import App, { Container } from 'next/app';
import Layout from '../components/Layout'
import MyContext from '../lib/my-context'
import {Provider} from 'react-redux'

class MyApp extends App {
  state = {
    context: 'value',
  };

  /**
   * 重写 getInitialProps 方法
   */
  static async getInitialProps(ctx) {
    const {Component} = ctx;
    // 每次页面切换的时候,这个方法都会被执行!!!
    console.log('app init');
    let pageProps = {};
    // 因为如果不加 _app.js,默认情况下,Next.js 会执行 App.getInitialProps
    // 所以重写 getInitialProps 方法时,路由组件的 getInitialProps 必须要执行
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }
    return {
      pageProps
    }
  }

  render() {
    const { Component, pageProps, reduxStore } = this.props;

    return (
      // 在最新的 Next.js 版本中,Container 被移除了,不再需要 Container 包裹组件
      // https://github.com/zeit/next.js/blob/master/errors/app-container-deprecated.md
      <Container>
        <Layout>
            <MyContext.Provider value={this.state.context}>
              <Component {...pageProps} />
            </MyContext.Provider>
        </Layout>
      </Container>
    )
  }
}
export default MyApp;

_document.js

  • Он будет вызываться только при рендеринге сервера, клиент не будет выполняться.
  • Используется для изменения содержимого документа, отображаемого на сервере.
  • Обычно используется со сторонними решениями css-in-js, такими какstyled-components
import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
    // 重写 getInitialProps 方法
    static async getInitialProps(ctx) {
        // 因为如果不加 _document.js,默认情况下,Next.js 会执行 Document.getInitialProps
        // 所以自定义的时候,必须执行 Document.getInitialProps
        const props = await Document.getInitialProps(ctx);
        return {
            ...props
        }
    }

    // render 要么不重写,重写的话,以下的内容都必须加上
    // render() {
    //   return (
    //     <Html>
    //       <Head>
    //           <style>{`body { background:red;} /* custom! */`}</style>
    //       </Head>
    //       <body className="custom_class">
    //         <Main />
    //         <NextScript />
    //       </body>
    //     </Html>
    //   )
    // }
}

export default MyDocument

Внутренняя интеграция с Webpack

  • Next.js интегрирует Webpack внутри, прямо из коробки
  • Разделение кода и встряхивание дерева по умолчанию в среде сборки

Интегрировать Редукс

онлайн демо

процесс рендеринга

Next.js 渲染流程 (1).jpg

Порядок выполнения сервера

онлайн демо

  1. _app getInitialProps()
  2. page getInitialProps()
  3. _document getInitialProps()
  4. _app constructor()
  5. _app render()
  6. page constructor()
  7. page render()
  8. _document constructor()
  9. _document render()

страница представляет компонент маршрутизации

Порядок выполнения клиента (первая открытая страница)

  1. _app constructor()
  2. _app render()
  3. page constructor()
  4. page render()

Уведомление:Когда страница загружается изначально,getInitialPropsбудет вызываться только на стороне сервера. Только когда маршрут прыгает(LinkПереход к компоненту или переход к методу API), клиент выполнитgetInitialProps.

Порядок выполнения прыжка по маршруту

  1. _app getInitialProps()
  2. page getInitialProps()
  3. _app render()
  4. page constructor()
  5. page render()

Плюсы и минусы использования Next.js

преимущество:

  • Легкий и простой в использовании, низкая стоимость обучения, готовые решения (например, внутренняя интеграция Webpack, обычная маршрутизация и т. д.), нет необходимости создавать проекты самостоятельно. Личное мнение: это фреймворк, который обменивает степени свободы на простоту использования.
  • Благодаря собственной стратегии синхронизации данных он решает самую большую проблему рендеринга на стороне сервера. Очень проблематично получать данные, отображаемые сервером, и повторно использовать их на стороне клиента, когда нет фреймворка.
  • Благодаря множеству плагинов мы можем использовать его по запросу, когда мы его используем.
  • Гибкая конфигурация: его можно быстро и гибко настроить в соответствии с различными требованиями проекта.

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

Outlook без сервера

  • Бессерверная архитектура — бессерверная архитектура.
  • Бессерверность не означает, что серверы больше не нужны, но означает, что разработчикам больше не нужно слишком много думать о серверах, и появляется концепция вычислительных ресурсов как сервисов вместо серверов.
  • Serverless определенно станет популярным, Front-end может напрямую писать функции для реализации back-end логики без учета развертывания, эксплуатации и обслуживания, среды и других сценариев, что значительно повысит производительность.
  • При использовании Serverless последующая SSR может называться Serverless Side Rendering.
  • Поскольку я мало что знаю о Serverless, я знаю только его концепцию и влияние, поэтому я не осмеливаюсь говорить слишком много Заинтересованные студенты могут понять это сами.

Поймите Serverless, этой статьи достаточно
Понять принцип бессерверной архитектуры без сервера (1)
Что такое бессерверная бессерверная архитектура?

Общая проблема

Клиенты должны использовать ReactDOM.hydra вместо ReactDOM.render, чтобы делать то, чего не делает SSR (например, привязка событий).

  • В Реакции v15,ReactDOM.renderметод будет основан наdata-react-checksumтег, повторное использованиеReactDOMServerРезультат рендеринга не повторяет рендеринг. согласно сdata-reactidатрибут, найдите элемент события, который необходимо связать, и обработайте привязку события.
  • В Реакции v16,ReactDOMServerВизуализированный контент больше не поставляется сdata-reactАтрибуты,ReactDOM.renderМожет использоваться, но выдаст предупреждение.
  • В Реакции v17,ReactDOM.renderБольше не будет функции мультиплексирования контента SSR, унифицированного использованияhydrate()Чтобы закончить оказанную услугу.
  • Поскольку HTML-код, возвращаемый сервером, представляет собой строку, несмотря на наличие контента, различные компоненты не имеют событий, на складе клиента нет данных, вы можете видетьсморщенная нить. Клиент завершит инициализацию React в соответствии с этими строками, такими как создание экземпляров компонентов, привязка событий, инициализация данных хранилища и т. д. гидрат играет очень важную роль в этом процессе, широко известном как «впрыск воды», который можно понимать как впрыскивание воды в сморщенные семена, чтобы сделать их более жизнеспособными.
  • При использовании Next.jsОткройте консоль браузера => найдите сеть => найдите запрос текущего маршрута и просмотрите ответ => вы можете видеть, что html, возвращаемый сервером, содержит данные, требуемые текущей страницей, так что клиент не будет повторно -инициировать запрос, полагаться на этоReactDOM.hydrate.

image.png

SSR должен использоватьStaticRouter(Статический маршрутный контейнер), а неBrowserRouterа такжеHashRouter

И клиент, и сервер должны настроить склад магазина, но эти два склада будут разными.

componentDidMountне выполняется на стороне сервера иcomponentWillMountВыполняется как на клиенте, так и на сервере, поэтому не рекомендуется использоватьcomponentWillMountПричина отправки запроса

Регистрационные мероприятия должны быть размещены вcomponentDidMount, нельзя помещать вcomponentWillMount, потому что сервер не будет выполнятьсяcomponentWillUnmount, если поместить вcomponentWillMount, это приведет к повторной регистрации событий и утечкам памяти

Если вы не хотите использовать SSR, но хотите оптимизировать SEO, вы можете использоватьprerender илиprerender-spa-pluginзаменить ССР

При ручной настройке инфраструктуры SSR: используйтеnpm-run-all & nodemonДля повышения эффективности разработки Node-проектов

  • nodemon Отслеживание изменений в файлах кода и автоматический перезапуск при изменении кода.
  • npm-run-allинструмент cli для запуска нескольких npm-скриптов параллельно или последовательно
npm install npm-run-all nodemon --save-dev
 "scripts": {
    "dev": "npm-run-all --parallel dev:**",
    "dev:start": "nodemon build/server.js",
    "dev:build:client": "webpack --config webpack.client.js --watch",
    "dev:build:server": "webpack --config webpack.server.js --watch"
 }

В Next.js: импортируется по умолчаниюimport React from "react", но если его не ввести, то редактор будет выдавать предупреждение при написании компонентов, так что лучше его ввести

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

В Next.js: Webpack интегрирован внутри, а разделение кода и встряхивание дерева выполняются по умолчанию в сгенерированной среде.

Next.js работает с любым фреймворком узлов, ноrequest,responseДолжна быть разница в способе инкапсуляции, как это гарантирует, что Next.js экспортируетhandleСовместим ли метод с этими фреймворками?

  • гарантияhandleПолученный метод является родным для Nodejsrequsetобъект иresponseОбъект, а не фреймворк на основе собственной инкапсуляцииrequest,responseобъект. Вот почему при использовании koahandleполученоctx.req,ctx.res, вместоctx.request,ctx.responseпричина.

В Next.js: как интегрировать стилизованные компоненты

  • Необходимо интегрировать в _document.js
  • Идеи аспектно-ориентированного программирования с использованием АОП
cnpm i styled-components babel-plugin-styled-components -D

// .babelrc
{
  "presets": ["next/babel"],
  "plugins": [
    [
      "import",
      {
        "libraryName": "antd"
      }
    ],
    ["styled-components", { "ssr": true }]
  ]
}

// _document.js
import Docuemnt, { Html, Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet } from 'styled-components'

function withLog(Comp) {
  return props => {
    console.log(props);
    return <Comp {...props} />
  }
}

class MyDocument extends Docuemnt {
  
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          // 增强 APP 功能
          enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
          // 增强组件功能
          // enhanceComponent: Component => withLog(Component)
        });

      const props = await Docuemnt.getInitialProps(ctx);

      return {
        ...props,
        styles: (
          <>
            {props.styles}
            {sheet.getStyleElement()}
          </>
        ),
      }
    } finally {
      sheet.seal()
    }
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

// pages/a.js
import { withRouter } from 'next/router'
import Link from 'next/link'
import styled from 'styled-components'

const Title = styled.h1`
  color: yellow;
  font-size: 40px;
`;

const color = '#113366';

const A = ({ router, name}) => {
  return (
    <>
      <Title>This is Title</Title>
      <Comp />
      <Link href="#aaa">
        <a className="link">
          A {router.query.id} {name} 
        </a>
      </Link>
      <style jsx>{`
        a {
          color: blue;
        }
        .link {
          color: ${color};
        }
      `}</style>
    </>
  )
};
export default withRouter(A)

В Next.js: как интегрировать CSS/Sass/Less/Stylus

для поддержки.css,.scss,.less,.styl, вам необходимо настроить файл next.config.js по умолчанию, подробности см. по ссылке ниже.

В Next.js: невозможно загрузить стили Antd по запросу при упаковке

блог woo woo woo.cn on.com/1ask/fear/1079…

woo woo Краткое описание.com/afraid/2 9 3 oh 41 from…

В Next.js: не настраивайте имена статических папок

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

В Next.js: почему приложение открывается медленно

  • Можно поместить модуль, используемый только сервером, в getInitialProps, и тогда Webpack также упакует модуль. Может относиться кimport them properly

Список распространенных ошибок Next.js

послесловие

  • Эта статья просто написана на основе моего понимания.Если есть неправильное понимание, пожалуйста, поправьте меня или предложите лучшее решение
  • Для того, чтобы написать максимально подробно, потребовалось два месяца до и после, чтобы разобраться в этой статье.Увидев это, если вы считаете, что эта статья неплохая, пожалуйста, поставьте лайк~~

адрес проекта

Вручную создайте упрощенную версию платформы SSR.

React16.8 + Next.js + Koa2 разрабатывают проект полного стека Github

Ссылаться на

Практика разделения передней и задней части Taobao ! ! ! ! ! !

UmiJS SSR

Зачем делать реактивный проект изоморфным приложением ssr

Демистификация изоморфных приложений React

Создайте высоконадежное и высокопроизводительное изоморфное решение React

МООК Next.js Учебник

Рекомендуемое чтение

Вы действительно понимаете жизненный цикл React?

Подробные хуки React [почти 1W слов] + бой проекта

Непонимание переменных среды настройки Webpack

Реализация простого веб-пакета от 0 до 1