Modern.js CSR 应用多平台部署实战:Node.js / Vercel / Netlify 从构建到上线

发布时间:2026/10/13 5:55:00

Modern.js CSR 应用多平台部署实战:Node.js / Vercel / Netlify 从构建到上线 前端后端Web框架【免费下载链接】modern.jsA progressive web framework based on React and Rsbuild.项目地址https://gitcode.com/gh_mirrors/mo/modern.js点击查看免费下载导读本文以仓库中的 modern-js-deploy-csr 示例工程 为主体系统讲解基于 Modern.js 的纯前端 CSRClient-Side Rendering应用如何通过统一的modern deploy命令一键产出可在Node.js 服务器、Vercel、Netlify三种环境直接运行的部署产物。读完本文你将掌握 CSR 示例工程的项目结构、本地开发与生产构建流程、三种部署方式的配置差异以及modern deploy背后各平台 preset 的底层实现原理能够根据自己的托管场景快速选型并完成上线。示例工程概览与功能特性modern-js-deploy-csr是一个使用 Modern.js 框架构建的 CSR 应用示例它的核心设计目标是演示同一份前端代码如何适配多种部署方式。从工程结构上看package.json 中声明的技术栈清晰地说明了它的构成基于Modern.js框架modern-js/app-tools提供构建与 CLI 能力modern-js/runtime提供运行时能力使用React 19作为 UI 框架react/react-dom版本为^19.2.8使用TypeScript保证类型安全typescript ~5.7.3并依赖modern-js/tsconfig构建工具为Rspack由modern-js/app-tools内置集成。工程同时支持三种部署途径部署方式目标产物适用场景Node.js 服务器部署.output目录自有服务器、容器化部署灵活性最高Vercel 平台部署.vercel/output目录托管平台一键部署无需自建服务器Netlify 平台部署dist_redirects托管平台一键部署支持静态站点与 Functions需要说明的是本示例是纯 CSR 应用不含 SSR、BFF 或自定义 Web Server因此三种方式都以静态资源 路由回退为核心全栈场景SSR/BFF对应的示例可参考 modern-js-deploy-ssr本文会在原理章节一并说明两者的差异。环境准备与本地开发流程前置条件按示例工程 README 与 package.json 的engines声明运行本工程需要Node.js 20.19.5pnpm包管理器仓库本身即 pnpm workspace参见根目录 pnpm-workspace.yaml。安装依赖pnpm install本地开发启动开发服务器pnpm devdev脚本在 package.json 中对应modern dev。开发模式下 Rspack 会提供热更新可直接在浏览器中预览src/routes下基于文件约定生成的页面。生产构建pnpm build对应modern build产出构建结果到dist目录。本地预览生产构建pnpm serve对应modern serve用于在本地以生产模式起服务验证构建产物。除此之外示例工程的package.json还预置了两个与部署直接相关的脚本它们是理解多平台部署的钥匙deploy: modern deploy, deploy:gh-pages: MODERNJS_DEPLOYghPages modern deploy gh-pages -d .outputdeploy脚本执行modern deploy由 Modern.js 自动检测部署平台并生成对应产物deploy:gh-pages通过环境变量MODERNJS_DEPLOYghPages强制指定 GitHub Pages 平台生成.output产物后用gh-pages工具推送到 Pages 分支需要安装gh-pages开发依赖该依赖已声明在 devDependencies 中。工程配置解析一份代码如何适配多平台示例工程根目录下并列存在modern.config.ts、vercel.json、netlify.toml三个配置文件分别服务于构建本身与平台适配。modern.config.ts基础路径配置modern.config.ts 内容如下import { appTools, defineConfig } from modern-js/app-tools; // https://modernjs.dev/en/configure/app/usage export default defineConfig({ plugins: [appTools()], server: { baseUrl: /modern-js-deploy-csr, // It should be replaced with your repository name }, output: { minify: false, assetPrefix: /modern-js-deploy-csr/, // It should be replaced with your repository name }, });其中两个关键配置项需要重点说明server.baseUrl应用访问的基础路径。示例中设置为仓库名modern-js-deploy-csr部署到 GitHub Pages 这类子路径托管场景时页面必须通过username.github.io/repository-name访问因此路由与资源路径都要带上该前缀。若你的仓库名不同必须替换为实际仓库名否则部署后资源 404。output.assetPrefix静态资源 URL 前缀同样指向/modern-js-deploy-csr/。它控制构建产物中 JS/CSS 等资源引用的绝对路径前缀与server.baseUrl保持一致才能保证页面、路由、资源三者路径统一。minify: false仅用于便于调试示例产物生产项目可移除。平台适配文件vercel.json 与 netlify.tomlVercel 通过根目录 vercel.json 声明构建行为{ buildCommand: modern deploy, outputDirectory: .vercel/output }Netlify 通过根目录 netlify.toml 声明构建行为[build] publish dist command modern deploy两者的共同点是构建命令都是modern deploy即平台接管构建后调用 Modern.js 的部署命令让它按对应平台规范产出产物差异在于产物的读取位置——Vercel 读取.vercel/outputNetlify 发布dist目录。这正是 Modern.js 多平台部署的核心设计统一命令入口各平台 preset 负责产出各自规范的目录结构。modern deploy统一部署命令的底层原理modern deploy之所以能适配多平台是因为modern-js/app-tools内置了名为modern-js/plugin-deploy的插件其实现位于 packages/solutions/app-tools/src/plugins/deploy/index.ts。从源码结构可以还原出它的完整决策链路const deployTarget process.env.MODERNJS_DEPLOY || provider || node;即部署目标的确定优先级为环境变量MODERNJS_DEPLOY 平台运行时自动探测provider来自std-env 默认node。也就是说在 Vercel / Netlify 等官方支持平台上构建时插件能自动识别运行环境无需手动指定在本地或自有服务器上执行时默认走 Node.js preset需要强制指定平台如 GitHub Pages时通过MODERNJS_DEPLOYghPages modern deploy手动覆盖。插件内部维护了一个部署目标到 preset 工厂函数的映射表见 index.tstype DeployPresetCreators { node: typeof createNodePreset; vercel: typeof createVercelPreset; netlify: typeof createNetlifyPreset; ghPages: typeof createGhPagesPreset; };每个 preset 都是一个生命周期对象按固定顺序执行四个阶段见 index.tsdeployPreset?.prepare (await deployPreset?.prepare()); deployPreset?.writeOutput (await deployPreset?.writeOutput()); deployPreset?.genEntry (await deployPreset?.genEntry()); deployPreset?.end (await deployPreset?.end());prepare清理上一次的产物目录writeOutput把构建结果dist拷贝/重组成平台规范的目录genEntry根据项目模块类型ESM 用.mjs、CJS 用.cjs模板生成服务器入口文件end收尾包括用ndepe将modern-js/prod-server等隐式依赖连同产物一起打包进.output/node_modules保证产物可在目标环境独立运行。在选定 preset 之前插件还会通过 getProjectUsage 读取构建产物中的路由描述文件route.json判断项目是否使用了 SSR、API 或自定义 Web Server从而决定needModernServer的值const needModernServer useSSR || useAPI || useWebServer;这正是 CSR 与 SSR 部署产物结构差异的根源纯 CSR 应用needModernServer false走静态托管 路由重写路线全栈应用needModernServer true则走Serverless Function 完整 prod-server路线。本示例的 CSR 工程属于前者下面逐一展开三种部署方式的产物细节。方式一Node.js 服务器部署生成产物在未检测到 Modern.js 官方支持平台的环境中如本地或自有服务器直接执行npx modern deployNode.js preset实现见 platforms/node.ts会清理并重建.output目录将dist完整拷贝到.output基于 node-entry.cjsESM 项目则用node-entry.mjs生成入口文件.output/index.js调用ndepe把modern-js/prod-server等运行时依赖收敛到.output/node_modules同时过滤掉static目录与.map文件避免重复打包静态资源见 node.ts。命令完成后终端会输出两条关键提示与官方部署指南 deploy.mdx 中描述一致Static directory: .output/static You can preview this build by node .output/index启动服务node .output/index入口模板会读取route.json中的路由描述、加载插件与modern-js/prod-server最终调用createProdServer启动 HTTP 服务见 node-entry.cjs。默认监听8080端口如需改端口通过环境变量指定PORT3000 node .output/index页面所需的静态资源位于.output/static也可以自行将静态资源上传到 CDN服务器只负责 HTML 与路由。Monorepo 场景若项目位于 pnpm Monorepo 中构建当前项目前还需先构建它依赖的 workspace 子项目。官方指南建议在 package.json 中追加如下脚本假设当前项目名为app{ scripts: { build:packages: pnpm --filter app^... run build, deploy: pnpm run build:packages modern deploy } }Rush 用户则对应{ scripts: { build:packages: rush rebuild --to-except app, deploy: rushx build:packages modern deploy } }构建完成后Modern.js 会将全部依赖生成到.output/node_modules同样用node .output/index启动。方式二Vercel 平台部署纯前端项目配置Vercel preset实现见 platforms/vercel.ts将产物输出到.vercel/output并在其中生成符合 Vercel Build Output API v3 规范的config.json。对本示例这类纯 CSR 项目生成的 config 结构如下源码见 vercel.ts{ version: 3, routes: [ { src: /static/(.*), headers: { cache-control: s-maxage31536000, immutable }, continue: true }, { handle: filesystem }, { src: /(?:/.*)?, headers: { cache-control: s-maxage0 }, dest: /html/main/index.html } ] }值得注意的实现细节静态资源命中/static/(.*)时返回s-maxage31536000, immutable的长缓存头并在continue: true后继续匹配后续规则纯 CSR 场景下主入口及其余入口的 HTML 会被拷贝到.vercel/output/static/html下路由规则把根路径及入口路径统一重写到对应 HTMLdest根据html.outputStructure是flat还是目录结构决定是/html/main.html还是/html/main/index.html从而保证前端路由刷新不 404由于needModernServer false本示例不会生成functions/index.func函数目录见 vercel.ts。配合根目录 vercel.json{ buildCommand: modern deploy, outputDirectory: .vercel/output }在 Vercel 平台导入仓库时Framework Preset 选择Other提交代码即可触发部署。全栈项目的差异如果项目使用 SSR、自定义 Web Server 或 BFFneedModernServer为trueVercel preset 会额外在.vercel/output/functions/index.func下生成函数目录写入.vc-config.json声明运行时runtime: nodejs${Node大版本}.x、handler: index.js、supportsResponseStreaming: true见 vercel.ts基于 vercel-entry.cjs 生成函数入口入口内部用createProdServer(...).getRequestListener()拿到请求监听器再包装成(req, res) {}形式的 Serverless Handler见 vercel-entry.cjs。注意事项以官方文档 deploy.mdx 为准当前版本 Modern.js 暂不支持在 Vercel 上部署 BFF 项目函数执行的 Node.js 版本由 Vercel 平台项目配置决定。Monorepo 场景在 Vercel 平台将Root Directory配置为packages/app在package.json中声明 Node 运行时engines: { node: 20.x }并追加与 Node.js 部署章节相同的build:packages/deploy脚本同时将 vercel.json 中的构建命令改为npm run deploy{ buildCommand: npm run deploy, outputDirectory: .vercel/output }方式三Netlify 平台部署纯前端项目配置Netlify preset实现见 platforms/netlify.ts与 Vercel 思路类似但产物形态不同构建产物留在dist路由重写规则写入dist/_redirects文件。对本示例这类纯 CSR 项目_redirects内容形如/ /html/main/index.html 200 /user /html/user/index.html 200每条规则对应源路径 目标路径 状态码生成逻辑见 netlify.ts核心作用是让任意前端路由路径都回退到对应 HTML 文件并返回200从而支持客户端路由的刷新与直接访问。由于needModernServer false本示例不会创建.netlify/functions目录。配合根目录 netlify.toml[build] publish dist command modern deploy在 Netlify 平台导入仓库即可触发部署Base directory 视 Monorepo 情况按需设置为packages/app。全栈项目的差异对于使用 Custom Web Server、SSR 或 BFF 的全栈项目需要部署到Netlify Functions基于上述配置追加[build] publish dist command modern deploy [functions] directory .netlify/functions node_bundler none included_files [.netlify/functions/**]此时 preset 会把产物拷贝到.netlify/functions基于 netlify-entry.cjs 生成函数入口并把_redirects的兜底规则改为/* /.netlify/functions/index 200由函数接管全部请求见 netlify.ts。同时注意node_bundler none是关键配置——函数内的依赖已由 Modern.js 的ndepe步骤打包完成不需要 Netlify 再次打包。官方文档明确当前版本 Modern.js 暂不支持 Netlify Edge Functions。补充GitHub Pages 部署示例工程的第四种能力虽然示例 README 只罗列了三种部署方式但工程 package.json 中预置的deploy:gh-pages脚本展示了第四种能力GitHub Pages 部署对应 preset 实现见 platforms/gh-pages.ts。其完整流程为在 modern.config.ts 中配置server.baseUrl与output.assetPrefix为/仓库名示例工程已配置为/modern-js-deploy-csr安装gh-pages开发依赖执行npm run deploy:gh-pages该脚本等价于MODERNJS_DEPLOYghPages modern deploy gh-pages -d .output。gh-pages preset 会执行prepare → writeOutput → end三个阶段清理并重建.output然后通过reorganizeHtmlFiles依据路由描述文件serverRoutes把各个入口的 HTML 按urlPath重排为路径/index.html形式实现见 gh-pages.ts最后由gh-pages -d .output将产物发布到 Pages 分支。此外在 GitHub 仓库的 Settings Pages Source 中选择GitHub Actions模式也可以编写 workflow 在 CI 中执行同样的命令完成部署。使用自有 Node.js 服务器托管替代方案如果不想依赖modern deploy生成的.output/index.js纯 CSR 项目也可以把构建产物接入自己的 Node.js 服务。官方指南 deploy.mdx 给出了一个基于 Koa 的最小示例将.output含html与static目录拷贝到服务器仓库安装mime-types依赖然后实现/static路径返回静态资源流、/返回入口 HTML的逻辑const Koa require(koa); const fs require(fs); const path require(path); const mime require(mime-types); const app new Koa(); app.use(async (ctx, next) { if (ctx.path.startsWith(/static)) { ctx.type mime.lookup(ctx.path); ctx.body fs.createReadStream( path.resolve(__dirname, .output${ctx.path}), ); } else if (ctx.path /) { ctx.type html; ctx.body fs.createReadStream( path.resolve(__dirname, .output/html/main/index.html), ); } }); app.listen(3000);需要注意的是如果项目使用了 Modern.js 约定式路由或 React Router 客户端路由必须通过正确的baseURL访问 HTML 文件默认server.baseUrl为/可在 modern.config.ts 中修改对于带客户端路由的项目永远不要通过/index.html路径访问 HTML。同时多入口项目需要为不同路径返回对应 HTML以上代码仅是基础示例。小结CSR 部署选型建议部署方式核心产物是否需要服务器推荐场景Node.js 内置服务器.outputnode .output/index需要自有服务器、Docker 容器灵活可控Vercel.vercel/outputBuild Output API v3不需要快速托管自动 HTTPS 与 CDNNetlifydist_redirects不需要快速托管静态站点能力丰富GitHub Pages.outputgh-pages推送不需要开源仓库文档/演示站点无论选择哪种方式构建入口都是统一的modern deploy平台差异完全由modern-js/plugin-deploy的 preset 生命周期封装。纯 CSR 项目如本示例在各平台均以静态资源 路由回退方式部署无需生成 Serverless Function一旦引入 SSR / BFF / 自定义 Web ServerneedModernServer会变为true同一套命令会自动切换到函数形态产物这也是 modern-js-deploy-ssr 示例所演示的能力。更完整的官方部署说明可继续阅读 部署应用指南 及其中文版 部署应用。赞分享前端后端Web框架【免费下载链接】modern.jsA progressive web framework based on React and Rsbuild.项目地址https://gitcode.com/gh_mirrors/mo/modern.js点击查看免费下载相关推荐如何彻底告别CJK字体兼容性问题思源宋体的3种实战部署方案如何彻底告别CJK字体兼容性问题思源宋体的3种实战部署方案 当你的应用需要同时处理中文、日文、韩文内容时是否遇到过这样的尴尬场景中文显示完美日文却出现字设计系统web-check多平台部署Vercel/Netlify/Fly配置web check多平台部署Vercel/Netlify/Fly配置 ?️‍♂️ 还在为网站安全分析工具部署发愁web check作为一款功能强大的OSIN后端前端网络安全Wasp 应用云部署实战指南从 wasp build 到多平台上线Wasp 应用云部署实战指南从 wasp build 到多平台上线 本指南系统讲解 Wasp 全栈应用的生产部署流程只要你的托管平台能运行 Node.js后端前端Web框架编译器开发工具代码生成上一篇【亲测免费】 探索VisP强大的视觉对象跟踪库下一篇Docker API 版本兼容机制实战解析octant 仓库中 vendored versions 包的 legacy 类型组织与版本比较创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/13 5:55:00

用鸿蒙开发鸿蒙:DevEco工具链落地PC公测版的实践与避坑指南

1. 为什么说“用鸿蒙开发鸿蒙”是个分水岭去年我还在为“鸿蒙应用只能在Windows/Mac上开发”而头疼,现在这层窗户纸被捅破了。DevEco Studio、DevEco Code、DevEco CLI 随鸿蒙PC公测版一起放出,等于把完整的开发工具链搬到了鸿蒙系统自己家里。简单说&am…

2026/10/13 5:55:00

鸿蒙PC公测版发布:三件套工具链实现“用鸿蒙开发鸿蒙”

“用鸿蒙开发鸿蒙”这句话,初看像一句绕口令,细品其实是这轮更新最核心的信号。鸿蒙PC公测版正式到来,而DevEco Studio、DevEco Code、DevEco CLI这整套开发工具链,也同步在鸿蒙PC上跑了起来。以前我们聊鸿蒙开发,都是…

2026/10/13 5:55:00

QKeyMapper:基于Qt的低级键盘钩子改键工具原理与编译实践

简介:QKeyMapper是一款基于Qt Widget与WinAPI开发的按键映射工具,适配Win10和Win11,全程无需修改注册表、不用重启系统即可生效,适合游戏键位调整、特殊按键替换、办公快捷键重排以及虚拟手柄摇杆模拟等应用。资源包为24.26MB的zi…

2026/10/13 7:10:04

黑黄配色商务PPT模板设计实操:母版、版式与兼容性维护

简介:这款黑黄配色商务报告PPT模板专为职场商务汇报场景设计,适合需要快速制作工作概况、阶段成就、经验教训或阶段计划等内容的用户选用。模板以黑色为底、黄色高亮,兼顾稳重感与信息突出度,内置目录页、数据图表、图片展示页等常…

2026/10/13 7:10:04

Spring Boot自动配置机制:Spring.factories文件解析与实践

1. Spring.factories 文件解析与应用场景Spring.factories 是 Spring Boot 自动配置机制中的关键配置文件,它采用 Java 的 SPI(Service Provider Interface)机制实现模块化扩展。这个文件通常位于 META-INF 目录下,格式为键值对形…

2026/10/13 7:10:04

Crunch.py:纯Python密码字典生成器的原理与应用

简介:Crunch 密码列表生成器的 Python 实现,主要面向安全测试、渗透测试及密码恢复等需要快速生成自定义字典的场景。脚本支持通过 min/max 参数设定密码长度范围,并通过字符集或掩码方式控制生成规则,还提供后缀添加、输出重定向…

2026/10/13 7:10:04

1. 存储性能基础:IO模型与存储栈解析

存储性能的根基——IO模型和存储栈。说实话,我见过太多性能问题,根子都出在对这条IO路径的理解上。你想想看,一个请求从应用发出去,到最终落盘,中间要经过多少层?每一层都可能成为瓶颈。 1.1 IO模型:同步、异步与阻塞 先说说IO模型。我个人习惯把IO模型分成三类:阻塞…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介:这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师,聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案,解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件,约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型,最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支,让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图,十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑