前端 SSG:别让你的网站加载速度慢得像蜗牛
前端 SSG:别让你的网站加载速度慢得像蜗牛
毒舌时刻
这网站加载速度慢得能让我泡杯咖啡回来还没好。
各位前端同行,咱们今天聊聊前端 SSG(静态站点生成)。别告诉我你还在使用纯客户端渲染,那感觉就像在没有预加载的情况下开车——能开,但起步慢得要命。
为什么你需要 SSG
最近看到一个项目,每次加载都要重新获取数据,用户体验差。我就想问:你是在做网站还是在做实时应用?
反面教材
// 反面教材:纯客户端渲染 // App.jsx import React, { useState, useEffect } from 'react'; function App() { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { async function fetchPosts() { setLoading(true); try { const response = await fetch('https://api.example.com/posts'); const data = await response.json(); setPosts(data); } catch (error) { console.error('Error fetching posts:', error); } finally { setLoading(false); } } fetchPosts(); }, []); return ( <div> <h1>我的博客</h1> {loading ? <div>加载中...</div> : ( <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> </div> ))} </div> )} </div> ); } export default App; 毒舌点评:这代码,就像在每次启动时都要重新启动发动机,慢得要命。
正确姿势
1. Next.js SSG
// 正确姿势:Next.js SSG // 1. 安装依赖 // npx create-next-app@latest // 2. 页面组件 // pages/index.js import React from 'react'; export async function getStaticProps() { // 构建时获取数据 const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); return { props: { posts }, revalidate: 60 // 每 60 秒重新生成 }; } export default function Home({ posts }) { return ( <div> <h1>我的博客</h1> <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> </div> ))} </div> </div> ); } // 3. 动态路由 // pages/posts/[id].js import React from 'react'; export async function getStaticPaths() { // 构建时生成所有可能的路径 const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); const paths = posts.map(post => ({ params: { id: post.id.toString() } })); return { paths, fallback: false }; } export async function getStaticProps({ params }) { // 构建时获取数据 const res = await fetch(`https://api.example.com/posts/${params.id}`); const post = await res.json(); return { props: { post } }; } export default function Post({ post }) { return ( <div> <h1>{post.title}</h1> <p>{post.content}</p> </div> ); } 2. Astro SSG
// 正确姿势:Astro SSG // 1. 安装依赖 // npm create astro@latest // 2. 页面组件 // src/pages/index.astro --- // 构建时获取数据 const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); --- <html> <head> <title>我的博客</title> </head> <body> <h1>我的博客</h1> <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> </div> ))} </div> </body> </html> // 3. 动态路由 // src/pages/posts/[id].astro --- // 构建时获取数据 const { id } = Astro.params; const res = await fetch(`https://api.example.com/posts/${id}`); const post = await res.json(); --- <html> <head> <title>{post.title}</title> </head> <body> <h1>{post.title}</h1> <p>{post.content}</p> </body> </html> 3. Gatsby SSG
// 正确姿势:Gatsby SSG // 1. 安装依赖 // npm install -g gatsby-cli // gatsby new my-site // 2. 配置数据源 // gatsby-config.js module.exports = { plugins: [ { resolve: 'gatsby-source-rest-api', options: { endpoints: ['https://api.example.com/posts'] } } ] }; // 3. 页面组件 // src/pages/index.js import React from 'react'; import { graphql } from 'gatsby'; export const query = graphql` query { allRestApiPosts { edges { node { id title content } } } } `; export default function Home({ data }) { const posts = data.allRestApiPosts.edges.map(edge => edge.node); return ( <div> <h1>我的博客</h1> <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> </div> ))} </div> </div> ); } // 4. 动态页面 // src/templates/post.js import React from 'react'; import { graphql } from 'gatsby'; export const query = graphql` query($id: String!) { restApiPosts(id: { eq: $id }) { title content } } `; export default function Post({ data }) { const post = data.restApiPosts; return ( <div> <h1>{post.title}</h1> <p>{post.content}</p> </div> ); } // 5. 创建动态页面 // gatsby-node.js exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions; const result = await graphql(` query { allRestApiPosts { edges { node { id } } } } `); result.data.allRestApiPosts.edges.forEach(edge => { createPage({ path: `/posts/${edge.node.id}`, component: path.resolve('./src/templates/post.js'), context: { id: edge.node.id } }); }); }; 毒舌点评:这才叫前端 SSG,构建时生成静态页面,加载速度快,用户体验好,再也不用担心页面加载慢的问题了。