跳转到内容

从 Gatsby 迁移

以下是一些关键概念和迁移策略,帮助你开始。使用我们的其他文档和我们的 Discord 社区 继续进行!

Gatsby 和 Astro 之间的关键相似性

段落标题 Gatsby 和 Astro 之间的关键相似性

Gatsby 和 Astro 共享一些相似性,这将帮助你迁移你的项目:

Gatsby 和 Astro 之间的关键差异

段落标题 Gatsby 和 Astro 之间的关键差异

当你在 Astro 中重建你的 Gatsby 站点时,你会注意到一些重要的差异:

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

  • Astro 组件不是以返回页面模板的出口函数形式编写的。相反,你将你的代码分割为专门为你的 JavaScript 设计的 “代码围栏” 和专门为你生成的 HTML 设计的主体。

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

转换你的 Gatsby 项目

段落标题 转换你的 Gatsby 项目

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

创建一个新的 Astro 项目

段落标题 创建一个新的 Astro 项目

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

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

终端窗口
# 启动 Astro CLI 向导
npm create astro@latest
# 使用官方示例创建一个新项目
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,包括 import 语句,都放入“代码围栏” (---)中。注意:在 Astro 中,经常会直接在 HTML 模板内编写条件渲染内容的 JavaScript。

  4. 使用Astro.props来访问之前传递给你的 Gatsby 函数的任何其他 props。

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

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

查看 Gatsby’s Blog 启动模板转换步骤示例

比较以下的 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="zh">
<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>
<!-- 将 slot 元素包裹在你现有的布局模板中 -->
<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 中的 内容集合 来存储和管理你的内容。作为集合的一部分时,Markdown 和 MDX 文件将位于 src/content/ 内的文件夹中。你将需要自己获取内容并动态生成这些页面

由于 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">博客</Link>
<a href="/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 />

将任何 {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 /> 使用的信息.

Gatsby 样式转换为 Astro

段落标题 Gatsby 样式转换为 Astro

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

如果需要,将内联样式对象(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 集成 后支持 Tailwind。不需要对现有的 Tailwind 代码进行任何更改!

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

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

Gatsby 图像插件转换为 Astro

段落标题 Gatsby 图像插件转换为 Astro

根据情况在你的 React 组件中将 Gatsby 的 <StaticImage /><GatsbyImage /> 组件转换为 Astro 自己的图像集成组件 或者转化成 标准的 HTML <img> / JSX <img /> 标签

src/pages/index.astro
---
import { Image } from 'astro:assets';
import rocket from '../assets/rocket.png';
---
<Image src={rocket} alt="太空中的火箭飞船。" />
<img src={rocket.src} alt="太空中的火箭飞船。">

Astro 的 <Image /> 组件只能在 .astro.mdx 文件中工作。查看该组件可用的完整组件属性列表,并注意它与 Gatsby 的属性有一些不同。

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

src/pages/post-1.md
# 我的 Markdown 页面
<!-- 存储在 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 查询的地方,然后使用 Astro.glob() 来访问你的本地文件中的数据。

或者,如果使用内容集合,使用 getEntry()getCollection()src/content/ 中查询你的 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 = await Astro.glob('../pages/posts/*.md');
---
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

此示例将主项目布局(layout.js)从 Gatsby 的博客起始器转换为 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 中页面路由和标题条件性地渲染 header:

    • 通过 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="主页" pathname={pagePathname}>
    <p>Astro</p>
    </Layout>
  6. 为了测试条件 header,使用相同的模式创建第二个页面 about.astro

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

    当你访问关于页面时,你应该只看到指向 “主页” 的链接。

更多迁移指南

贡献

你有什么想法?

社区