ð¶未固定,图像托管服务和自托管图像
我将这张Deno新鲜响应式图像帖子汇总在一起,以谈论我第一次听到Matt Kane的新Umpic Tool 时的想法。首先设定了 Modern Image插件标准的框架可能是Gatsby,Matt Kane是在其插件上工作的工程师之一。 UMAIC背后的想法是提供一个简单的API,用于在Web应用程序中包含响应式图像。它是考虑到图像托管服务的设计。一种的一种来统治它们的工具,因为有 astro,react,preact和svelte 的组件,并且每种都可以与流行的图像托管服务一起使用。
我经常听到有关图像托管服务的投诉与成本有关。实际上,我在我正在研究的一个副项目中被托管Bill 的惊喜图像击中。从那时起,我偏爱自我托管图像为附带项目。我的想法是使用方便的API ,Umpic提供了自我托管。这可以节省您编写许多用于处理响应式图像的客户端代码。图像文件可以包含在前端项目中或单独的无服务器API应用中。
概念证明
我有点工作。这比最终的工作解决方案更像是概念证明。因为我希望调整API是无服务器并在不同的托管服务上运行的,所以我选择使用 Rust Wasm 对图像进行调整大小的繁重工作。这一切都在起作用,尽管我仍在寻找用于以 avif和WebP 等下一代格式生成图像的解决方案。在这篇文章中,我带您介绍了到目前为止的内容以及对丢失部分的一些想法。
ð§±imgix图像API
我前面提到,Umpic支持多个图像托管服务。对于使用Umpic,拥有自己的自托装图像大小的API模拟现有图像是有意义的。 Imgix Rendering API似乎是一个流行的选择,并由Prismic,Sanity和其他工具使用,因此我选择了。
在本文的其余部分中,我从我构建的DeNo Fresh应用程序中共享一些代码,作为概念证明。它使用Rust WASM模块进行实际调整。我们在这里跳过锈蚀码。在引擎盖下,我们使用image
板条箱进行调整,以防您感兴趣。您可以在github repo中看到锈蚀代码(链接进一步向下)。
客户前端标记
deno Fresh用途提前客户标记。但是,有一些反应和Svelte插件使用相同的API,如果您喜欢其他框架,则将以完全相同的方式工作。
import { Image } from "npm:@unpic/preact";
export default function Home() {
const imageHost = "http://localhost:8000"
return (
<main className="wrapper">
<h1 className="heading">FRESH!</h1>
<section class="images">
<Image
src={`${imageHost}/api/images/dinosaur-selfie.png`}
layout="constrained"
width={128}
height={128}
alt="A dinosaur posing for a selfie"
cdn="imgix"
/>
<Image
src={`${imageHost}/api/images/dinosaur-selfie.png`}
loading="eager"
layout="constrained"
width={256}
height={256}
alt="A dinosaur posing for a selfie"
cdn="imgix"
/>
<Image
src={`${imageHost}/api/images/dinosaur-selfie.png`}
layout="constrained"
width={64}
height={64}
alt="A dinosaur posing for a selfie"
cdn="imgix"
/>
</section>
</main>
);
}
这里最有趣的部分是:
- 我们在
1
中导入umpicImage
组件。它在我们的标记中取代了HTMLimg
。 - 我们将在下面看到
unpic
操纵src
值。要输出正确的代码,我需要使用绝对URL,即使我们使用img
tag,相对的代码也可以。 -
src
值实际上是API路线。在这里,它可以在同一项目中可用,尽管没有什么可以阻止您将API路由分为自己的无服务器应用程序。
ð¥!生成的图像标记
这是为第一个图像生成的HTML:
<img
alt="A dinosaur posing for a selfie"
loading="lazy"
decoding="async"
sizes="(min-width: 128px) 128px, 100vw"
style="
object-fit: cover;
max-width: 128px;
max-height: 128px;
aspect-ratio: 1;
width: 100%;
"
srcset="
http://localhost:8000/api/images/dinosaur-selfie.png?w=128&h=128&fit=min&auto=format 128w,
http://localhost:8000/api/images/dinosaur-selfie.png?w=256&h=256&fit=min&auto=format 256w
"
src="http://localhost:8000/api/images/dinosaur-selfie.png?w=128&h=128&fit=min&auto=format"
/>
这具有您在图像上设置的大多数属性Addy Osmani recommends,以获得良好的用户体验。您可能会注意到我们缺少下一代图像的源集。实际上,有一种方法可以表明浏览器是否支持下一代格式。我稍后再解决!
不过,在我们探讨这一点之前,这里的一些重要功能是:
-
aspect-ratio
设置:这有助于减少累积布局偏移 -
loading="lazy"
:这是一个很好的默认值,Chrome,Firefox和Safari都支持Lazy Loading -
srcset
:为浏览器提供提示的响应部分,因此移动设备最终不应浪费数据下载大于需要的图像
请注意,这些功能从开箱即用。如果您使用Vanilla img
标签,则必须记住手动包括它们。
图像大小的API路线
生成的图像源URL遵循以下模式:
http://localhost:8000/api/images/dinosaur-selfie.png?w=256&h=256&fit=min&auto=format
路径名包含我们需要的图像的文件名。然后,URL搜索参数提供您期望的宽度和高度值。除此之外,我们还具有fit=min
缩放/调整参数。最后,auto=format
表示API应使用content negotiation确定最合适的图像格式(在支持时返回下一代格式)。
使用Deno Fresh,我们可以创建模板API路由。这将在与http://localhost:8000/api/images/[FILENAME]
匹配的路线上聆听。 Astro,Remix和Sveltekit具有处理模板参数的机制。使用Deno Fresh,我们可以在routes/api/images/[file].ts
上创建一个处理程序文件以在这些路线上收听。
import { HandlerContext } from "$fresh/server.ts";
export const handler = async (
request: Request,
context: HandlerContext
): Promise<Response> => {
if (request.method === "GET") {
const {
params: { file },
} = context;
const { url } = request;
const { searchParams } = new URL(url);
const width = searchParams.get("w");
const height = searchParams.get("h");
const fit = searchParams.get("fit");
// TRUNCATED...
在这里,我们只是从请求URL读取图像参数。
查找请求的图像
接下来,我们可以将请求路径名映射到项目中的图像文件。由于路径名中的文件参数可能是任意的,因此检查实际上在项目中实际上有一个匹配文件并返回一个没有一个的404
错误。
// ...TRUNCATED
let image_bytes: Uint8Array | null = null;
try {
image_bytes = await Deno.readFile(`./images/${file}`);
} catch (error: unknown) {
if (error instanceof Deno.errors.NotFound) {
return new Response("Not found", {
status: 404,
});
}
}
// TRUNCATED...
Deno新鲜响应式图像:调整大小
调整大小是使用WASM代码完成的。尽管我决定使用WASM,但JavaScript Sharp库是另一种选择,因此代码可以在更多的环境中部署。 Sharp基于Libvips C库,还有一个相关的WASM-VIPS项目。 wasm-vips is still in the early stages of development。
import { instantiate, resize_image } from "@/lib/rs_lib.generated.js";
export const handler = async (
request: Request,
context: HandlerContext
): Promise<Response> => {
// TRUNCATED...
await instantiate();
const resizeOptions = {
width: Number.parseInt(width),
height: Number.parseInt(height),
...(typeof fit === "string" ? { fit } : {}),
};
const {
error,
resized_image_bytes: resizedImageBytes,
mime_type: mimeType,
} = resize_image(image_bytes, resizeOptions);
第一行中的导入是使处理程序可访问的WASM模块的位置。
Deno新鲜响应图像:响应
最后,我们可以使用缓存标头返回图像。返回404
错误时,将标题设置为不缓存,以防万一有临时问题。
return new Response(new Uint8Array(resizedImageBytes), {
headers: {
"Content-Type": mimeType,
"Cache-Control": "public, max-age=31536000, immutable",
},
});
ðrust wasm模块
wasmbuild
deno模块使DeNo中的WASM代码相当简单。它是wasm-pack
的包装器,如果在DeNo中不起作用的话,您可以直接使用它。但是,在Deno中,只需将wasmbuild
添加到您的deno.json
:
{
"tasks": {
"start": "deno run -A --watch=static/,routes/ dev.ts",
"wasmbuild": "deno run -A https://deno.land/x/wasmbuild@0.10.4/main.ts"
},
"importMap": "./import_map.json",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
然后初始化项目,一旦准备就绪,构建WASM模块:
deno task wasmbuild new
deno task wasmbuild
ðdeno新鲜响应式图像:缺少什么?
我前面提到,这里还没有下一代图像生成。我们可以通过请求检查Accept
标头来实现自己的内容谈判形式:
import { instantiate, resize_image } from "@/lib/rs_lib.generated.js";
export const handler = async (
request: Request,
context: HandlerContext
): Promise<Response> => {
const { headers } = request;
console.log(headers.get("Accept"));
// TRUNCATED...
这里的典型标头值是:
"image/avif,image/webp,*/*"
是针对当前版本的Firefox,让我们知道在这种情况下我们可以发送AVIF或WebP图像。然后,我们可以从WASM模块请求首选格式,因此在支持时它会搅动下一代图像。
缺少的是输出下一代图像的WASM代码。对于WebP,有一些生锈的实现,可以将C LibWep实现放置。同样,对于AVIF,您可以找到C RAV1E库的端口。这些对于在生锈中编写WASM模块并不理想,并且纯粹的生锈实施受到青睐。对于Avif,ravif
库是潜在的纯锈选择。我仍然需要在这里做一些可行性工作。
ð½DENODENO新鲜响应式图像结束了
我们看到了在DeNo中使用Deno新鲜响应图像的一些想法。特别是,您看到了:
- 如何使用
unpic
产生响应式图像标记 - 您如何实施内容谈判用于提供最佳图像
- 用于自托图像API的方法的构建块
complete code for this project (including Rust source) is in the Rodney Lab GitHub repo。我确实希望该帖子对您有帮助,或者为新项目提供了一些灵感。
如果您对此内容或改进建议有一些疑问,请联系。如果愿意,可以在下面添加评论。另外,请了解有关DENO或其他主题的新鲜内容的想法!
ðð½DENO新鲜响应图像:反馈
您发现该帖子有用吗?您想看另一个主题的帖子吗?与新帖子的想法联系。另外,如果您喜欢我的写作风格,请与您的公司网站撰写一些帖子,以联系您的公司网站。请继续阅读以找到与之联系的方法,以下更远。如果您想支持与此类似的帖子,并且可以浪费几美元,欧元或磅,那么请consider supporting me through Buy me a Coffee。
最后,请随时在社交媒体帐户上分享所有发现有用的关注者的帖子。除了在下面留下评论外,您还可以在Twitter上通过@askRodney,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与我们的最新项目一起。