跳转到内容

从 Gatsby 迁移

这里有一些关键概念和迁移策略可以帮助你入门。利用我们文档的其余部分和我们的 Discord 社区 继续前进!

Gatsby 和 Astro 之间的主要相似之处

“Gatsby 和 Astro 之间的主要相似之处”部分

Gatsby 和 Astro 有一些相似之处,这将帮助你迁移项目

  • .astro 文件的语法与 JSX 类似。编写 Astro 应该会感到熟悉。

  • Astro 内置支持 Markdown,并集成了 MDX 文件。此外,你可以配置并继续使用许多现有的 Markdown 插件。

  • Astro 还提供了使用 React 组件的官方集成。请注意,在 Astro 中,React 文件**必须**具有 .jsx.tsx 扩展名。

  • Astro 支持安装 NPM 包,包括 React 库。你现有的许多依赖项都可以在 Astro 中工作。

  • 与 Gatsby 类似,Astro 项目可以是 SSG 或 带页面级预渲染的 SSR

Gatsby 和 Astro 之间的主要区别

“Gatsby 和 Astro 之间的主要区别”部分

当你用 Astro 重建 Gatsby 站点时,你会注意到一些重要的区别

  • Gatsby 项目是 React 单页应用程序,并使用 index.js 作为项目的根。Astro 项目是多页站点,index.astro 是你的主页。

  • Astro 组件不是编写为返回页面模板的导出函数。相反,你会将代码拆分为 JavaScript 的“代码围栏”和专门用于生成 HTML 的主体。

  • 本地文件数据:Gatsby 使用 GraphQL 从项目文件中检索数据。Astro 使用 ESM 导入和顶级 await 函数(例如 import.meta.glob()getCollection())从项目文件中导入数据。你可以在 Astro 项目中手动添加 GraphQL,但它默认不包含在内。

转换你的 Gatsby 项目

“转换你的 Gatsby 项目”部分

每个项目迁移都会有所不同,但从 Gatsby 转换到 Astro 时,你会执行一些常见操作。

创建一个新的 Astro 项目

“创建一个新的 Astro 项目”部分

使用你的包管理器的 create astro 命令来启动 Astro 的 CLI 向导,或从 Astro 主题展示中选择一个社区主题。

你可以将 --template 参数传递给 create astro 命令,以使用我们的官方启动器(例如 docsblogportfolio)启动一个新的 Astro 项目。或者,你可以从 GitHub 上的任何现有 Astro 仓库启动新项目

终端窗口
# launch the Astro CLI Wizard
npm create astro@latest
# create a new project with an official example
npm create astro@latest -- --template <example-name>

然后,将现有的 Gatsby 项目文件复制到你的新 Astro 项目中,放入 src 之外的独立文件夹中。

安装集成(可选)

“安装集成(可选)”部分

在将 Gatsby 项目转换为 Astro 时,你会发现安装一些 Astro 的可选集成很有用

  • @astrojs/react:在新 Astro 站点中重用现有 React UI 组件或继续使用 React 组件。

  • @astrojs/mdx:从你的 Gatsby 项目中引入现有 MDX 文件,或在新 Astro 站点中使用 MDX。

将你的代码放入 src

“将你的代码放入 src”部分

遵循 Astro 的项目结构

  1. 删除 Gatsby 的 public/ 文件夹。

    Gatsby 使用 public/ 目录作为其构建输出,因此你可以安全地丢弃此文件夹。你不再需要 Gatsby 站点的构建版本。(Astro 默认使用 dist/ 作为构建输出。)

  2. Gatsby 的 static/ 文件夹重命名public/,并将其用作 Astro 的 public/ 文件夹。

    Astro 使用一个名为 public/ 的文件夹来存放静态资源。你也可以将 static/ 的内容复制到你现有的 Astro public/ 文件夹中。

  3. 在重建站点时,根据需要将 Gatsby 的其他文件和文件夹(例如 componentspages 等)复制或移动到你的 Astro src/ 文件夹中,遵循 Astro 的项目结构

    Astro 的 src/pages/ 文件夹是一个特殊文件夹,用于基于文件的路由,从 .astro.md.mdx 文件创建你的站点页面和文章。你无需为你的 Astro、Markdown 和 MDX 文件配置任何路由行为。

    所有其他文件夹都是可选的,你可以按照自己喜欢的方式组织 src/ 文件夹的内容。Astro 项目中其他常见的文件夹包括 src/layouts/src/componentssrc/stylessrc/scripts

提示:将 JSX 文件转换为 .astro 文件

“提示:将 JSX 文件转换为 .astro 文件”部分

以下是将 Gatsby .js 组件转换为 .astro 组件的一些提示

  1. 只使用现有 Gatsby 组件函数的 return() 作为你的 HTML 模板。

  2. 将任何 Gatsby 或 JSX 语法更改为 Astro 语法或 HTML Web 标准。例如,这包括 <Link to="">{children}className

  3. 将所有必要的 JavaScript(包括导入语句)移动到“代码围栏”(---中。注意:在 Astro 中,用于条件渲染内容的 JavaScript 通常直接写在 HTML 模板内。

  4. 使用 Astro.props 访问之前传递给 Gatsby 函数的任何附加 props。

  5. 决定是否需要将任何导入的组件也转换为 Astro。安装了官方 React 集成后,你可以在 Astro 文件中使用现有 React 组件。但是,你可能希望将它们转换为 .astro 组件,特别是如果它们不需要交互的话!

  6. 删除任何 GraphQL 查询。改为使用 import 和 import.meta.glob() 语句来查询本地文件。

参阅Gatsby 博客启动模板转换为 Astro 的逐步示例

比较:.jsx.astro

“比较:.jsx 与 .astro”部分

比较以下 Gatsby 组件和相应的 Astro 组件

component.jsx
import * as React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Header from "./header"
import Footer from "./footer"
import "./layout.css"
const Component = ({ message, children }) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div style={{ margin: `0`, maxWidth: `960`}}>{message}</div>
<main>{children}</main>
<Footer siteTitle={data.site.siteMetadata} />
</>
)
}
export default Component

你可能会发现,首先将 Gatsby 布局和模板转换为Astro 布局组件会很有帮助。

每个 Astro 页面都明确要求存在 <html><head><body> 标签,因此在页面之间重用布局文件很常见。Astro 使用 <slot /> 代替 React 的 {children} prop 来表示页面内容,不需要导入语句。你的 Gatsby layout.js 和模板将不包含这些。

注意标准的 HTML 模板和对 <head> 的直接访问

src/layouts/Layout.astro
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<title>Astro</title>
</head>
<body>
<!-- Wrap the slot element with your existing layout templating -->
<slot />
</body>
</html>

你可能还希望重用 Gatsby 的 src/components/seo.js 中的代码,以包含额外的站点元数据。请注意,Astro 既不使用 <Helmet> 也不使用 <Header>,而是直接创建 <head>。你可以导入和使用组件,即使在 <head> 中,也可以分离和组织页面内容。

在 Gatsby 中,你的页面和文章可能存在于 src/pages/ 中,或者位于 src 之外的另一个文件夹中,例如 content。在 Astro 中,你所有的页面内容都必须位于 src/ 中,除非你使用内容集合

你现有的 Gatsby JSX (.js) 页面需要从 JSX 文件转换为 .astro 页面。你不能在 Astro 中使用现有的 JSX 页面文件。

这些 .astro 页面必须位于 src/pages/ 内,并且会根据其文件路径自动生成页面路由。

Astro 内置支持 Markdown,并提供 MDX 文件的可选集成。你现有的Markdown 和 MDX 文件可以重用,但可能需要对它们的 frontmatter 进行一些调整,例如添加Astro 的特殊 layout frontmatter 属性。它们也可以放置在 src/pages/ 中,以利用自动基于文件的路由。

或者,你可以在 Astro 中使用内容集合来存储和管理你的内容。你将自行检索内容并动态生成这些页面

由于 Astro 输出原始 HTML,因此可以使用构建步骤的输出来编写端到端测试。如果你能够匹配旧 Gatsby 站点的标记,则之前编写的任何端到端测试都可能开箱即用。Jest 和 React Testing Library 等测试库可以导入并在 Astro 中用于测试你的 React 组件。

更多信息请参阅 Astro 的测试指南

重新利用配置文件

“重新利用配置文件”部分

Gatsby 有几个顶级配置文件,其中还包括站点和页面元数据,并用于路由。你不会在 Astro 项目中使用任何这些 gatsby-*.js 文件,但在构建 Astro 项目时,可能有一些内容可以重用

  • gatsby-config.js:将你的 siteMetadata: {} 移动到 src/data/siteMetadata.js(或 siteMetadata.json)中,以便将有关你站点的数据(标题、描述、社交账号等)导入到页面布局中。

  • gatsby-browser.js:考虑将此处使用的任何内容直接添加到你的主布局<head> 标签中。

  • gatsby-node.js:你不需要在 Astro 中创建自己的节点,但查看此文件中的 schema 可能会帮助你在 Astro 项目中定义类型。

  • gatsby-ssr.js:如果你选择在 Astro 中使用 SSR,你将在 astro.config.mjs 中直接添加和配置你选择的 SSR 适配器

参考:转换为 Astro 语法

“参考:转换为 Astro 语法”部分

以下是一些你需要转换为 Astro 语法的 Gatsby 特有语法的示例。在 Astro 组件编写指南中查看更多Astro 与 JSX 之间的差异

将所有 Gatsby <Link to=""><NavLink> 等组件转换为 HTML <a href=""> 标签。

<Link to="/blog">Blog</Link>
<a href="/blog">Blog</a>

Astro 不使用任何特殊的链接组件,但你可以构建自己的 <Link> 组件。然后,你可以像使用任何其他组件一样导入和使用此 <Link>

src/components/Link.astro
---
const { to } = Astro.props
---
<a href={to}><slot /></a>

如有必要,更新所有文件导入,以精确引用相对文件路径。这可以通过导入别名或完整编写相对路径来完成。

请注意,.astro 和其他几种文件类型必须使用其完整的文件扩展名进行导入。

src/pages/authors/Fred.astro
---
import Card from `../../components/Card.astro`;
---
<Card />

Gatsby Children Props 到 Astro

“Gatsby Children Props 到 Astro”部分

将所有 {children} 实例转换为 Astro 的 <slot />。Astro 不需要将 {children} 作为函数 prop 接收,并且会自动在 <slot /> 中渲染子内容。

src/components/MyComponent
---
---
export default function MyComponent(props) {
return (
<div>
{props.children}
</div>
);
}
<div>
<slot />
</div>

传递多组子组件的 React 组件可以使用命名插槽迁移到 Astro 组件。

查看更多关于Astro 中 <slot /> 的具体用法

你可能需要将任何 CSS-in-JS 库(例如 styled-components)替换为 Astro 中其他可用的 CSS 选项。

如有必要,将所有内联样式对象(style={{ fontWeight: "bold" }})转换为内联 HTML 样式属性(style="font-weight:bold;")。或者,使用Astro <style> 标签来实现作用域 CSS 样式。

src/components/Card.astro
<div style={{backgroundColor: `#f4f4f4`, padding: `1em`}}>{message}</div>
<div style="background-color: #f4f4f4; padding: 1em;">{message}</div>

安装 Tailwind Vite 插件后即可支持 Tailwind。无需对你现有的 Tailwind 代码进行任何更改!

Gatsby 中通过在 gatsby-browser.js 中导入 CSS 来实现全局样式。在 Astro 中,你将直接将 .css 文件导入到主布局组件中以实现全局样式。

查看更多关于在 Astro 中设置样式的信息。

Gatsby 图像插件到 Astro

“Gatsby 图像插件到 Astro”部分

将 Gatsby 的 <StaticImage /><GatsbyImage /> 组件转换为Astro 自己的图像集成组件,或转换为 React 组件中适当的标准 HTML <img> / JSX <img /> 标签。

src/pages/index.astro
---
import { Image } from 'astro:assets';
import rocket from '../assets/rocket.png';
---
<Image src={rocket} alt="A rocketship in space." />
<img src={rocket.src} alt="A rocketship in space.">

Astro 的 <Image /> 组件仅在 .astro.mdx 文件中有效。参阅其组件属性的完整列表,并注意其中一些属性将与 Gatsby 的属性不同。

要继续在 Markdown (.md) 文件中使用标准 Markdown 语法(![]())的图片,你可能需要更新链接。对于本地图片,在 .md 文件中直接使用 HTML <img> 标签不受支持,必须转换为 Markdown 语法。

src/pages/post-1.md
# My Markdown Page
<!-- Local image stored at src/assets/stars.png -->
![A starry night sky.](../assets/stars.png)

在 React (.jsx) 组件中,使用标准的 JSX 图像语法(<img />)。Astro 不会优化这些图像,但你可以安装和使用 NPM 包以获得更大的灵活性。

你可以在图像指南中了解更多关于在 Astro 中使用图像的信息。

Gatsby GraphQL 到 Astro

“Gatsby GraphQL 到 Astro”部分

删除所有对 GraphQL 查询的引用,改为使用 import.meta.glob() 来访问本地文件中的数据。

或者,如果使用内容集合,请使用 getEntry()getCollection() 查询你的 Markdown 和 MDX 文件。

这些数据请求在 Astro 组件的 frontmatter 中使用数据进行。

src/pages/index.astro
---
import { graphql } from "gatsby"
import { getCollection } from 'astro:content';
// Get all `src/content/blog/` entries
const allBlogPosts = await getCollection('blog');
// Get all `src/pages/posts/` entries
const allPosts = Object.values(import.meta.glob('../pages/post/*.md', { eager: true }));
---
export const pageQuery = graphql`
{
allMarkdownRemark(sort: { frontmatter: { date: DESC } }) {
nodes {
excerpt
fields {
slug
}
frontmatter {
date(formatString: "MMMM DD, YYYY")
title
description
}
}
}
}
`

引导示例:Gatsby 布局到 Astro

“引导示例:Gatsby 布局到 Astro”部分

此示例将 Gatsby 博客启动器中的主项目布局(layout.js)转换为 src/layouts/Layout.astro

此页面布局在访问主页时显示一个页头,在访问所有其他页面时显示带有返回主页链接的不同页头。

  1. 识别 return() JSX。

    layout.js
    import * as React from "react"
    import { Link } from "gatsby"
    const Layout = ({ location, title, children }) => {
    const rootPath = `${__PATH_PREFIX__}/`
    const isRootPath = location.pathname === rootPath
    let header
    if (isRootPath) {
    header = (
    <h1 className="main-heading">
    <Link to="/">{title}</Link>
    </h1>
    )
    } else {
    header = (
    <Link className="header-link-home" to="/">
    Home
    </Link>
    )
    }
    return (
    <div className="global-wrapper" data-is-root-path={isRootPath}>
    <header className="global-header">{header}</header>
    <main>{children}</main>
    <footer>
    © {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.gatsbyjs.com">Gatsby</a>
    </footer>
    </div>
    )
    }
    export default Layout
  2. 创建 Layout.astro 并添加此 return 值,转换为 Astro 语法

    请注意

    • {new Date().getFullYear()} 完美运行 🎉
    • {children} 变为 <slot /> 🦥
    • className 变为 class 📛
    • Gatsby 变为 Astro 🚀
    src/layouts/Layout.astro
    ---
    ---
    <div class="global-wrapper" data-is-root-path={isRootPath}>
    <header class="global-header">{header}</header>
    <main><slot /></main>
    <footer>
    © {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.astro.build">Astro</a>
    </footer>
    </div>
  3. 添加页面外壳,使你的布局为每个页面提供必要的 HTML 文档部分

    src/layouts/Layout.astro
    ---
    ---
    <html>
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <title>Astro</title>
    </head>
    <body>
    <div class="global-wrapper" data-is-root-path={isRootPath}>
    <header class="global-header">{header}</header>
    <main>
    <slot />
    </main>
    <footer>
    &#169; {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.astro.build">Astro</a>
    </footer>
    </div>
    </body>
    </html>
  4. 添加任何所需的导入、props 和 JavaScript

    在 Astro 中根据页面路由和标题有条件地渲染页头

    • 通过 Astro.props 提供 props。(请记住:你的 Astro 模板从其 frontmatter 访问 props,而不是传递到函数中。)
    • 使用三元运算符,如果这是主页,则显示一个标题,否则显示另一个标题。
    • 移除 {header}{isRootPath} 的变量,因为它们不再需要。
    • 将 Gatsby 的 <Link/> 标签替换为 <a> 锚点标签。
    • 使用 class 而不是 className
    • 从你的项目中导入本地样式表,使类名生效。
    src/layouts/Layout.astro
    ---
    import '../styles/style.css';
    const { title, pathname } = Astro.props
    ---
    <html>
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <title>Astro</title>
    </head>
    <body>
    <div class="global-wrapper">
    <header class="global-header">
    { pathname === "/"
    ?
    <h1 class="main-heading">
    <a href="/">{title}</a>
    </h1>
    :
    <h1 class="main-heading">
    <a class="header-link-home" href="/">Home</a>
    </h1>
    }
    </header>
    <main>
    <slot />
    </main>
    <footer>
    &#169; {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.astro.build">Astro</a>
    </footer>
    </div>
    </body>
    </html>
  5. 更新 index.astro 以使用此新布局,并向其传递必要的 titlepathname props

    src/pages/index.astro
    ---
    import Layout from '../layouts/Layout.astro';
    const pagePathname = Astro.url.pathname
    ---
    <Layout title="Home Page" pathname={pagePathname}>
    <p>Astro</p>
    </Layout>
  6. 要测试条件页头,请使用相同的模式创建第二个页面 about.astro

    src/pages/about.astro
    ---
    import Layout from '../layouts/Layout.astro';
    const pagePathname = Astro.url.pathname
    ---
    <Layout title="About" pathname={pagePathname}>
    <p>About</p>
    </Layout>

    你只在访问“关于”页面时才能看到“主页”链接。

更多迁移指南

贡献 社区 赞助