Astro和Azure静态Web应用程序
#javascript #网络开发人员 #azure #astro

SpaceXUnsplash

的封面照片

我非常看好的网络框架之一就是Astro。我主张并现在使用它,因为大约一年,坦率地说,它可以完成工作。最近,我有机会建立了一个会议网站(请参阅Micro Frontends Conference),该网站最终应在Azure托管。对于这样一个信息驱动的静态页面,astro不仅是理想的。作为Azure的托管服务,我选择了Azure静态Web应用程序(SWA)。

在本文中,我想向您介绍Astro是什么,以及为什么它是这样一个项目的理想选择。我将向您介绍Azure SWA作为托管候选人,以及您去那里时可能要考虑的事情。话...

什么是Astro?

Astro是一个专注于内容的现代网络框架。它最初是静态站点生成器(即,为您预先渲染所有内容,这是将页面上传到一些廉价静态存储的理想之选),但已经发展到了这一点。现在,您可以选择几种托管模型。对于我创建的静态站点模式的页面就足够了。

Astro还试图使开发人员非常友好。正如其他Web Frameworks普及的那样,Astro也是基于组件的,这使其可重复使用性和合成性非常好。 Astro组件分为两个部分:组件脚本和组件模板。前者负责模板中可以使用的所有事物,而后者是实际表示形式,即将要渲染的内容。

一个快速示例,显示Astro组件的外观:

---
import SpeakerPreview from "./SpeakerPreview.astro";

export interface Props {
  title: "string;"
  speakers: Array<{
    id: string;
    name: string;
    avatar: string;
  }>;
}

const { title, speakers } = Astro.props;
---

<a href="/schedule" class="backlink">
  Back to schedule
</a>
<div class="talk-details">
  <h3 class="socials-header">{title}</h3>
</div>
<div class="talk-details">
  <h3 class="socials-header">Speakers</h3>
  {
    speakers.map((speaker) => (
      <a href={`/speakers/${speaker.id}`}>
        <SpeakerPreview speakers={[speaker]} />
      </a>
    ))
  }
</div>

在上一个示例中,我们教模板有关要使用的另一个组件(SpeakerPreview)。这是由其导入定义的。这样,我们只能导入任何*.astro文件以获取对Astro组件的引用。

通过惯例,我们可以使用Typescript来定义Astro组件的道具。我们需要的只是在组件脚本中导出Props接口。在这里,Astro支持打字条开箱即用,而无需进行任何更改。但是,按照JSX的规则,模板部分非常接近HTML。因此,我们可以使用Curly Bracs {}进行表达开关。同样,只需使用pascalcase而不是蛇形案例,就可以参考导入的组件。

作为Astro的主要目标是HTML(而不是DOM),是内置元素(例如adiv)的道具是他们的属性(“ class”),而不是其属性(“ className”)。您可以使用their docs在Astro上找到更多信息。

是什么使Astro吸引人?

Astro试图通过优化和剥离不必要的部分来使最快的页面成为可能。对于我们的会议网站,这看起来如下:

Measure Performance

要实现这一行为做几件事:

  • 由于组件模板本质上是JSX,因此HTML将以缩合形式得出(即使用此技术,不必要的whitespace的剥离是微不足道的)。
  • Astro使用特殊的stylescript块。 style在SSR的CSS-IN-JS上有些接近,即,将其组合到单个style Block per < / em> page-page-删除未使用的类 /代码。 script元素也正在捆绑。
  • 可以通过使用例如Image元素(以下更多)来优化图像和其他资源。

有些人可能还想提到,Astro使用所谓的岛屿建筑将来自其他框架的组件(例如,反应)进行交互式。我认为,尽管这可能是使用的好功能,但这不应该是您的主要问题。例如,我将本文用作示例的网站使用React组件为其管理页面,但实际上只是静态内容,它试图避免尽可能多地使用JavaScript。

让我们看看如何使用optin @astrojs/image软件包与sharp(另一个软件包,可以由@astrojs/image/sharp使用)来优化图像:

import { defineConfig } from "astro/config";
import image from "@astrojs/image";

export default defineConfig({
  integrations: [
    image({
      serviceEntryPoint: "@astrojs/image/sharp",
    }),
  ],
});

使用此信息,我们现在可以避免编写<img src="...">,而是写下:

---
import { Image } from "@astrojs/image/components";
---
<Image
    alt="Some text"
    src="../path-to-image/file.png"
    loading="lazy"
    format="webp"
    width={220}
    height={260}
/>

很棒的是,优化不仅将图像转换为所需的格式(例如WebP),而且还将考虑给定的维度(上面的情况为220x260)。因此,我们真的不需要手动优化,剪切或缩放图像。我们让Astro做这项繁琐的工作。

什么是Azure静态Web应用程序?

向Azure发布一组静态文件非常容易且非常有效。我们需要的只是一个存储帐户,其中包含BLOB存储。然后,我们可以在刀片中启用具有相同名称的刀片中的“静态网站”功能:

Activating Static Website on Azure Blob Storage

如果我们想进一步优化交付,我们还可以获得CDN服务并将其链接到Azure Blob存储。问题解决了。现在,我们已经获得了静态资产的第一批交付。但是,...

  • 安全性(身份验证和授权)
  • 动态后端功能(例如,访问某些数据库)
  • 多个环境(例如,作为开发或预览环境)

使其更容易,Microsoft向名为Azure static Web应用程序的Azure引入了专用服务。从本质上讲,它将边缘第一资产交付与预定义的可自定义路由规则和Azure功能相结合。按照惯例,使用/api段的路径将通过相应的Azure函数来处理,而其他路径将导致上载的静态资产。该路由规则还允许对某些错误进行自定义(不仅找不到“ 404”错误,而且还找不到任何其他错误,例如内部服务器“ 500”错误)。以/.auth开头的特殊路径将非常轻松地连接身份验证。

整个配置可以在staticwebapp.config.json中进行,看起来像这样:

{
  "routes": [
    {
      "route": "/.auth/login/twitter",
      "statusCode": 404
    },
    {
      "route": "/.auth/login/github",
      "statusCode": 404
    },
    {
      "route": "/admin",
      "allowedRoles": ["administrator"]
    }
  ],
  "auth": {
    "rolesSource": "/api/get-roles",
    "identityProviders": {
      // ...
    }
  },
  "platform": {
    "apiRuntime": "node:16"
  },
  "responseOverrides": {
    "401": {
      "redirect": "/.auth/login/aad?post_login_redirect_uri=.referrer",
      "statusCode": 302
    },
    "404": {
      "rewrite": "/404",
      "statusCode": 404
    }
  }
}

在此处,我们定义了一些路由(尤其是 *de *通过Twitter和github激活登录),并引入一些响应替代。在后者中,我们告诉SWA,应将401(未经授权)错误重定向到登录页面,而404错误应通过自定义页面显示。此外,我们将Azure函数的平台设置为节点V16。

是什么使Azure SWA吸引人?

这种托管的提供商在市场上有很多可用的产品。诸如Fly.io,Vercel,Heroku等之类的东西提供了相同的(以及更多)。但是,对于这些产品,您通常会支付更高的价格。当然,这是有道理的,因为他们的产品超出了我们在这里所看到的,但这正是重点:为什么要少付更多。

如果

,所有的azure swa都非常适合
  • 您已经有Azure订阅
  • 可以使用一些API调用来增强的大多数静态(即非服务器端渲染)页面很好
  • 想要开箱即用的许多东西(即以更无用的方式) - 例如身份验证

如果您有服务器端渲染页面或需要自定义的大部分身份验证流程。

就个人而言,我喜欢Aure SWA,因为它快速且易于部署,并且使用了一个非常有效的模型,可以深入集成到Azure中。例如,要查看Azure功能的日志输出,您将连接应用程序Insights Workbook。在此工作簿中,您将获得完整的日志内省和可视化。不需要完整的麋鹿堆栈或类似的东西 - 一切已经存在。当然,如果这不是您想要的,那么整个过程是一个问题。记录部分上的自定义很麻烦。

开发和部署

使用简单的静态存储与某些后端动力学形式的SSG组合可以非常吸引人,但需要一些额外的接线才能获得方便的开发体验。

进行开发和部署的主要驱动力是@azure/static-web-apps-cli。这有助于我们使事情变得更轻松。它的CLI工具(swa)实际上只是一个编排者 - 使用Azure Functions Core Tools或Astro的CLI等事物。

使用swa start对我有用的配置是以下 swa-cli.config.json

{
  "$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
  "configurations": {
    "app": {
      "appLocation": "src",
      "apiLocation": "api",
      "outputLocation": "dist",
      "appBuildCommand": "npm run build",
      "apiBuildCommand": "npm run build --if-present",
      "run": "npm run dev",
      "appDevserverUrl": "http://localhost:3000"
    }
  }
}

虽然apiLocation指的是具有自己的 package.json 的目录,但其余的人会教SWA CLI有关如何使用Astro的信息。例如,npm run build本质上只是astro buildnpm run devastro dev。当启动时(通常这将从4280之类的港口开始),4280代理在3000港口提供的资产。同样,API(位于Azure函数核心工具CLI定义的某个端口上)也被代理(使用/api段)。

总结一下 - 几乎在这里处理。部署还利用了SWA CLI:

swa deploy ./dist --env production --api-location api --deployment-token $SWA_TOKEN

在这里,我们明确地告诉SWA CLI,应将./dist文件夹用于静态Web App Assets,而./api目录应用于使用的Azure函数。在CI/CD运行期间,部署令牌将作为环境变量注入。

Azure功能的打字稿

就个人而言,我几乎只使用Typescript开发。但是,Azure功能需要使用JavaScript(或其他内容,例如C#)。幸运的是,Typescript总是可以被转移,但是然后我们需要提出二级结构。例如,我要做的是以下内容:

api/function-name/function.json
api/function-name/index.ts
api/function-name/...

function.json包含对scriptFile的重新引用(即,通常它会隐式地转到“ index.js”,但是由于我们使用Typescript,我们需要将其更改为移植的伪像):

{
  "bindings": [
    // ...
  ],
  "scriptFile": "../dist/function-name.js"
}

在常见的dist文件夹中收集功能的文件是有道理的,但是只有没有冲突。确保无冲突处理和快速启动性能的一种好方法是避免使用tsc进行转介。相反,我们可以使用像esbuild这样的捆绑器来优化资产。

以下片段显示了build.js文件的示例,该文件可用于触发构建:

const { build } = require("esbuild");
const { readdirSync, statSync } = require("fs");
const { resolve } = require("path");

const entryFileNames = ["index.tsx", "index.ts", "index.js"];
const watch = process.argv.includes("--watch");

const entryPoints = {};

for (const dir of readdirSync(__dirname)) {
  const p = resolve(__dirname, dir);

  if (statSync(p).isDirectory()) {
    const names = readdirSync(p);

    if (names.includes("function.json")) {
        const [name] = names.filter((m) => entryFileNames.includes(m));

        if (name) {
        const fn = resolve(p, name);
        entryPoints[dir] = fn;
        }
    }
  }
}

build({
  watch,
  entryPoints,
  bundle: true,
  outdir: resolve(__dirname, "dist"),
  format: "cjs",
  platform: "node",
});

在这里,我们浏览当前目录中包含的所有目录。如果我们找到匹配(例如, function-name/index.ts ),我们将其添加为入口点。每个入口点都使用index.tsindex.tsx(或类似)文件作为参考,其中源目录的名称被用作输出文件的名称。此外,我们可以使用--watch选项以观察模式调用此。

结论

Azure静态Web应用程序是一个出色的平台,可以按一些后端需求推出静态网页。 Azure功能的开发模型既容易又灵活,这为我们提供了有效工作的适量界限。

将Astro用作静态资产的SSG具有多种优势,可以与Azure SWA结合使用。可以将更多的互动式(例如会议页面中的管理区域)作为交互性岛包括,而整体内容完全由Astro驱动,从而预先渲染。