You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js应用中获取预生成HTML以加载关键CSS?

解决方案:在Next.js中获取预生成HTML并提取关键CSS

1. App Router场景(非流式渲染)

如果你的项目不依赖服务端流式渲染,可以通过自定义根layout手动捕获完整HTML,再提取关键CSS。这种方式会绕开Next.js默认渲染优化,仅适合静态生成或传统SSR场景:

import { ReactNode } from 'react';
import { renderToString } from 'react-dom/server';
// 可替换为penthouse、critical等你偏好的关键CSS提取工具
import { extractCritical } from 'emotion-server';

export default async function RootLayout({ children }: { children: ReactNode }) {
  // 先将页面内容渲染为HTML字符串
  const pageHtml = renderToString(<>{children}</>);
  // 提取首屏关键CSS
  const { css } = extractCritical(pageHtml);

  return (
    <html lang="zh-CN">
      <head>
        {/* 注入关键CSS */}
        <style dangerouslySetInnerHTML={{ __html: css }} />
        {/* 异步加载非关键CSS,避免阻塞首屏 */}
        <link 
          rel="preload" 
          href="/styles/non-critical.css" 
          as="style" 
          onLoad="this.onload=null;this.rel='stylesheet'" 
        />
        <noscript><link rel="stylesheet" href="/styles/non-critical.css" /></noscript>
      </head>
      <body dangerouslySetInnerHTML={{ __html: pageHtml }} />
    </html>
  );
}

2. Pages Router场景

在Pages Router中,可通过getServerSideProps渲染页面组件为HTML,再完成关键CSS提取:

import { renderToString } from 'react-dom/server';
import { extractCritical } from 'emotion-server';
import TargetPage from './TargetPage';

export async function getServerSideProps(context) {
  const pageHtml = renderToString(<TargetPage />);
  const { css } = extractCritical(pageHtml);

  return {
    props: { pageHtml, criticalCss: css },
  };
}

export default function Page({ pageHtml, criticalCss }) {
  return (
    <html>
      <head>
        <style dangerouslySetInnerHTML={{ __html: criticalCss }} />
      </head>
      <body dangerouslySetInnerHTML={{ __html: pageHtml }} />
    </html>
  );
}

3. 流式渲染场景的替代方案

流式渲染下无法在发送前获取完整HTML(内容分块输出),可采用以下思路:

  • 组件级CSS注入:使用App Router的useServerInsertedHTML或Pages Router的next/head,在首屏组件中直接注入自身所需的CSS,确保优先加载。
  • 依赖Next.js原生优化:启用CSS Modules,Next.js会自动按页面分割CSS,仅加载当前路由所需样式,虽不是基于HTML的精准提取,但已能大幅减少冗余。

4. 构建时静态HTML处理(静态生成项目)

如果是静态生成的Next.js项目,可在构建完成后用第三方工具批量提取关键CSS:

  1. 先完成Next.js项目构建,生成静态HTML文件
  2. 用penthouse或critical遍历HTML文件,提取首屏关键CSS
  3. 将提取的CSS注入到对应HTML的<head>中

示例Node.js脚本:

const fs = require('fs');
const path = require('path');
const critical = require('critical');

async function generateCriticalCss() {
  const htmlDir = path.join(__dirname, '.next', 'static', 'html');
  const htmlFiles = fs.readdirSync(htmlDir).filter(file => file.endsWith('.html'));

  for (const file of htmlFiles) {
    const filePath = path.join(htmlDir, file);
    const rawHtml = fs.readFileSync(filePath, 'utf8');

    const { css } = await critical.generate({
      html: rawHtml,
      width: 1300,
      height: 900,
    });

    // 替换HTML头部,注入关键CSS
    const updatedHtml = rawHtml.replace('</head>', `<style>${css}</style></head>`);
    fs.writeFileSync(filePath, updatedHtml);
  }
}

generateCriticalCss();

内容的提问来源于stack exchange,提问作者umalogic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 23:35:23