news 2026/9/24 16:28:02

RedwoodJS 禁用 API 层与数据库:纯静态站点部署实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RedwoodJS 禁用 API 层与数据库:纯静态站点部署实战指南
  • 后端
  • 前端
  • Web框架
  • 开发工具

【免费下载链接】redwood

RedwoodGraphQL

项目地址:https://gitcode.com/gh_mirrors/re/redwood
点击查看免费下载

本文以 RedwoodJS 为背景,完整讲解如何在不使用 API 层与数据库的前提下,将一个 Redwood 项目改造成纯静态站点(或"本地 JSON 数据 + 静态页面"的混合站点)并部署到 Netlify。读完本文,你将掌握:删除api目录的正确姿势、通过yarn rw deploy netlify --prisma=false --dm=false关闭 Prisma 与数据迁移、在netlify.toml中关闭函数构建,以及利用web/public下的静态 JSON 文件配合浏览器原生fetch()与 Chart.js 渲染数据图表的完整实战方案。

适用场景与前提

RedwoodJS 虽然以"全栈"著称,但并非每个项目都需要 GraphQL API 或数据库。以下两类场景非常适合禁用 API/数据库:

  • 纯静态站点:站点不需要任何外部数据,例如个人主页、产品落地页、文档站;
  • 低频数据站点:只需要消化一个简单的 JSON 数据结构,且数据变化频率极低——低到修改数据只需编辑一个纯文本文件、然后重新部署站点即可。

本文以Netlify 作为部署目标编写(原文档即以此为前提)。若使用其他托管平台或自定义构建流程,命令与配置可能有所差异,需要结合对应平台的构建说明自行调整。相关平台完整部署流程可参考 Netlify 部署指南 与 部署总览。

第一步:删除 /api 目录

最简单粗暴的方式是:直接把整个/api目录删掉,Redwood 应用在开发模式下依然可以正常工作:

rm -rf api

删除后建议再运行一次yarn install,清理掉那些已经不再被引用的依赖包,让node_modules与锁文件保持整洁。

说明:Redwood 的目录约定是api(服务端)与web(前端)并存,可参考仓库中任意一个完整项目,例如 example-todo-main 项目 的目录结构。删除api后,web侧依旧可以独立开发与构建。

第二步:禁用 Prisma 与数据迁移功能

yarn rw deploy netlify命令中有两个关键参数:--prisma--dm--data-migrate的别名),两者默认值均为true,必须显式设置为false

netlify.toml的构建命令中关闭它们:

[build] command = "yarn rw deploy netlify --prisma=false --dm=false"

为什么必须关闭?在本地开发环境中,即使不带这两个参数也不会影响开发;但一旦部署到生产环境(至少以 Netlify 为部署目标时),如果仍保持默认值true,构建会报出'No Prisma Schema found'错误——因为我们已经删除了api目录,Prisma 无从找到 schema 文件。

源码验证:这两个参数究竟做了什么

从 Redwood CLI 的源码可以看到这两个参数的定义与默认值,位于 deploy 命令的共享 helpers:

.option('prisma', { description: 'Apply database migrations', type: 'boolean', default: 'true', }) .option('data-migrate', { description: 'Migrate the data in your database', type: 'boolean', default: 'true', alias: 'dm', })

而 deployHandler 会根据这些开关动态拼接最终执行的命令链:

let commandSet = [] if (build) { commandSet.push('yarn rw build --verbose') } if (prisma) { commandSet.push('yarn rw prisma migrate deploy') } if (dataMigrate) { commandSet.push('yarn rw>[build] command = "yarn rw deploy netlify --prisma=false --dm=false" publish = "web/dist" # functions = "api/dist/functions" [dev] command = "yarn rw dev" [[redirects]] from = "/*" to = "/index.html" status = 200

各配置项含义:

  • command:Netlify 构建时执行的命令,这里已关闭 Prisma 与数据迁移;
  • publish:指定静态站点的发布目录为web/dist(Redwoodweb侧构建产物);
  • # functions = "api/dist/functions"注释掉这一行,Netlify 便不会尝试把api/dist/functions下的代码部署为 Lambda 函数;
  • [dev]/command = "yarn rw dev":Netlify Dev 本地开发启动命令;
  • [[redirects]]:SPA 回退规则,将任意路径请求重定向到index.html(状态码 200),保证前端路由在刷新时可用。

对照默认模板理解差异

Redwood 官方提供的 netlify.toml 模板(yarn rw setup deploy netlify生成)默认包含functions = "api/dist/functions"这一行,见 setup deploy 的 Netlify 模板:

[build] command = "yarn rw deploy netlify" publish = "web/dist" functions = "api/dist/functions" [build.environment] NODE_VERSION = "20"

仓库中的完整示例项目(如 example-todo-main 的 netlify.toml)同样采用默认配置。而本文的静态站点方案正是在这个默认模板基础上:① 构建命令追加--prisma=false --dm=false;② 注释掉functions行。

如果只是纯静态站点、完全不需要访问任何数据,做到这一步就已经完成了。继续往下看,如何用"随 web 侧一起部署的本地 JSON 文件"充当数据源,构建一个混合型站点。

第四步:从本地 JSON 文件读取数据

下面演示一个完整场景:展示 2017 年 1 月 30 日当周俄罗斯莫斯科的天气预报折线图。这个场景听起来很"特别",是因为它用的正是 OpenWeather API 的官方示例数据(天气 API 示例数据)。

你可以从 OpenWeather 官方示例接口获取 JSON,也可以直接使用下文给出的完整数据,保存为web/public/forecast.json

{ "cod": "200", "message": 0, "city": { "geoname_id": 524901, "name": "Moscow", "lat": 55.7522, "lon": 37.6156, "country": "RU", "iso2": "RU", "type": "city", "population": 0 }, "cnt": 7, "list": [ { "dt": 1485766800, "temp": { "day": 262.65, "min": 261.41, "max": 262.65, "night": 261.41, "eve": 262.65, "morn": 262.65 }, "pressure": 1024.53, "humidity": 76, "weather": [ { "id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d" } ], "speed": 4.57, "deg": 225, "clouds": 0, "snow": 0.01 }, { "dt": 1485853200, "temp": { "day": 262.31, "min": 260.98, "max": 265.44, "night": 265.44, "eve": 264.18, "morn": 261.46 }, "pressure": 1018.1, "humidity": 91, "weather": [ { "id": 600, "main": "Snow", "description": "light snow", "icon": "13d" } ], "speed": 4.1, "deg": 249, "clouds": 88, "snow": 1.44 }, { "dt": 1485939600, "temp": { "day": 270.27, "min": 266.9, "max": 270.59, "night": 268.06, "eve": 269.66, "morn": 266.9 }, "pressure": 1010.85, "humidity": 92, "weather": [ { "id": 600, "main": "Snow", "description": "light snow", "icon": "13d" } ], "speed": 4.53, "deg": 298, "clouds": 64, "snow": 0.92 }, { "dt": 1486026000, "temp": { "day": 263.46, "min": 255.19, "max": 264.02, "night": 255.59, "eve": 259.68, "morn": 263.38 }, "pressure": 1019.32, "humidity": 84, "weather": [ { "id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d" } ], "speed": 3.06, "deg": 344, "clouds": 0 }, { "dt": 1486112400, "temp": { "day": 265.69, "min": 256.55, "max": 266, "night": 256.55, "eve": 260.09, "morn": 266 }, "pressure": 1012.2, "humidity": 0, "weather": [ { "id": 600, "main": "Snow", "description": "light snow", "icon": "13d" } ], "speed": 7.35, "deg": 24, "clouds": 45, "snow": 0.21 }, { "dt": 1486198800, "temp": { "day": 259.95, "min": 254.73, "max": 259.95, "night": 257.13, "eve": 254.73, "morn": 257.02 }, "pressure": 1029.5, "humidity": 0, "weather": [ { "id": 800, "main": "Clear", "description": "sky is clear", "icon": "01d" } ], "speed": 2.6, "deg": 331, "clouds": 29 }, { "dt": 1486285200, "temp": { "day": 263.13, "min": 259.11, "max": 263.13, "night": 262.01, "eve": 261.32, "morn": 259.11 }, "pressure": 1023.21, "humidity": 0, "weather": [ { "id": 600, "main": "Snow", "description": "light snow", "icon": "13d" } ], "speed": 5.33, "deg": 234, "clouds": 46, "snow": 0.04 } ] }

关键机制web/public目录下的任何文件都会被 Netlify 原样托管,跳过一切构建过程。也就是说,你把forecast.json放进web/public,它就等同于站点根路径下的一个静态资源/forecast.json。这正是"编辑一个纯文本文件 → 重新部署"这种极简数据更新流程的基础。

第五步:用 React 组件拉取并展示数据

接下来让 React 组件远程获取这份 JSON 并展示在页面上。先生成一个首页:

yarn rw generate page home /

然后使用浏览器内置的fetch()获取数据,先把原始 JSON 直接 dump 到屏幕上验证链路是否打通:

import { useState, useEffect } from 'react' const HomePage = () => { const [forecast, setForecast] = useState({}) useEffect(() => { fetch('/forecast.json') .then((response) => response.json()) .then((json) => setForecast(json)) }, []) return <div>{JSON.stringify(forecast)}</div> } export default HomePage

这里用useState保存天气数据,用useEffect在组件挂载时触发数据加载。由于fetch请求的是同源静态资源/forecast.json,不存在跨域问题,在本地开发与 Netlify 生产环境都能直接工作。

第六步:用 Chart.js 绘制天气曲线

数据链路打通后,引入 Chart.js 做简单图表。Chart.js 是 Redwood 项目中常用的第三方图表库之一,通过yarn workspace web将其安装到web侧:

yarn workspace web add chart.js

先用假数据验证图表渲染

import { useState, useEffect, useRef } from 'react' import Chart from 'chart.js' const HomePage = () => { const chartRef = useRef() const [forecast, setForecast] = useState({}) useEffect(() => { fetch('/forecast.json') .then((response) => response.json()) .then((json) => setForecast(json)) }, []) useEffect(() => { new Chart(chartRef.current.getContext('2d'), { type: 'line', data: { labels: ['Jan', 'Feb', 'March'], datasets: [ { label: 'High', data: [86, 67, 91], }, { label: 'Low', data: [45, 43, 55], }, ], }, }) }, [forecast]) return <canvas ref={chartRef} /> } export default HomePage

要点说明:

  • useRef创建chartRef并绑定到<canvas>元素,Chart.js 通过chartRef.current.getContext('2d')获取 2D 绘图上下文;
  • 图表创建逻辑放在第二个useEffect中,依赖数组为[forecast],即等天气数据加载完成后才绘制图表;
  • 这一段先用写死的假数据([86, 67, 91]等)验证 Chart.js 渲染链路是否正常。

把真实 JSON 数据转换成 Chart.js 需要的格式

假数据渲染正常后,剩下的工作就是把天气 JSON 转换成 Chart.js 期望的结构。最终版HomePage增加了两个数据转换函数,并正确处理日期显示:

import { useState, useEffect, useRef } from 'react' import Chart from 'chart.js' const MONTHS = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ] const getDates = (forecast) => { return forecast.list.map((entry) => { const date = new Date(0) date.setUTCSeconds(entry.dt) return `${MONTHS[date.getMonth()]} ${date.getDate()}` }) } const getTemps = (forecast) => { return [ { label: 'High', data: forecast.list.map((entry) => kelvinToFahrenheit(entry.temp.max)), borderColor: 'red', backgroundColor: 'transparent', }, { label: 'Low', data: forecast.list.map((entry) => kelvinToFahrenheit(entry.temp.min)), borderColor: 'blue', backgroundColor: 'transparent', }, ] } const kelvinToFahrenheit = (temp) => { return ((temp - 273.15) * 9) / 5 + 32 } const HomePage = () => { const chartRef = useRef() const [forecast, setForecast] = useState(null) useEffect(() => { fetch('/forecast.json') .then((response) => response.json()) .then((json) => setForecast(json)) }, []) useEffect(() => { if (forecast) { new Chart(chartRef.current.getContext('2d'), { type: 'line', data: { labels: getDates(forecast), datasets: getTemps(forecast), }, }) } }, [forecast]) return <canvas ref={chartRef} /> } export default HomePage

各函数的职责:

  • MONTHS:月份英文缩写常量表,用于把 Unix 时间戳格式化为"Jan 30"这样的可读标签;
  • getDates(forecast):遍历forecast.list,把每条记录的dt(Unix 秒级时间戳)通过new Date(0)+setUTCSeconds(entry.dt)转换为日期对象,再格式化为"月份 日期",作为折线图的 X 轴标签;
  • getTemps(forecast):分别提取entry.temp.maxentry.temp.min,经kelvinToFahrenheit把开尔文温度换算为华氏度,生成"High"(红线)与"Low"(蓝线)两条数据集;
  • kelvinToFahrenheit:温度单位换算工具函数。

注意forecast的初始值从{}改成了null,并在绘制前增加if (forecast)判断——这样既避免在数据尚未到达时对undefined调用forecast.list.map,也防止重复创建 Chart 实例。渲染成功后,页面会出现一条红色高温曲线与一条蓝色低温曲线。

收尾:部署到生产

至此,一个"无 API、无数据库"的混合型站点就完成了:数据存于web/public/forecast.json,前端通过静态资源请求读取并在浏览器端用 Chart.js 绘制。剩余工作就是提交代码并交给 Netlify 构建部署——注意构建命令必须保持--prisma=false --dm=false,且functions行保持注释状态。

总结

RedwoodJS 的核心价值在于让"需要访问数据库或第三方 API"的全栈应用开发更轻松,但它同样可以用于纯静态站点,以及本文演示的这种混合站点——当你想消化并展示数据,但数据源只是自己 URL 下的一个静态文件时。核心要点回顾:

  1. 删除api目录后开发模式依旧可用;
  2. yarn rw deploy netlify --prisma=false --dm=false关闭数据库迁移与数据迁移(二者默认均为true,源码见 deploy helpers);
  3. 注释掉netlify.toml中的functions,阻止 Netlify 扫描 Lambda 函数代码;
  4. web/public下的文件被原样托管,可充当极简数据源;配合浏览器fetch()与 Chart.js 即可渲染数据图表。

这种方案的额外收益是:数据更新成本极低(改一个 JSON 文件重新部署),无需维护数据库、无需关心迁移,部署链路更简单,也省去了 Lambda 函数的冷启动与配额顾虑。

  • 后端
  • 前端
  • Web框架
  • 开发工具

【免费下载链接】redwood

RedwoodGraphQL

项目地址:https://gitcode.com/gh_mirrors/re/redwood
点击查看免费下载

相关推荐

上一篇:如何快速获取百度网盘真实下载链接:面向普通用户的完整指南
下一篇:两步跑通抖音去水印下载:单条视频、整个主页,都能存

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 16:20:55

【Dv2Admin】mounted实现定时请求和消息通知

在现代应用开发中,消息通知功能在提升用户体验中发挥着至关重要的作用,特别是当用户有未读消息时,如何及时提醒用户成为一个挑战。本文将通过实际的代码示例和应用场景,介绍如何在Vue.js项目中集成一个智能的消息通知系统,使用户能够周期性地收到未读消息提醒,并通过点击…

作者头像 李华