发表于 2023.03.16
大家好,很高兴地向大家宣布,Modern.js v2 版本已经正式发布了!
Modern.js 是字节跳动 Web Infra 团队开源的一套 Web 工程体系。在开源以来的一年多时间里,Modern.js 保持稳定的迭代节奏,数十位贡献者参与了开发,累计提交 2000+ 个 Pull Request,并支持了 Rspack 构建、嵌套路由、流式渲染等新特性。
在这篇文章里,我们会和大家一起聊一聊 Modern.js 在过去一年多时间里的变化。
Modern.js v2 官网
首先介绍一下我们为什么要做 Modern.js v2 版本,主要有以下几个原因:
以上因素促使我们完成了 Modern.js v2 版本。
在 v2 版本中,我们重新明确了 Modern.js 的定位:Modern.js 是字节跳动 Web 工程体系的开源版本,它提供多个解决方案,来帮助开发者解决不同研发场景下的问题。
目前我们开源了三个解决方案,分别面向 Web 应用开发场景、npm 包开发场景和文档站开发场景:
Modern.js 解决方案
作为 Modern.js 工程体系的一部分,以上每个解决方案都可以被单独使用,并且各自部署了独立的文档站点。开发者可以按需选择其中的一个或多个解决方案来使用。
在代码层面,这三个解决方案按照统一的研发规范迭代,并复用同一套插件机制,因此,它们提供的研发体验也较为一致。大家如果对内部实现感兴趣,可以在 GitHub 上的 Modern.js 仓库 中找到它们的源代码。
下面让我们来了解一下这三个解决方案提供的最新能力。
Modern.js 框架是一个基于 React 的渐进式 Web 开发框架。在字节跳动内部,我们将 Modern.js 封装为上层框架,并支撑了数千个 Web 应用的研发。
由于 Modern.js 框架的使用最为广泛,在下文中,我们会省略「框架」,直接称其为 Modern.js。
在 Modern.js 落地的过程中,我们收到很多业务同学提出的诉求,包括构建性能、框架的灵活性和可扩展性、页面加载性能等方面,相信社区中的开发者也会面临相似的问题。
为了更好地满足这些诉求,Modern.js v2 提供了以下特性:
Modern.js v2 提供开箱即用的双构建工具支持,开发者可以在成熟的 Webpack 和更快的 Rspack 之间进行切换。大家对 Rspack 可能还不太了解,Rspack 是由字节跳动开源的 Web 构建工具,基于 Rust 语言开发,具有高性能、可定制、兼容 Webpack 生态等特性。
相较于 webpack,Rspack 的构建性能有明显提升,除了 Rust 带来的语言优势,这也来自于它的并行架构和增量编译等特性。经过 benchmark 验证,Rspack 可以给 Modern.js 项目带来 5 ~ 10 倍编译性能的提升。
Modern.js 已支持在 Rspack 模式下使用框架的 70% 功能和配置项,包括服务器端渲染(SSR),静态站点生成(SSG)、嵌套路由、CSS Modules 和 Tailwind CSS 等功能。除了功能,Modern.js 在 Rspack 模式下的配置项也与 Webpack 模式基本一致,在我们的实际验证中,一个小型项目花几分钟就可以平滑切换到 Rspack 模式。
目前,Rspack 项目以及 Modern.js 的 Rspack 模式仍在快速迭代中。在未来几个月内,我们将逐步对齐 Webpack 模式和 Rspack 模式的绝大多数功能和配置,使更多项目能从 Webpack 平滑地过渡到 Rspack。
Rspack 已于 2023.03.10 号正式开源,你也可以在非 Modern.js 的项目中直接使用 Rspack 进行构建。如果你对 Rspack 感兴趣,请阅读 「Rspack 正式发布了」来了解更多。
大家对 Modern.js 框架的第一印象可能是「一个大而全的框架」,但事实上,为了避免变得臃肿,Modern.js 采取了渐进式设计,将所有功能建立在灵活的插件系统之上,因此具备按需启用和可插拔的能力。
Modern.js 期望能支持不同规模的项目研发,考虑到中大型项目和小型项目对功能的诉求存在差异,Modern.js 的大多数功能都是按需启用的。在创建项目时,Modern.js 默认只安装核心模块,使 npm 依赖保持轻量;当需要用到额外功能时,你可以通过 modern new 命令一键开启,并自动安装相关依赖。
比如:
@modern-js/app-tools
,即具备了开发调试、生产构建的能力。目前,你可以通过 modern new
命令来按需开启以下功能,未来我们也会将更多功能加入到 new
命令中,使其能够被便捷地集成。
开发者在实际项目中使用 Web 研发框架时,除了使用开箱即用的能力,也会有很强的定制化诉求。因此,Modern.js 设计了一套灵活的插件系统来满足这一点。
Modern.js 可以划分为三个核心部分:CLI 工具、服务端和运行时。其中,CLI 工具负责提供 CLI 命令和打包构建能力;服务端提供 SSR、BFF 等能力;运行时提供状态管理、路由等能力。
Modern.js 核心模块
我们为这三者分别设计了插件:
这三种插件使用统一的 Hook 模型,并提供丰富的插件 API。比如,你可以使用插件做到:
在字节跳动内部,我们借助这些插件 API,结合公司内的基建和平台,封装出内部的企业级框架。如果你需要对 Modern.js 框架进行深度定制,也可以借助这些插件 API 来完成。
如果你对 Modern.js 的插件系统感兴趣,请阅读 「Modern.js - 自定义插件」文档。
Modern.js v2 基于 React Router v6 提供了新的路由方式 —— 嵌套路由(Nested Routes)。
如果大家了解过 Remix 或 Next.js 13,应该对嵌套路由不陌生了。嵌套路由与 Modern.js v1 提供的约定式路由相似,也是一种基于文件系统的路由。
在 Modern.js v2 中,我们约定在 src/routes
目录下的文件,在应用启动时会自动生成对应的路由结构,页面的路由与文件结构是相呼应的,并且可以为资源加载带来一些性能优化。
Modern.js 的嵌套路由包含以下功能:
在 Modern.js v2 中,只需要配置 runtime.router
,即可开启嵌套路由:
如果你对嵌套路由的细节感兴趣,请阅读「Modern.js - 路由」文档。
Modern.js v2 基于 React v18 的全新 API 支持了流式渲染(Streaming SSR)。
如果大家关注去年 React v18 的版本更新,可能会注意到它提供了新的 Server Side APIs,并对 Suspense 做了完整支持。在 Modern.js v2 中,我们通过 React Router v6 暴露的能力,在框架层面支持了流式渲染。
流式渲染利用 HTTP 的能力,允许将页面的 HTML 分割成较小的块,并逐步将这些块从服务器发送到客户端。页面无需等待所有数据加载完成,即可呈现完整用户界面,因此与数据无关的局部内容能够更早地显示出来。
在 Modern.js v2 中,只需要配置 server.ssr.mode
,即可开启流式渲染:
如果你想在 Modern.js 中使用 SSR 和流式渲染,请阅读「 Modern.js 服务端渲染(SSR)」文档。
Modern.js Module 是我们针对 npm 包开发场景提供的解决方案,它为开发者提供了专业的 npm 包开发工具,能够更轻松地构建、调试和发布一个 npm 包。
Modern.js Module 首页
Modern.js Module 的核心能力包括:
在 v2 版本中,我们以 esbuild 为核心,扩展其插件机制,并结合 SWC 实现了一个通用的模块构建工具,它的特性包括:
在生成 TS 类型文件上,Modern.js Module v2 也支持新的方式:
总的来说,相较于 v1 版本,Modern.js Module v2 提供了更完整的构建能力,同时构建效率也有明显提升。
如果你对 Modern.js Module 感兴趣,请移步「Modern.js Module 文档」来了解更多。
Rspress 是一个面向文档站场景的框架,它的目标是给开发者提供一个简单、高效、可扩展的文档站解决方案。
Rspress 官网介绍页
目前,Rspress 包含如下能力:
我们做 Rspress 的初心,是为了解决我们团队内的文档站搭建需求。随着 Rspress 的功能逐渐完整,我们也将它开放给社区使用,使它能发挥更大的价值。
目前,Rspress 仍处于 beta 测试状态,相关源代码已经开放在 Rspress 仓库 中,并提供了基础的 使用文档。在未来,我们将继续投入,使之成为一个完成度更高的文档解决方案。
Modern.js 中的部分代码实现参考了社区中的开源项目,我们对这些项目表示衷心的感谢:
@modern-js/bundle-require
: 修改自 bundle-require。@modern-js/plugin
: hook API 的实现参考了 farrow-pipeline。@modern-js/builder
: moduleScope 和 fileSize 插件参考了 create-react-app,TsConfigPathsPlugin 参考了 tsconfig-paths-webpack-plugin,generateMetaTags 函数参考了 html-webpack-plugin。@modern-js/plugin-testing
: jest runner 参考了 jest-cli。@modern-js/plugin-data-loader
: 部分实现参考了 remix。现阶段 Modern.js 仍是一个很年轻的开源项目,在未来,我们将继续拥抱长期主义,持续打磨功能和文档,并以更透明的方式与社区共同协作。
如果你有兴趣尝试一下 Modern.js,欢迎试用并留下你的反馈意见~