Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions docs/2.deploy/20.providers/azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
Integration with this provider is possible with [zero configuration](/deploy/#zero-config-providers).
::

[Azure Static Web Apps](https://azure.microsoft.com/en-us/products/app-service/static) are designed to be deployed continuously in a [GitHub Actions workflow](https://docs.microsoft.com/en-us/azure/static-web-apps/github-actions-workflow). By default, Nitro will detect this deployment environment and enable the `azure` preset.
[Azure Static Web Apps](https://azure.microsoft.com/en-us/products/app-service/static) are designed to be deployed continuously in a [GitHub Actions workflow](https://docs.microsoft.com/en-us/azure/static-web-apps/github-actions-workflow). By default, Nitro will detect this deployment environment and enable the `azure-swa` preset.

### Local preview

Expand All @@ -21,7 +21,7 @@ Install [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azur
You can invoke a development environment to preview before deploying.

```bash
NITRO_PRESET=azure npx nypm@latest build
NITRO_PRESET=azure-swa npx nypm@latest build
npx @azure/static-web-apps-cli start .output/public --api-location .output/server
```

Expand All @@ -32,11 +32,14 @@ Azure Static Web Apps are [configured](https://learn.microsoft.com/en-us/azure/s
Nitro automatically generates this configuration file whenever the application is built with the `azure` preset.
Comment thread
Xiang-CH marked this conversation as resolved.
Outdated

Nitro will automatically add the following properties based on the following criteria:
| Property | Criteria | Default |
| --- | --- | --- |
| **[platform.apiRuntime](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#platform)** | Will automatically set to `node:16` or `node:14` depending on your package configuration. | `node:16` |
| **[navigationFallback.rewrite](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#fallback-routes)** | Is always `/api/server` | `/api/server` |
| **[routes](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#routes)** | All prerendered routes are added. Additionally, if you do not have an `index.html` file an empty one is created for you for compatibility purposes and also requests to `/index.html` are redirected to the root directory which is handled by `/api/server`. | `[]` |


| Property | Criteria | Default |
| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| **[platform.apiRuntime](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#platform)** | Uses `node:20` or `node:22` when `package.json` `engines.node` (or your current Node major version) matches those supported versions; otherwise falls back to `node:18`. | `node:18` |
| **[navigationFallback.rewrite](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#fallback-routes)** | Is always `/api/server` | `/api/server` |
| **[routes](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#routes)** | All prerendered routes are added. Additionally, if you do not have an `index.html` file an empty one is created for you for compatibility purposes and also requests to `/index.html` are redirected to the root directory which is handled by `/api/server`. | `[]` |


### Custom configuration

Expand All @@ -50,12 +53,14 @@ When you link your GitHub repository to Azure Static Web Apps, a workflow file i

When you are asked to select your framework, select custom and provide the following information:

| Input | Value |
| --- | --- |
| **app_location** | '/' |
| **api_location** | '.output/server' |

| Input | Value |
| ------------------- | ---------------- |
| **app_location** | '/' |
| **api_location** | '.output/server' |
| **output_location** | '.output/public' |


If you miss this step, you can always find the build configuration section in your workflow and update the build configuration:

```yaml [.github/workflows/azure-static-web-apps-<RANDOM_NAME>.yml]
Expand All @@ -68,5 +73,4 @@ output_location: '.output/public'

That's it! Now Azure Static Web Apps will automatically deploy your Nitro-powered application on push.

If you are using runtimeConfig, you will likely want to configure the corresponding [environment variables on Azure](https://docs.microsoft.com/en-us/azure/static-web-apps/application-settings).

If you are using runtimeConfig, you will likely want to configure the corresponding [environment variables on Azure](https://docs.microsoft.com/en-us/azure/static-web-apps/application-settings).
20 changes: 19 additions & 1 deletion src/presets/azure/runtime/_utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Cookie } from "@azure/functions";
import type { Cookie, HttpRequest } from "@azure/functions";
import { parse } from "cookie-es";

export function getAzureParsedCookiesFromHeaders(headers: Headers): Cookie[] {
Expand Down Expand Up @@ -32,6 +32,24 @@ export function getAzureParsedCookiesFromHeaders(headers: Headers): Cookie[] {
return azureCookies;
}

export function resolveBaseUrl(req: HttpRequest) {
const forwardedProto = req.headers["x-forwarded-proto"];
const forwardedHost = req.headers["x-forwarded-host"];
const host = forwardedHost || req.headers["host"];
if (host) {
return `${forwardedProto || "http"}://${host}`;
}
const originalUrl = req.headers["x-ms-original-url"];
if (originalUrl) {
try {
return new URL(originalUrl).origin;
} catch {
// ignore invalid original URL
}
Comment thread
Xiang-CH marked this conversation as resolved.
}
return "http://localhost";
}
Comment thread
Xiang-CH marked this conversation as resolved.

function parseNumberOrDate(expires: string) {
const expiresAsNumber = parseNumber(expires);
if (expiresAsNumber !== undefined) {
Expand Down
7 changes: 4 additions & 3 deletions src/presets/azure/runtime/azure-swa.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "#nitro/virtual/polyfills";
import { parseURL } from "ufo";
import { useNitroApp } from "nitro/app";
import { getAzureParsedCookiesFromHeaders } from "./_utils.ts";
import { getAzureParsedCookiesFromHeaders, resolveBaseUrl } from "./_utils.ts";

import type { HttpRequest, HttpResponse, HttpResponseSimple } from "@azure/functions";

Expand All @@ -19,8 +19,9 @@ export async function handle(context: { res: HttpResponse }, req: HttpRequest) {
url = "/api/" + (req.params.url || "");
}

const request = new Request(url, {
const request = new Request(new URL(url, resolveBaseUrl(req)), {
method: req.method || undefined,
headers: new Headers(req.headers),
// https://github.com/Azure/azure-functions-nodejs-worker/issues/294
// https://github.com/Azure/azure-functions-host/issues/293
body: req.bufferBody ?? req.rawBody,
Expand All @@ -32,7 +33,7 @@ export async function handle(context: { res: HttpResponse }, req: HttpRequest) {
// (v4) https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#http-response
context.res = {
status: response.status,
body: response.body,
body: response.body ? Buffer.from(await response.arrayBuffer()) : undefined,
cookies: getAzureParsedCookiesFromHeaders(response.headers),
headers: Object.fromEntries(
[...response.headers.entries()].filter(([key]) => key !== "set-cookie")
Expand Down