开始使用Astro和Redis
Astro是一种针对构建快速内容网站的新工具。尽管它是新的,但该团队已经发布了1.0版,并且API现在稳定。关键的卖点为零JavaScript 默认情况下以及带上自己的框架。我们将在这里使用Svelte来帮助我们开始使用Astro和Redis。那是使用无服务器数据库构建基本笔记应用程序。尽管我们使用Svelte,但您应该能够在没有事先苗条的知识的情况下跟随。也就是说,如果您喜欢的话,您可以稍后将组件换成React, Vue or other supported frameworks。
我们将大力依靠浏览器API,实际上仅在单个组件中运送JavaScript。我们将在CloudFlare上托管该应用程序,并使用工人,但稍后会介入。
要开始使用Astro和Redis,请在本地克隆启动器代码模板:
pnpm create astro -- --template rodneylab/upstash-astro
提示时,接受依赖项的安装并初始化GIT存储库。选择推荐的打字稿选项。将目录更改为您的新项目文件夹。默认情况下没有框架支持,我们添加了一个集成以便能够使用Svelte:
pnpm astro add svelte
Svelte设置是自动的,如果您从提示符中选择默认选项。接下来,要旋转开发服务器,请运行pnpm dev
命令。 CLI会给您URL(类似于http://localhost:3000)。打开浏览器中的URL。
Astro路线
让我们看一下src/pages/index.astro
。这是http://localhost:3000/
主页的Astro标记。 Astro使用基于文件的路由。这意味着我们在src/pages
目录中创建的Astro文件将输出输出到具有匹配路径的HTML页面。我们还将在src/pages/api.ts
中的 typescript 中编写 API端点。 API文件还遵循基于文件的路由模式,因此我们将在http://localhost:3000/api
上访问该端点。
您可能会注意到我们在浏览器中有一个Favicon,但是index.astro
标记中没有link
标签。那是因为我们在src/layouts/Layout.astro
上使用了布局文件。在index.astro
中,我们将页面主内容包装在Layout
组件中。这种模式为我们节省了在较大项目中重复布局代码的重复。
在src/components
文件夹中,我们有我们的Svelte组件。我们将能够像使用布局组件一样将它们导入index.astro
。
开始使用Astro和Redis:Astro文件
Astro文件有两个部分。第一个,脚本,部分是我们可以添加任何JavaScript或Typescript逻辑的地方。我们将此部分包裹在---
系数中。第二部分是模板,看起来很像HTML。您已经知道JSX很熟悉。
一些现代的Astro功能是:
- 开箱即用打字稿支持,
- partial hydration和
-
顶级等待(在
.astro
文件中)。
初始笔记
让我们在index.astro
的脚本部分中定义一些注释,然后将它们传递到模板部分中的Svelte组件。
更新src/pages/index.astro
中的代码(您可以在本教程中将style
标签留在底部):
---
import HeadingBar from '~components/HeadingBar.svelte';
import NoteBody from '~components/NoteBody.svelte';
import NotesList from '~components/NotesList.svelte';
import Layout from '~layouts/Layout.astro';
import type { Note } from '~types/note';
const editMode = false;
const notes: Note[] = [
{
id: '1',
title: 'Very first note',
text: 'First note’s text',
modified: new Date().toISOString(),
},
{
id: '2',
title: 'Another note',
text: 'This note’s text',
modified: new Date().toISOString(),
},
];
const selectedNote = notes[0];
const title = 'Upstash Astro Notes';
---
<Layout title={title}>
<main class="wrapper">
<h1>{title}</h1>
<div class="container">
<header class="heading">
{selectedNote ? <HeadingBar note={selectedNote} {editMode} /> : null}
</header>
<aside class="list">
<NotesList client:load {notes} selectedId={selectedNote?.id} {editMode} />
</aside>
<section class="note">
<NoteBody note={selectedNote} />
</section>
</div>
</main>
</Layout>
您应该看到显示的第一个注释。暂时不可能做其他事情,我们将在片刻之内设置数据库。目前,这是您完成的第一位Astro代码!我们在该行中看到了一些JSX的影响:
{selectedNote ? <HeadingBar note={selectedNote} {editMode} /> : null}
在这里,我们使用JavaScript三元运算符检查是否有selectedNote
,如果没有一个,则什么也不会渲染。请注意,我们如何使用HeadingBar
组件,传递道具。这包括现代快捷方式,让我们使用速记{editMode}
,我们本可以写出editMode={editMode}
。
我们前面提到的是,Astro默认情况下将零JavaScript运送。实际上,我们刚刚添加的HeadingBar
组件遵循此默认值。当我们确实希望JavaScript在组件中运行时,我们可以通过在其属性中包含client:load
指令(例如在NotesList
组件上)来启用它。可见一次检查Astro docs for other directives像水合物一样。接下来,我们将启动REDIS数据库,以便我们可以摆脱静态的手动评论。
开始使用Astro和Redis:无服务器Redis
我们将使用UpStash来提供我们的REDIS数据库。 Create an Upstash account如果您还没有一个,否则只需登录即可。从控制台创建一个新数据库。我们需要从控制台上的Astro项目进行两个环境变量。向下滚动到数据库详细信息页面的 REST API 部分。我们需要:
- upstash_redis_rest_url
- upstash_redis_rest_token
将项目根目录中的.env.EXAMPLE
文件重命名为.env
,并在此处添加这些凭据。 .env
包含在.gitignore
中,以避免意外提交这些价值。
现在我们已经设置了该设置,我们可以创建我们的API路由,将应用程序链接到无服务器Redis数据库。
API路线
我们将最大程度地减少Javasript的使用,并严重倾斜HTML。为此,在主要部分中,我们将使用HTML form element action
和method
属性来启动 create , update 和 delete 流程。 阅读可用的注释列表,我们使用HTTP GET请求。这些过程都始于index.astro
或Svelte组件文件代码。
src/pages/api.ts
文件将最终从Cloudflare Worker处理所有文件。从那里,我们与Upstash无服务器数据库联系,以完成CRUD(创建,读取,更新和删除)操作。让我们仔细看看文件。因此,此文件处理发送给http://localhost:3000/api
的HTTP请求。我们正在使用@upstash/redis
软件包与我们的远程数据库接口。我们导入此,然后在顶部配置redis实例:
import { Redis } from "@upstash/redis";
/* TRUNCATED */
const HASHSET_KEY = "notes";
const url = import.meta.env.UPSTASH_REDIS_REST_URL;
const token = import.meta.env.UPSTASH_REDIS_REST_TOKEN;
const redis = new Redis({ url, token });
要访问Astro中的秘密环境变量,我们使用import.meta.env
。
HTTP请求
正如您期望的那样,get
和put
方法中的代码(进一步)会响应端点收到的HTTP GET并提出请求。这些功能可以访问输入HTTP请求,然后返回响应。
我们设置了音符创建过程,以便新的音符具有自动设置为Untitled
和一个空白的标题。然后,用户可以从浏览器更新。我们将使用查询参数将浏览器重定向到Note编辑表单。那曾经是我们创建了骨架笔记。这是src/components/NotesList.svelte
的代码,启动注释 create 工作流程,浏览器:
<form action="/api" method="post">
<input type="hidden" name="action" value="create" />
<button>[ new ]</button>
</form>
该表单包含上面端点代码中使用的隐藏的action
字段。在这里,动作是create
,我们将在以后使用update
和delete
(以其他形式)。从本质上讲,我们的put
功能可以使用标准API进行操作并请求URL。如果动作是create
,我们在标签数据结构中提出了新注释。这是一个Redis structure which fits our use case。我们将当前的时间戳(作为number of milliseconds since ECMAScript epoch)用作元素id
。这对于我们的简单应用程序正常。 redis.hset
呼叫负责将新注释送入数据库:
const date = new Date();
const id = date.getTime();
/* TRUNCATED */
await redis.hset(HASHSET_KEY, {
[id]: JSON.stringify(note),
});
urlParams.append("edit", "true");
urlParams.append("note", id.toString(10));
/* TRUNCATED */
return Response.redirect(`${redirectURL}?${urlParams.toString()}`);
最后,请注意如何在重定向URL的末端添加edit
和note
查询参数。我们将更新前端代码以使用这些。
完成API
目前,我们只能创建一个骨架注释,甚至无法编辑它,因此这是API的完整代码。更新具有完整功能的src/pages/api.ts
:
import { Redis } from "@upstash/redis/cloudflare";
import type { APIRoute } from "astro";
import type { Note } from "../types/note";
import { getDomainUrl } from "../utilities/utilities";
const HASHSET_KEY = "notes";
const url = import.meta.env.UPSTASH_REDIS_REST_URL;
const token = import.meta.env.UPSTASH_REDIS_REST_TOKEN;
const redis = new Redis({ url, token });
export const get: APIRoute = async function get() {
try {
const notes: Record<string, Note> | null = await redis.hgetall(HASHSET_KEY);
/* notes (when not null) has structure:
{
'1660841122914': { // this is the note id
title: 'First One',
text: 'First text',
modified: '2022-08-18T16:45:22.914Z'
},
'1660843285978': {
title: 'Second one',
text: 'Hi',
modified: '2022-08-18T17:21:25.978Z'
}
}
*/
if (notes) {
const sortedNotes: Note[] = Object.entries(notes)
.map(([id, { title, text, modified }]) => ({
id,
title,
text,
modified,
}))
.sort((a, b) => Date.parse(b.modified) - Date.parse(a.modified));
return new Response(JSON.stringify({ notes: sortedNotes }), {
headers: { "content-type": "application/json" },
status: 200,
});
}
return new Response(JSON.stringify({ notes: [] }), {
headers: { "content-type": "application/json" },
status: 200,
});
} catch (error: unknown) {
console.error(`Error in /api GET method: ${error as string}`);
return new Response(JSON.stringify({ notes: [] }), {
headers: { "content-type": "application/json" },
status: 200,
});
}
};
export const post: APIRoute = async function post({ request }) {
try {
const form = await request.formData();
const action = form.get("action");
const redirectURL: string = getDomainUrl(request);
const urlParams = new URLSearchParams();
switch (action) {
case "create": {
const date = new Date();
const id = date.getTime();
const modified = date.toISOString();
const note = {
title: "Untitled",
text: "",
modified,
};
await redis.hset(HASHSET_KEY, {
[id]: JSON.stringify(note),
});
urlParams.append("edit", "true");
urlParams.append("note", id.toString(10));
break;
}
case "update": {
const id = form.get("id") as string;
const title = form.get("title");
const text = form.get("text");
const modified = new Date().toISOString();
await redis.hset(HASHSET_KEY, {
[id]: JSON.stringify({ title, text, modified }),
});
urlParams.append("note", id);
break;
}
case "delete": {
const id = form.get("id");
if (typeof id === "string") {
await redis.hdel(HASHSET_KEY, id);
}
break;
}
default:
}
return Response.redirect(`${redirectURL}?${urlParams.toString()}`);
} catch (error: unknown) {
console.error(`Error in /api PUT method: ${error as string}`);
return Response.redirect(getDomainUrl(request));
}
};
因此,我们使用的主要升级redis命令是:
-
创建:
await redis.hset(HASHSET_KEY, { [id]: JSON.stringify({ title, text, modified}) });
, -
阅读:
await redis.hgetall(HASHSET_KEY);
, -
更新:
await redis.hset(HASHSET_KEY, { [id]: JSON.stringify({ title, text, modified}) });
, -
delete :
await redis.hdel(HASHSET_KEY, id);
。
访问HTTP标头
默认情况下,Astro是一个静态站点生成器(SSG),我们希望访问服务器端渲染(SSR),因此我们始终显示数据库中的最新注释。稍后我们将添加一个CloudFlare适配器,并自动将我们从SSG切换到SSR。不过,我们希望在此期间访问请求标头,这是在下一节中使用的getDomainUrl
函数中。要切换到SSR更新astro.config.js
文件以包括output: 'server'
,然后重新启动您的DEV服务器:
import { defineConfig } from "astro/config";
import svelte from "@astrojs/svelte";
// https://astro.build/config
export default defineConfig({
output: "server",
integrations: [svelte()],
});
前端:创建和更新
好吧,我们现在取得了一些进展。接下来,我们要更新index.astro
文件以读取URL中的查询参数,然后将用户引导到正确的视图。一旦我们有连线,我们将创建和编辑一些新的笔记。
Astro的Astro.url
和Astro.request
API,让我们访问搜索参数,还可以帮助我们确保将请求发送到正确的URL。更新index.astro
的脚本部分:
---
import EditNote from '~components/EditNote.svelte';
import HeadingBar from '~components/HeadingBar.svelte';
import NoteBody from '~components/NoteBody.svelte';
import NotesList from '~components/NotesList.svelte';
import Layout from '~layouts/Layout.astro';
import type { Note } from '~types/note';
import { getDomainUrl } from '~utilities/utilities';
const { request, url } = Astro;
const domainUrl = getDomainUrl(request);
const { searchParams } = url;
const selectedId = searchParams.get('note');
const editMode = searchParams.get('edit') === 'true';
const response = await fetch(`${domainUrl}/api`, { method: 'GET' });
const { notes }: { notes: Note[] } = await response.json();
const selectedNote = notes.find(({ id }) => id === selectedId) ?? notes[0];
const title = 'Upstash Astro Notes';
---
searchParams
是URLSearchParams object from the Browser API。您可以看到我们还使用获取浏览器API将GET请求发送到我们的端点,并吸入注释列表(当前为空)。 Astro大量使用浏览器标准。
getDomainUrl
是实用程序函数。我们在src/utilities/utilities
中定义它。现在将返回http://localhost:3000
,类似http://localhost:8788
,当时我们以后使用Cloudflare Wrangler工具本地运行该站点,最后,https://example.com
当我们将网站部署到Web时。
作为最后一步,在index.astro
中更新模板代码:
<Layout title={title}>
<main class="wrapper">
<h1>{title}</h1>
<div class="container">
<header class="heading">
{selectedNote ? <HeadingBar client:load note={selectedNote} {editMode} /> : null}
</header>
<aside class="list">
<NotesList client:load {notes} {selectedId} {editMode} />
</aside>
<section class="note">
{editMode && selectedNote ? <EditNote client:load note={selectedNote} /> : null}
{!editMode && selectedNote ? <NoteBody note={selectedNote} /> : null}
</section>
</div>
</main>
</Layout>
在这里,我们使用的是从URL提取的editMode
参数。
开始使用Astro和Redis:测试它
按[ new ]
按钮创建新注释。检查浏览器地址栏中的URL。我有http://localhost:3000/?edit=true¬e=1661428055833
。按下按钮,使用create
操作调用API put
功能。这在Upstash Redis数据库中创建了一个新注释,然后将浏览器重定向到此URL。 index.astro
中的逻辑拾取了edit=true
查询参数,因此显示了EditNote
组件,而不是NoteBody
。难以置信的是,我们做了所有这些主要依靠标准API的所有操作吗?
单击Save Changes
。我们在这里使用的表单以与创建相似的方式工作,尽管这次表单代码在src/components/EditNote.svelte
中。
一旦保存第一个便条,请尝试创建另一个注释。这次单击Cancel
,而不是保存。在这里,我们使用JavaScript的位置,这就是为什么我们在index.astro
中将client:load
指令添加到EditNote
的原因。对于“取消按钮”,我们使用preventDefault
并运行此handlecancel函数:
function handleCancel() {
const searchParams = new URLSearchParams({ note: id });
window.location.replace(`/?${searchParams}`);
}
将用户推回主页,而不是对Redis进行更改。这表明我们有一个JavaScript“逃生舱口”,每当我们确实需要一些互动性时。选择您刚刚创建的注释而无需编辑并点击[ delete ]
按钮。它的形式在HeadingBar
组件中。
构建和部署
Astro为主要的云托管提供商建造了适配器。添加CloudFlare工人适配器:
pnpm astro add cloudflare
接受默认值以自动配置。现在我们可以构建网站:
pnpm run build
如果这是您第一次在计算机上使用Wrangler,则需要通过运行pnpm wrangler login
命令将本地实例链接到Cloudflare帐户。检查Wrangler get started guide for full details。 wrangler
CLI工具包含在项目package.json
中。
要预览该站点,因为CloudFlare工人与其他环境有所不同,我们会更改默认命令。我将其保存为package.json
中的preview:cloudlfare
脚本,因此运行pnpm preview:cloudflare
。要查看网站,请转到浏览器中的http://127.0.0.1:8788
。
查看项目的dist
文件夹。这是Astro输出您的生产地点的地方。那里会有一个_worker.js
。这是Astro自动为您生成的Cloudflare Worker。我们在库中包含的wrangler.toml
文件中添加了路径。
部署到Cloudflare
有一个很小的更改,可以支持Cloudflare Worker运行时阅读秘密环境变量。这是需要解决方法的方法,而Astro团队找到了一个永久的解决方案,以提供开箱即用的支持。更新astro.config.js
:
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import svelte from "@astrojs/svelte";
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
// https://astro.build/config
export default defineConfig({
output: "server",
integrations: [svelte()],
adapter: cloudflare(),
vite: {
define: {
"process.env.UPSTASH_REDIS_REST_URL": JSON.stringify(
process.env.UPSTASH_REDIS_REST_URL,
),
"process.env.UPSTASH_REDIS_REST_TOKEN": JSON.stringify(
process.env.UPSTASH_REDIS_REST_TOKEN,
),
},
},
});
这些行使我们的秘密环境变量准确可用,而Cloudflare服务器将在哪里寻找它们。最后,要将远程构建环境设置为使用节点16,请在项目root文件夹中创建一个.nvmrc
文件,然后将内容设置为be 16
。
我们现在准备部署。要使网站进行直播,请提交并将存储库推向GIT服务。下一个log into your Cloudflare account并选择页面,然后创建一个项目 /连接到git < / strong>。链接到您的git服务。选择 Astro 作为框架预设。最后,请记住在单击保存和部署之前添加两个环境变量。
。开始使用Astro和Redis:结束
这就是我现在想向您展示的一切。该教程仅展示了我们可以使用Upstash和Astro所能做的一小部分,但我希望您足以让您开始使用Astro和Redis。请按照上述链接探讨我们提到的功能的细节。检查Upstash blog for more tutorials,您可以learn more Astro from Rodney Lab。 Let me know how you found this tutorial以及您的下一个项目将是什么!