如何提升新建Next.js应用的Lighthouse性能:优化主线程与JS执行时间
从你的Lighthouse检测截图来看,主线程工作9.1秒、JS执行4.5秒是核心性能瓶颈,以下是针对性的优化方法:
一、削减JavaScript体积,减少不必要加载
用动态导入拆分非核心代码
Next.js默认支持代码拆分,但要主动对非首屏必需的组件(比如弹窗、次要功能模块)用next/dynamic延迟加载,避免一次性加载所有代码:import dynamic from 'next/dynamic' // 非首屏组件延迟加载,关闭SSR进一步减轻压力 const HeavyChartComponent = dynamic(() => import('../components/HeavyChart'), { ssr: false, loading: () => <p>加载中...</p> })同时确保
next.config.js开启压缩:module.exports = { compress: true, }清理冗余依赖与代码
用npm ls排查项目里的冗余依赖,把仅开发用的包(如测试工具、ESLint插件)放到devDependencies,避免打包进生产环境。另外用ESLint的no-unused-vars规则清理未使用的组件、变量和函数。优化第三方依赖
替换体积大的第三方库:比如用date-fns(按需导入)替代moment.js,用lucide-react替代react-icons(更小的图标库)。如果必须用未优化的第三方包,用next-transpile-modules处理:// next.config.js const withTM = require('next-transpile-modules')(['some-big-unoptimized-package']) module.exports = withTM({ /* 其他配置 */ })
二、优化JavaScript执行效率,减少主线程阻塞
拆分长任务,避免阻塞
把大数据处理、复杂DOM操作这类耗时任务拆成小片段,用requestIdleCallback放到浏览器空闲时段执行:function processLargeDataset(data) { let currentIndex = 0 const processChunk = () => { const endIndex = Math.min(currentIndex + 100, data.length) for (; currentIndex < endIndex; currentIndex++) { // 处理单条数据逻辑 } if (currentIndex < data.length) { requestIdleCallback(processChunk) } } requestIdleCallback(processChunk) }优化React渲染性能
- 用
React.memo缓存纯组件,避免不必要的重渲染:const UserCard = React.memo(({ name, avatar }) => { return <div className="user-card">{name}</div> }) - 用
useMemo和useCallback缓存计算结果与回调函数,防止因引用变化触发重渲染:const filteredList = useMemo(() => { return largeList.filter(item => item.category === activeCategory) }, [largeList, activeCategory]) const handleItemClick = useCallback((id) => { setSelectedId(id) }, [])
- 用
启用SWC编译器
Next.js 12+默认用SWC替代Babel,编译更快且产出的JS代码更高效,确保next.config.js没手动禁用:module.exports = { swcMinify: true, // 默认开启,不要关闭 }
三、辅助优化,减轻主线程负载
用next/image优化图片
图片解码会占用主线程资源,用Next.js的next/image组件自动压缩、懒加载图片,减少这部分开销:import Image from 'next/image' <Image src="/product.jpg" alt="产品图" width={600} height={400} priority // 首屏图片标记为优先加载 />延迟加载非关键脚本
把第三方统计、广告这类非核心脚本放到useEffect里动态加载,避免阻塞首屏渲染:useEffect(() => { const analyticsScript = document.createElement('script') analyticsScript.src = '/analytics.js' analyticsScript.async = true document.body.appendChild(analyticsScript) return () => document.body.removeChild(analyticsScript) }, [])定位具体瓶颈
用Chrome DevTools的Performance面板录制页面加载过程,找到耗时最长的任务(比如某个大组件的渲染、第三方脚本的执行),针对性优化。也可以用@next/bundle-analyzer分析打包体积:// next.config.js const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }) module.exports = withBundleAnalyzer({ /* 其他配置 */ })运行
ANALYZE=true npm run build查看包体积分布,找到大模块进行优化。
内容的提问来源于stack exchange,提问作者kartik Krishna sharma

