首页 > 其他分享 >Next.js 14 性能优化:从首屏加载到运行时优化的最佳实践

Next.js 14 性能优化:从首屏加载到运行时优化的最佳实践

时间:2024-12-26 15:31:29浏览次数:5  
标签:function return 14 Next export import const 优化

在现代 Web 应用中,性能优化直接影响用户体验和业务转化。Next.js 14 提供了多种内置的性能优化特性,今天我们就来深入探讨如何充分利用这些特性,以及一些实用的优化技巧。

图片和字体优化

1. 图片优化

Next.js 的 Image 组件供了强大的图片优化功能:

// components/OptimizedImage.tsx
import Image from 'next/image';
import { useState } from 'react';

interface OptimizedImageProps {
  src: string;
  alt: string;
  width: number;
  height: number;
}

export function OptimizedImage({
  src,
  alt,
  width,
  height
}: OptimizedImageProps) {
  const [isLoading, setLoading] = useState(true);

  return (
    <div className="relative overflow-hidden">
      <Image
        src={src}
        alt={alt}
        width={width}
        height={height}
        quality={75} // 默认图片质量
        placeholder="blur" // 使用模糊占位
        blurDataURL="data:image/jpeg;base64,..." // 生成的 base64 图片
        className={`
          duration-700 ease-in-out
          ${isLoading ? 'scale-110 blur-2xl' : 'scale-100 blur-0'}
        `}
        onl oadingComplete={() => setLoading(false)}
        priority={false} // 是否优先加载
      />
    </div>
  );
}

// 使用自定义图片加载器
const imageLoader = ({ src, width, quality }) => {
  return `https://your-cdn.com/${src}?w=${width}&q=${quality || 75}`;
};

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    loader: 'custom',
    loaderFile: './lib/imageLoader.ts',
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    formats: ['image/webp'],
  },
};

2. 字体优化

Next.js 14 提供了内置的字体优化:

// app/fonts.ts
import { Inter, Roboto_Mono } from 'next/font/google';

export const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  preload: true,
  fallback: ['system-ui', 'arial'],
  adjustFontFallback: true, // 自动调整回退字体
});

export const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
});

// app/layout.tsx
import { inter } from './fonts';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

// 自定义字体加载
import localFont from 'next/font/local';

const myFont = localFont({
  src: [
    {
      path: '../public/fonts/font-regular.woff2',
      weight: '400',
      style: 'normal',
    },
    {
      path: '../public/fonts/font-bold.woff2',
      weight: '700',
      style: 'normal',
    },
  ],
  display: 'swap',
  preload: true,
});

动态导入和代码分割

1. 组件动态导入

// components/DynamicComponent.tsx
import dynamic from 'next/dynamic';
import { Suspense } from 'react';

// 基础动态导入
const DynamicHeader = dynamic(() => import('./Header'), {
  loading: () => <p>Loading...</p>,
  ssr: true, // 是否服务端渲染
});

// 带有自定义加载的动态导入
const DynamicChart = dynamic(
  () => import('./Chart').then(mod => mod.Chart),
  {
    loading: () => <ChartSkeleton />,
    ssr: false, // 禁用服务端渲染
  }
);

// 使用 Suspense 包裹动态组件
export function DashboardPage() {
  return (
    <div>
      <DynamicHeader />
      <Suspense fallback={<ChartSkeleton />}>
        <DynamicChart />
      </Suspense>
    </div>
  );
}

2. 路由分组和懒加载

// app/(marketing)/layout.tsx
import { Suspense } from 'react';

// 营销相关页面的布局
export default function MarketingLayout({
  children
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="marketing-layout">
      <Suspense fallback={<NavSkeleton />}>
        <Navigation />
      </Suspense>
      {children}
    </div>
  );
}

// app/(dashboard)/layout.tsx
// 仪表板相关页面的布局
export default function DashboardLayout({
  children
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="dashboard-layout">
      <Suspense fallback={<SidebarSkeleton />}>
        <Sidebar />
      </Suspense>
      <main>{children}</main>
    </div>
  );
}

缓存策略优化

1. 数据缓存

// lib/cache.ts
import { cache } from 'react';
import { Redis } from '@upstash/redis';

const redis = new Redis({
  url: process.env.REDIS_URL,
  token: process.env.REDIS_TOKEN,
});

// 使用 React 缓存
export const getCachedData = cache(async (key: string) => {
  // 首先尝试从 Redis 获取
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);

  // 如果没有缓存,则获取新数据
  const data = await fetchData(key);

  // 存入 Redis
  await redis.set(key, JSON.stringify(data), {
    ex: 3600 // 1小时过期
  });

  return data;
});

// 使用示例
async function ProductPage({ id }: { id: string }) {
  const product = await getCachedData(`product:${id}`);
  return <ProductDetails product={product} />;
}

2. 静态生成优化

// app/products/[id]/page.tsx
import { generateMetadata } from 'next';

// 生成静态路由
export async function generateStaticParams() {
  const products = await getTopProducts();

  return products.map((product) => ({
    id: product.id,
  }));
}

// 静态元数据
export async function generateMetadata({ params }: {
  params: { id: string }
}): Promise<Metadata> {
  const product = await getProduct(params.id);

  return {
    title: product.name,
    description: product.description,
    openGraph: {
      images: [product.image],
    },
  };
}

// 页面组件
export default async function ProductPage({
  params
}: {
  params: { id: string }
}) {
  const product = await getProduct(params.id);

  return (
    <div>
      <h1>{product.name}</h1>
      <ProductDetails product={product} />
    </div>
  );
}

首屏加载优化

1. 流式渲染

// app/page.tsx
import { Suspense } from 'react';
import { headers } from 'next/headers';

async function SlowComponent() {
  const headersList = headers();
  const userAgent = headersList.get('user-agent');

  // 模拟慢速数据加载
  await new Promise(resolve => setTimeout(resolve, 2000));

  return (
    <div>
      <p>User Agent: {userAgent}</p>
    </div>
  );
}

export default function HomePage() {
  return (
    <div>
      <h1>即时加载的内容</h1>

      <Suspense fallback={<LoadingSkeleton />}>
        <SlowComponent />
      </Suspense>

      <Suspense fallback={<CardsSkeleton />}>
        <PopularProducts />
      </Suspense>

      <Suspense fallback={<FeedSkeleton />}>
        <RecentActivity />
      </Suspense>
    </div>
  );
}

2. 预加载数据

// lib/prefetch.ts
export async function prefetchData() {
  // 预加载关键数据
  const promises = [
    prefetchNavigation(),
    prefetchUserData(),
    prefetchPopularProducts(),
  ];

  await Promise.all(promises);
}

// app/layout.tsx
export default async function RootLayout({
  children
}: {
  children: React.ReactNode
}) {
  // 在布局组件中预加载数据
  await prefetchData();

  return (
    <html>
      <body>{children}</body>
    </html>
  );
}

Core Web Vitals 优化

1. 性能监控

// lib/analytics.ts
export function reportWebVitals({
  id,
  name,
  label,
  value,
}: {
  id: string;
  name: string;
  label: string;
  value: number;
}) {
  // 发送性能指标到分析服务
  fetch('/api/analytics', {
    method: 'POST',
    body: JSON.stringify({
      id,
      name,
      label,
      value,
      // 添加其他上下文信息
      page: window.location.pathname,
      timestamp: Date.now(),
    }),
  });
}

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    instrumentationHook: true,
  },
};

// instrumentation.ts
export function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    // 服务端监控
    require('./monitoring/server').setup();
  }
}

2. 性能优化实践

// components/OptimizedList.tsx
import { useVirtualizer } from '@tanstack/react-virtual';
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver';

// 虚拟列表优化
export function OptimizedList({ items }: { items: any[] }) {
  const parentRef = useRef<HTMLDivElement>(null);

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
  });

  return (
    <div ref={parentRef} className="h-[500px] overflow-auto">
      <div
        style={{
          height: `${virtualizer.getTotalSize()}px`,
          position: 'relative',
        }}
      >
        {virtualizer.getVirtualItems().map((virtualItem) => (
          <div
            key={virtualItem.key}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: `${virtualItem.size}px`,
              transform: `translateY(${virtualItem.start}px)`,
            }}
          >
            <ListItem item={items[virtualItem.index]} />
          </div>
        ))}
      </div>
    </div>
  );
}

// 图片懒加载优化
export function LazyImage({ src, alt }: { src: string; alt: string }) {
  const imgRef = useRef<HTMLImageElement>(null);
  const { isIntersecting } = useIntersectionObserver(imgRef);

  return (
    <img
      ref={imgRef}
      src={isIntersecting ? src : ''}
      alt={alt}
      loading="lazy"
      decoding="async"
    />
  );
}

3. 构建优化

// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});

/** @type {import('next').NextConfig} */
const nextConfig = {
  // 优化构建配置
  poweredByHeader: false,
  compress: true,
  productionBrowserSourceMaps: false,

  // 优化图片配置
  images: {
    minimumCacheTTL: 60,
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },

  // 实验性功能
  experimental: {
    optimizeCss: true, // 启用 CSS 优化
    scrollRestoration: true, // 启用滚动位置恢复
    serverActions: true, // 启用服务端操作
  },

  // webpack 配置
  webpack: (config, { dev, isServer }) => {
    // 优化生产环境构建
    if (!dev && !isServer) {
      config.optimization.splitChunks = {
        chunks: 'all',
        minSize: 20000,
        maxSize: 244000,
        minChunks: 1,
        maxAsyncRequests: 30,
        maxInitialRequests: 30,
        cacheGroups: {
          defaultVendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
            reuseExistingChunk: true,
          },
          default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true,
          },
        },
      };
    }

    return config;
  },
};

module.exports = withBundleAnalyzer(nextConfig);

写在最后

Next.js 14 提供了丰富的性能优化工具和特性。在实际应用中,需要注意以下几点:

  1. 合理使用图片和字体优化
  2. 实施有效的代码分割策略
  3. 优化数据缓存和预加载
  4. 监控和优化 Core Web Vitals
  5. 持续进行构建优化

在下一篇文章中,我们将深入探讨 Next.js 14 的部署与运维策略。如果你有任何问题或建议,欢迎在评论区讨论!

如果觉得这篇文章对你有帮助,别忘了点个赞

标签:function,return,14,Next,export,import,const,优化
From: https://blog.csdn.net/ChengFengTech/article/details/144728006

相关文章

  • Next.js 14 基础入门:从项目搭建到核心概念
    Next.js14带来了许多激动人心的新特性,包括局部渲染、ServerActions增强等。作为一名前端开发者,我最近在项目中升级到了Next.js14,今天就来分享一下从项目搭建到实际应用的完整过程。项目初始化首先,让我们创建一个全新的Next.js14项目:#使用create-next-app创建......
  • Multi Commander(多标签文件管理器) v14.5.0.3054
    MultiCommander中文版是一个多标签文件管理器,是一个标准的Windows资源管理器的替代软件,该最大的特色是带有双面板、并且还可以启用标签页形式浏览,在界面底部还带各种常见的功能按钮。软件功能1、集成多种常用功能的底部按钮面板:第一行的功能包括了刷新、查看、编辑、拷......
  • 新能源汽车门店运营优化:项目管理工具的实践与探索
    项目管理工具在新能源汽车门店运营中发挥着至关重要的作用,它们通过优化任务管理、增强团队协作、提升资源利用效率以及加强数据分析与决策支持等多个方面,显著提升了门店的运营效率。以下是对这些方面的详细阐述:一、优化任务管理项目管理工具能够帮助新能源汽车门店清晰地列出所......
  • 【开源】绿联145W能量π外壳
    绿联这个移动电源做工和能量还是给力的,但是最近有一个Type-C口既不能充也不能放了,拆解过程非常痛苦,外壳扣太紧了,最后狠下心破坏性拆解掉。电源板是双层堆叠的,拆开上板再插回去后那个坏掉的口子居然复活了。先前可能是内部电路出了什么问题,芯片进入了锁死的状态。接下来就是设计外......
  • 9.14
    6. 使用SparkStreaming实时处理数据概述SparkStreaming是Spark生态系统中的流式数据处理组件。本文将介绍如何使用SparkStreaming实现实时数据处理。内容SparkStreaming的基本概念从Socket数据源读取数据实时单词统计示例代码示例valconf=newSparkC......
  • 水库水位监测系统与气象数据结合:优化水库管理决策
    在水库管理领域,传统的单一水位监测方式已难以满足日益复杂的水资源调配和安全保障需求。如今,将水库水位监测系统与气象数据紧密结合,正成为优化水库管理决策、提升水资源利用效率和保障水库安全运行的关键手段。一、水库水位监测系统的基石作用水库水位监测系统是水库管理的......
  • 【无人机】无人机测绘路径优化策略与实践:探索高效、精准的测绘技术路径
    ......
  • 【物联网技术与应用】实验14:PS2操纵杆实验
    实验14PS2操纵杆实验【实验介绍】操纵杆是一种输入设备,由一个可在基座上旋转并向其控制的设备报告及角度和方向的操作杆组成,操纵杆通常用于控制视频游戏和机器人,这里使用操纵杆ps2。【实验组件】●ArduinoUno主板*1●USB数据线*1●PS2游戏手柄模块*1●面包......
  • 上交团队发表研究,通过组织学图像预测肿瘤微环境,优化癌症预后预测|顶刊精析·24-12-26
    小罗碎碎念今天分享的这篇文章于2024-05-21发表于CellReportsMedicine。这篇文章介绍了一个深度学习系统,该系统能够通过分析组织学图像来预测肿瘤微环境(TME),并提高癌症患者的预后准确性。角色姓名单位名称(中文)第一作者RuitianGao上海交通大学生命科学与生物技术学院......
  • 提升网站流量的秘密:SEO关键词优化与长尾关键词解析
    内容概要在数字化时代,网站流量的提升与搜索引擎优化(SEO)密切相关。SEO不仅是指通过技术手段提升网站在搜索引擎中的排名,更是优化用户体验及内容质量的重要环节。关键词优化作为SEO的核心组成部分,能够有效帮助网站吸引目标访客,从而增加页面的曝光率和转化率。首先,关键词优化的......