ð为什么要新鲜使用Deno?
- deno Fresh 构建快速站点因此您获得头等舱用户体验(ux),
- 它使用平台因此,如果您已经知道 javascript apis ,那么新鲜开始就可以很快开始,将它们与混音,Astro或Sveltekit一起使用),
- 令人惊叹的开发人员体验(DX) 无服务器没有构建步骤,部署是 live 几乎立即强>。
ð¶½什么是新鲜的?
deno Fresh是下一个代网站构建器。 它构建了服务器端渲染(SSR)站点并支持部分水合。在DENO JavaScript运行时进行新鲜运行,该运行时间优先考虑安全性和性能。在Deno,JavaScript API是一流的公民 - 它使用该平台。这使DeNo更快,更易于学习。 Deno在服务器上呈现您的网站,默认情况下将零javaScript归为浏览器。这使得内容网站的新鲜选择。通过内容网站,我们的意思是那些主要是文档,博客等,通常不是很互动。
当您需要在新鲜站点上进行交互性时,可以使用Fresh's 部分水合功能集。这仅意味着页面的部分是交互式的部分,也称为互动岛,得到水合。水合只是浏览器中页面加载中的一步,允许交互性的代码加载,并且这些组件的状态变得一致。
ð - 您如何旋转一个新鲜的应用程序?
要走,您将在开发环境中需要Deno。如果您尚未安装它,它很快就可以从MacOS上使用自制的终端设置或Linux上的Shell脚本:
# macOS
brew install deno
# Linux
curl -fsSL https://deno.land/install.sh | sh
# Test installation worked
deno --version
与node.js基于运行时的工具相比,通常您可以通过URL运行应用程序和访问软件包。这正是我们可以采取的措施来旋转新的Deno Fresh应用程序。安装了Deno后,在终端中键入这些命令以进行操作:
deno run -A -r https://fresh.deno.dev my-fresh-app && cd $_
deno task start
ð§deno Fresh开始:里面有什么?
.
├── components
│ └── Button.tsx
├── deno.json
├── deno.lock
├── dev.ts
├── fresh.gen.ts
├── import_map.json
├── islands
│ └── Counter.tsx
├── main.ts
├── routes
│ ├── [name].tsx
│ ├── api
│ │ └── joke.ts
│ └── index.tsx
└── static
├── favicon.ico
└── logo.svg
- 使用Deno Fresh,您可以在 preacct 中写下您的组件(如果您第一次提前做出反应)。您的提前组件文件会根据是否具有互动性,将其放置在
components
或islands
目录中。因此,更改状态的按钮可以在islands
中进行,但是使用平台和WebApis的表单可以进入components
。 -
deno.json
此松散地图映射到node.js中的package.json
文件。随附的start
任务是您运行的要启动应用程序,并告诉DeNo运行dev.ts
文件(也列出了上面), -
import_map.json
以及列出包装的别名,我们将看到如何在此文件中添加项目源文件的导入别名, -
main.ts
:这是我们从中运行内置的Web服务器的地方。您可以为TLS添加其他配置,而不是这里的内容, -
routes
:此文件夹包含将其映射到网站上实际页面的文件。如果您已经使用 Astro , remix 或 next.js 基于文件的路由系统将非常熟悉。routes/index.tsx
将在您的最终站点上映射到https://example.com/
,而routes/about.tsx
将映射到https://example.com/about
。routes/[name].tsx
是动态页面模板。这提供了例如,从单个文件中创建/offices/london
,/offices/berlin
和/offices/mumbai
,而无需重复内容并访问模板中的城市名称参数(/offices/[office-name].tsx
)。 。
-
static
适用于不需要诸如Favicons,pwas或 logos 的manifest.webmanifest
文件。 。
故意缺少什么?
注意没有:
-
package.json
:使用Deno Fresh,您可以使用import_map.json
用于依赖项和deno.json
中的tasks
字段用于脚本, -
tsconfig.json
:Deno Fresh带有内置的打字稿支持,并选择明智的默认值在引擎盖下,可以帮助您更快地进行新项目, -
eslint.js
&eslint.config.js
:只需使用deno lint
命令 - 不需要配置这个, -
.prettierrc
&.prettierignore
:类似于Rust,格式也已集成到工具中。当您想整理代码时,运行deno fmt
, -
vitest.config.ts
:您猜到了deNo在工具中内置了
ð«9 deno入门的快速提示
- 权限:DENO优先确定安全性,并使您对应用程序的访问权限有了更多的控制。
{
"tasks": {
"start": "deno run -A --watch=static/,routes/ dev.ts"
}, // ...TRUNCATED
}
start
脚本中的-A
标志授予我们的应用程序访问所有权限,包括文件系统(读取和写入),环境变量和网络。如果您希望更细的粒度控件将其删除并重新启动您的应用程序。现在,您将看到提示在终端中要求各种权限。
-
环境变量
在云中,您可以在DENO部署控制台(或您的主机等效)中定义秘密。在本地,与其他工具一样,您可以使用
.env
文件。请记住将其添加到您的.gitignore
文件中,以免秘密投入您的git reco。
.env
.DS_Store
DATABASE_PASSWORD="open-sesame"
对于您的项目访问.env
文件,您可以添加https://deno.land/std@0.171.0/dotenv
软件包。 DENO的新方法是用$std/
别名更新导入地图:
{
"imports": {
"$fresh/": "https://deno.land/x/fresh@1.1.2/",
"preact": "https://esm.sh/preact@10.11.0",
"preact/": "https://esm.sh/preact@10.11.0/",
"preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4",
"@preact/signals": "https://esm.sh/*@preact/signals@1.0.3",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.0.1",
"$std/": "https://deno.land/std@0.167.0/"
}
}
作为最佳实践,包括URL中的软件包版本(以使您的应用程序在较新的包装版本中引入破坏变化时,请按预期工作)。接下来,从dev.ts
文件中的dotenv
导入加载脚本:
#!/usr/bin/env -S deno run -A --watch=static/,routes/
import dev from "$fresh/dev.ts";
import "$std/dotenv/load.ts";
await dev(import.meta.url, "./main.ts");
请注意两件事:您将.ts
扩展包含在路径中,您可以使用刚创建的新别名。如果需要,您可以在导入语句中写出整个URL,而不是使用别名:
// EXAMPLE ONLY PREFER USING ALIASES AS ABOVE
import "https://deno.land/std@0.167.0/std/dotenv/load.ts";
这里的缺点是,您可能会在其他源文件中使用std
,当您想升级到0.168.0
时,您需要更新您包含完整路径的每个文件。使用别名方法,您只需要更新该文件导入地图。
最后,在您的源代码中,您可以使用Deno.env.get()
访问秘密变量:
const DATABASE_PASSWORD = Deno.env.get("DATABASE_PASSWORD");
if (typeof DATABASE_PASSWORD !== 'string') {
throw new Error("env `DATABASE_PASSWORD` must be set");
}
-
vscode设置:您可能已经在项目中有一个
.vscode/extensions.json
文件(取决于您回答设置提示的方式)。
{
"recommendations": [
"denoland.vscode-deno"
]
}
这将导致VSCODE在打开项目时提示您安装DENO扩展程序。我注意到,即使在非DENO项目中,扩展也正在连接到网络。因此,现在我将其按正常安装,然后在Vscode扩展程序中找到DENO,然后单击 disable 按钮。最后,我单击下拉列表以选择 enable(workspace)。
扩展名增加了刺激提示和格式化功能。要使用保存格式,请更新.vscode/settings.json
:
{
"deno.enable": true,
"deno.lint": true,
"editor.defaultFormatter": "denoland.vscode-deno",
"editor.formatOnSave": true,
}
我注意到当我从终端运行deno fmt
时,自动格式保存的文件会稍微更改,但是想象这将很快解决。
-
浏览器与服务器在其他框架中,您可能还记得必须进行一些检查以确保仅在客户端中运行一块代码。您可以在
components/Button.tsx
中看到一个如何实现这一目标的示例:
import { JSX } from "preact";
import { IS_BROWSER } from "$fresh/runtime.ts";
export function Button(props: JSX.HTMLAttributes<HTMLButtonElement>) {
return (
<button
{...props}
disabled={!IS_BROWSER || props.disabled}
/>
);
}
如果代码未在浏览器中运行,则在此禁用该按钮,但是如果您使用本地存储(例如),则可以使用此按钮,并且需要通过window.localStorage
在客户端上访问它。
9个快速入门的快速技巧继续(5)(9)
-
deno std 我们以前向
import_map.json
添加了std
软件包以访问dotenv
。这是 deno标准库(Deno具有标准库,例如C和Rust)。除了dotenv
,您还可以使用std
for:-
$std/crypto
:要在服务器端代码中访问webcrypto apis, -
$std/encoding
:用于从Markdown文件中提取前染色或生成BasicAuth HTTP标头的base64, -
$std/http
用于与HTTP Cookie合作。 -
$std/path
用于您可能在node:path
中找到的文件操作, -
$std/testing/asserts
,$std/testing/bdd
和$std/testing/snapshot.ts
用于玩笑风格的asserts
以及行为驱动的测试describe
和it
。对于柴风格expect
尝试https://cdn.skypack.dev/chai@4.3.4?dts
。
-
顺便说一句,从$std/fmt/bytes.ts
导入的format
将文件大小格式化为易于可读字符串。
-
查找软件包:deno与node.js有些不同,因为您不必使用npm作为软件包存储库,也可以从URL导入包装。在引擎盖下,Deno在本地缓存该软件包(有点像PNPM),因此每次启动应用程序时都无需重新下载它们。第三方模块的三个来源是:
- deno x:
https://deno.land/x?
在这里找到deno特定模块, - skypack:
https://cdn.skypack.dev/
NPM软件包的替代方案, - esm.sh:
https://esm.sh/
另一个NPM软件包替代方案。
- deno x:
-
更多的别名以及为外部模块添加别名,还可以为项目文件夹定义它们。例如,更新
import_map.json
:
{
"imports": {
"@/": "./",
"$fresh/": "https://deno.land/x/fresh@1.1.2/",
"preact": "https://esm.sh/preact@10.11.0",
"preact/": "https://esm.sh/preact@10.11.0/",
"preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4",
"@preact/signals": "https://esm.sh/*@preact/signals@1.0.3",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.0.1",
"$std/": "https://deno.land/std@0.167.0/"
}
}
现在我们可以整理routes/index.tsx
中的导入语句:
import { Head } from "$fresh/runtime.ts";
// import Counter from "../islands/Counter.tsx";
import Counter from "@/islands/Counter.tsx";
这可以使您的代码看起来更加干净,并且还可以更轻松地映射导入的位置。
-
404页:创建通过在项目中添加
routes/_404.tsx
文件来创建未找到的自定义页面:
import { Head } from "$fresh/runtime.ts";
import { UnknownPageProps } from "$fresh/server.ts";
export default function NotFoundPage({ url }: UnknownPageProps) {
const title = "Page not found 😢";
const description = "I don’t think you are supposed to be here!";
return (
<>
<Head>
<title>{title}</title>
</Head>
<main>
<h1>{title}</h1>
<p>
Not sure: <code>{url.pathname}</code> exists mate!
</p>
</main>
</>
);
}
注意,我们在此处使用Head
组件将<title>
元素添加到我们的页面的html <head>
中。
-
Favicons去哪儿了?这也是添加您的自托管字体甚至CSS的好地方。如果您使用的是PostCSS,则可能需要将输入CSS放在项目根部的单独的
styles
文件夹中,然后将PostCSS输出输出,将CSS转移到static/styles
。我们将进一步了解如何自动将哈希相附加到服务的文件名上,以便在更新时缓存。
DENO路线文件的解剖结构
作为第一步,请查看Deno Fresh Skeleton内容中包含的routes/index.tsx
文件。它导出一个默认函数,该功能是一个preact组件。如果您熟悉反应或预先反应,那么这里没有什么有趣的。
即使在一个相当基本的网站上,您也可能需要在项目中使用数据库甚至Markdown文件中的内容。这是Deno Fresh的工作,让您在服务器上进行操作并使用Deno 处理程序功能来源。处理程序函数可以与渲染内容(例如,routes/index.tsx
中的导出的React组件)放在同一文件中。我喜欢与渲染内容相同的文件中采购数据的模式。对于较小的网站,它可以帮助您更快地调试,甚至可以帮助您记住几个月前写的页面的工作方式。
DENO新路线请求处理程序
我从一个小的DeNo应用程序中修剪了一个源文件,以安排推文,这是一种可怜的Hootsuite或Buffer的表亲。这将有助于我们说明一些更真实的DENO新鲜功能。让我们首先查看数据处理部分:
import { Handlers, PageProps } from "$fresh/server.ts";
import type {
ScheduledTweet,
} from "@/utils/twitter.ts";
import { Temporal } from "js-temporal/polyfill/?dts";
import { Fragment } from "preact";
interface HappyPathData {
scheduledTweets: ScheduledTweet[];
error?: never;
}
interface ErrorData {
scheduledTweets?: never;
error: string;
}
type Data = HappyPathData | ErrorData;
export const handler: Handlers<Data> = {
GET(request, context) {
// my own function to get list of already scheduled tweets
const scheduledTweets = getScheduledTweets() ?? [];
return context.render({
scheduledTweets,
});
},
POST(request, context) {
const form = await request.formData();
const action = form.get("action");
const id = form.get("id");
if (action === "retweet" && typeof id === "string") {
const text = form.get("text");
const date = form.get("date");
const time = form.get("time");
if (typeof date === "string" && typeof time === "string") {
// my own function to schedule a tweet
scheduleRetweet({
id,
scheduleTime,
text,
});
}
}
const { scheduledTweets } = getScheduledTweets() ?? [];
return context.render({
scheduledTweets,
});
},
};
Typescript支持不断出现,我们什么也没添加以使其正常工作。您可以看到handler
有两个组件:一个GET
处理程序,而当页面加载和一个PUT
处理程序时,我们将通过提交表单(即将出现的前端代码)调用。请注意,GET
和PUT
是如何以HTTP请求方法命名的。DENO喜欢该平台!这些功能以request
和context
参数为输入。 request
是标准的WebAPI请求,我们可以应用formData()
,json()
或text()
方法来操纵请求主体。我们还可以破坏headers
,method
,url
等。
同时,context
包含一个params
对象。对于模板路线(还记得london
,mumbai
等中的办公室)吗?那里的模板文件名是routes/offices/[office-name].tsx
。好吧,例如,如果我们想在访问者访问https://example.com/offices/mumbai
时从数据库中取出正确的办公室的电话号码,我们可以使用上下文访问mumbai
部分:
GET(request, context) {
const {
params: { 'office-name': officeName },
} = context;
const phoneNumber = getPhoneNumber(officeName);
// ...TRUNCATED
context.render()
以及让我们访问路径参数,上下文对象还定义了render
方法。这就是为我们提供服务器端渲染的原因。通过返回它,我们可以将数据传递到客户端模板中。让我看看接下来。
客户端反应代码
请记住,我们可以保持简单,将此代码放在与处理程序同一文件中。我们没有在处理程序中处理上面的操作(以使事情变得简单),但是如果我们从数据库中提取一些问题的推文,我们可能会返回错误。检查客户端代码中的错误,我们可以让用户知道某些内容不正确。这里的<Fragment></Fragment>
在句法上等同于使用<></>
。如果您是不熟悉的反应或预先反应,您可能不知道,我们的渲染元素必须具有一个顶级元素(这就是为什么要包装Fragment
中的其他元素,否则HTMLHead
,Header
,等等都是最高级别的元素。
export default function TweetQueue(ctx: PageProps<Data>) {
const {
data: { error, scheduledTweets, tweets },
} = ctx;
if (error) {
return (
<Fragment>
<HTMLHead
title="Isolinear 🖥 | Twitter | Tweet Queue"
description="Isolinear tweet queue."
/>
<Header />
<h1>Something went wrong!</h1>
<p>{error}</p>
</Fragment>
);
}
const { url } = ctx;
const { searchParams } = url;
const retweet = searchParams.get("retweet");
const id = searchParams.get("id");
const minDate = Temporal.Now.plainDateTimeISO().toPlainDate().toString();
return (
<Fragment>
<h1>Twitter</h1>
<h2>Retweet</h2>
{retweet === "true" && typeof id === "string"
? (
<Fragment>
<h3 id="retweet">Retweet</h3>
<form action="/twitter/tweet-queue" method="post">
<input type="text" name="id" value={id} />
<input
type="text"
name="text"
placeholder="Tweet text"
maxLength={280}
/>
<input type="date" name="date" min={minDate} />
<input type="time" list="tweet-schedule" name="time" />
<input type="hidden" name="action" value="retweet" />
<button type="submit">[ retweet ]</button>
</form>
</Fragment>
)
: null}
</Fragment>
);
}
如果我们需要访问页面URL,则可以使用ctx
Prop进行。最后,请注意,我们有一个表格来处理提交新推文。这可以使用该平台工作,而无需其他JavaScript。如果您是新手,请检查MDN文档。一次学习一次,然后在sveltekit的DeNo Fresh中使用它,在Remix,Astro,甚至是普通的HTML/CSS网站!当用户单击按钮时,表单元素上的action="/twitter/tweet-queue" method="post"
表示浏览器将向POST
http请求发送到/twitter/tweet-queue
(此精确路由)。然后,上面处理程序中的POST
功能将照顾好它。你没有娱乐ð
DeNo Fresh:总结
我们才刚刚开始!但是,帖子不会变得太长,在后续行动中,我们会看到:
- deno Fresh Islands 工作,
- deno的内置测试框架,
- 创建 API路由和更多!
到目前为止的旅程是,我们已经快速看了Deno Fresh的开始。特别是,我们看到了:
- 如何创建一个新的Deno Fresh App ,
- 一些有用的 deno标准库函数,
- 如何将数据传递到客户端React页面。
查看新鲜文档以获取更多详细信息。如果您想了解更多关于Deno和Fresh的内容,请与我们联系。我希望您发现内容有用,并热衷于了解可能的改进。
Deno Fresh:反馈
您发现该帖子有用吗?您想看另一个主题的帖子吗?与新帖子的想法联系。另外,如果您喜欢我的写作风格,请与您联系,如果我可以在咨询中为您的公司网站编写一些帖子。请继续阅读以找到与之联系的方法,以下更远。如果您想支持与此类似的帖子,并且可以浪费几美元,欧元或英镑,请访问consider supporting me through Buy me a Coffee。
最后,请随时在社交媒体帐户上分享所有发现有用的关注者的帖子。除了在下面留下评论外,您还可以通过@askRodney在Twitter上与Mastodon上的@rodney@toot.community和#rodney元素矩阵室取得联系。另外,请参见further ways to get in touch with Rodney Lab。我定期发布在Astro和Deno上。还有subscribe to the newsletter to keep up-to-date与我们的最新项目。