cover

放弃从 Next.js 迁移到 Astro.js

sorcererxw
Astro
Astro builds fast content sites, powerful web applications, dynamic server APIs, and everything in-between.
https://astro.build/

最近了解了一下 Astro.js,感觉非常诱人:

  • 可以构建出零 runtime 的前端页面,页面性能非常好
  • 可以同时兼容主流的 UI 框架的组件(比如 React,Vue,Svelte 等)
  • 大量官方和社区提供的插件能力,实现很多常规功能时候非常省力(比如 i18n,sitemap 等)
  • 与基础设施解耦,可以轻松得配置部署到不同的 PaaS 上(而不是像 Next.js 一样和 Vercel 强绑定)
  • 代码编写方式比 React 更加直白,一个 astro 文件就是一个组件,不需要定义 Class Component 并 export

看完文档,心心念念了好几天,索性试着用 Astro 重写了一遍我的博客前端。开发的过程中还是碰到了各种各样的问题:

  • 存量代码兼容成本不低

    存量项目迁移 Astro,如果想获得最完美的效果,肯定是将所有代码都是用 Astro 模式重写一遍。但是我目前维护了不止一个 Next.js 项目,不少组件是共享使用的,这些组件是不可能被重写成 Astro 的。

    那么是不是直接将 React 组件引入 Astro 页面当中就好了?对于大部分情况,是没错的。但是我的部分页面直接使用了 Next.js 的基础组件,比如 next/imagenext/linknext/navigate 等,这些和 Next.js 强绑定的组件就无法被引入 Astro 当中。诚然,Astro 也提供了对应的组件完成相同的效果,但正如前面所说,原来的那些代码是公共共享的,比如把 next/image 替换成 Astro 的 Image 组件,其他依赖了这些代码的项目就无法运行了。

  • IDE 支持不够完善

    一直以来,我都是使用 Goland 开发,并使用 pnpm workspace 维护了一个前端代码的 monorepo。当我在 monorepo 当中添加了一个 Astro 的工程项目,Goland 通过 Astro 插件可以解析 .astro 文件。但是 Goland 没办法正确解析 Astro 当中的 Typescript 语法。

    查询之后发现,目前在 monorepo + Typescript 模式下会出现这种情况。我理解目前还是因为 Astro 用户规模比较小,整体开发生态上还是欠完善。

    https://youtrack.jetbrains.com/issue/WEB-59503
  • 收益有限

    Next.js13 之后明确区分了 Server Component 和 Client Component,如果是纯静态的页面只需要尽可能使用 Server Component 实现完全的 SSR,避免 Client Component 引入前端 Javascript,也可以获得很不错的渲染性能。但是在一些不得不引入前端交互逻辑的页面,也可以使用 “use client” 轻松地将一个页面转换为 Client-Side 渲染。

    反观 Astro,它追求尽可能静态的页面输出,对于一些需要引入 Client 侧逻辑的地方,需要使用 script 包裹原始的 javascript 代码操作 dom,对于用惯了 React 当中绑定/hook 等能力的我来说,这太麻烦的。当然,我也可以把这类交互逻辑转换成 React 组件,并在 Astro 页面当中作为 client only 的组件引入,但这就会导致前端加载 React runtime,失去了使用 Astro 的意义。

最终还是放弃了这一次迁移,暂时不会真正上线和维护 Astro 版本的项目了。但不代表我不认可 Astro,使用下来还是有很多甜点的,只不过不适合我当前的开发需求。如果是一个全新的、纯静态的前端项目,使用 Astro 开发是非常合适的。