Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions src/presets/_all.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import _awsAmplify from "./aws-amplify/preset.ts";
import _awsLambda from "./aws-lambda/preset.ts";
import _azure from "./azure/preset.ts";
import _bun from "./bun/preset.ts";
import _bunny from "./bunny/preset.ts";
import _cleavr from "./cleavr/preset.ts";
import _cloudflare from "./cloudflare/preset.ts";
import _deno from "./deno/preset.ts";
Expand Down Expand Up @@ -36,6 +37,7 @@ export default [
..._awsLambda,
..._azure,
..._bun,
..._bunny,
..._cleavr,
..._cloudflare,
..._deno,
Expand Down
4 changes: 2 additions & 2 deletions src/presets/_types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export interface PresetOptions {

export const presetsWithConfig = ["awsAmplify","awsLambda","azure","cloudflare","firebase","netlify","vercel"] as const;

export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-pages" | "cloudflare-pages-static" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis-handler" | "iis-node" | "koyeb" | "netlify" | "netlify-edge" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-middleware" | "node-server" | "platform-sh" | "render-com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static";
export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure-swa" | "base-worker" | "bun" | "bunny" | "bunny-edge-scripting" | "cleavr" | "cloudflare-dev" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-pages" | "cloudflare-pages-static" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis-handler" | "iis-node" | "koyeb" | "netlify" | "netlify-edge" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-middleware" | "node-server" | "platform-sh" | "render-com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static";

export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflareDev" | "cloudflare_dev" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "netlify" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-middleware" | "nodeMiddleware" | "node_middleware" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {});
export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "bunny" | "bunny-edge-scripting" | "bunnyEdgeScripting" | "bunny_edge_scripting" | "cleavr" | "cloudflare-dev" | "cloudflareDev" | "cloudflare_dev" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "netlify" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-middleware" | "nodeMiddleware" | "node_middleware" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {});
60 changes: 60 additions & 0 deletions src/presets/bunny/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { defineNitroPreset } from "../_utils/preset.ts";
import type { Nitro } from "nitro/types";
import { builtinModules } from "node:module";
import { rm } from "node:fs/promises";

const edgeScripting = defineNitroPreset(
{
entry: "./bunny/runtime/edge-scripting",

exportConditions: ["deno"],
commands: {
preview: "deno -A ./bunny-edge-scripting.mjs",
},

output: {
dir: "{{ rootDir }}/.output",
serverDir: "{{ output.dir }}",
publicDir: "{{ output.dir }}/public",
},

rollupConfig: {
output: {
format: "esm",
entryFileNames: "bunny-edge-scripting.mjs",
inlineDynamicImports: true,
hoistTransitiveImports: false,
},
external: (id: string) =>
id.startsWith("https://") || id.startsWith("node:") || builtinModules.includes(id),
},

serveStatic: "inline",
minify: true,

hooks: {
"build:before": (nitro: Nitro) => {
if (nitro.options.serveStatic !== "inline" && nitro.options.serveStatic !== false) {
nitro.options.serveStatic = "inline";
nitro.logger.warn(
"Bunny Edge Scripting preset requires `serveStatic` to be `inline` or `false`. Overriding to `inline`."
);
}
},
async compiled(nitro: Nitro) {
// Remove public dir when inlined, usecase is for
// managing assets directly in Bunny Storage
if (nitro.options.serveStatic === "inline") {
const publicDir = nitro.options.output.publicDir;
await rm(publicDir, { recursive: true, force: true });
}
},
},
},
{
aliases: ["bunny"],
name: "bunny-edge-scripting" as const,
}
);

export default [edgeScripting] as const;
20 changes: 20 additions & 0 deletions src/presets/bunny/runtime/edge-scripting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import "#nitro/virtual/polyfills";
import { useNitroApp } from "nitro/app";

const nitroApp = useNitroApp();

// @ts-expect-error
if (typeof Bunny !== "undefined") {
// @ts-expect-error
Bunny.v1.serve(nitroApp.fetch);
} else {
const _parsedPort = Number.parseInt(process.env.NITRO_PORT ?? process.env.PORT ?? "");

Deno.serve(
{
port: Number.isNaN(_parsedPort) ? 3000 : _parsedPort,
hostname: process.env.NITRO_HOST || process.env.HOST,
},
nitroApp.fetch
);
}
67 changes: 67 additions & 0 deletions test/presets/bunny.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { promises as fsp } from "node:fs";
import { execa, execaCommandSync } from "execa";
import { getRandomPort, waitForPort } from "get-port-please";
import { resolve } from "pathe";
import { describe, expect, it } from "vitest";
import { setupTest, testNitro } from "../tests.ts";

const hasDeno =
execaCommandSync("deno --version", { stdio: "ignore", reject: false }).exitCode === 0;

describe.runIf(hasDeno)("nitro:preset:bunny", async () => {
const ctx = await setupTest("bunny-edge-scripting");

testNitro(ctx, async () => {
const port = await getRandomPort();
const p = execa("deno", ["run", "-A", "./bunny-edge-scripting.mjs"], {
cwd: ctx.outDir,
stdio: "ignore",
env: {
NITRO_PORT: String(port),
NITRO_HOST: "127.0.0.1",
},
});
ctx.server = {
url: `http://127.0.0.1:${port}`,
close: () => p.kill(),
} as any;
await waitForPort(port, { delay: 1000, retries: 20, host: "127.0.0.1" });
return async ({ url, ...opts }) => {
const res = await ctx.fetch(url, opts);
return res;
};
});

it("should generate the bunny-edge-scripting.mjs file", async () => {
const serverFiles = await fsp.readdir(resolve(ctx.outDir));
expect(serverFiles).toContain("bunny-edge-scripting.mjs");
});

it("should not have a separate server directory", async () => {
const serverFiles = await fsp.readdir(resolve(ctx.outDir));
expect(serverFiles).not.toContain("server");
});

it("should not have a public directory (assets should be inlined)", async () => {
const serverFiles = await fsp.readdir(resolve(ctx.outDir));
if (ctx.nitro?.options.serveStatic === "inline") {
expect(serverFiles).not.toContain("public");
} else {
expect(serverFiles).toContain("public");
}
});

it("should have minified output", async () => {
const entry = await fsp.readFile(resolve(ctx.outDir, "bunny-edge-scripting.mjs"), "utf8");
// Check file is actually minified - should have very few newlines relative to size
const newlineCount = (entry.match(/\n/g) || []).length;
const ratio = entry.length / Math.max(1, newlineCount);
// Fixture is small, so we expect a high ratio of characters to newlines in minified code
expect(ratio).toBeGreaterThan(500);
});

it("should contain the Bunny.v1.serve call", async () => {
const entry = await fsp.readFile(resolve(ctx.outDir, "bunny-edge-scripting.mjs"), "utf8");
expect(entry).toContain("Bunny");
});
});
2 changes: 2 additions & 0 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export async function setupTest(
preset,
isDev: preset === "nitro-dev",
isWorker: [
"bunny-edge-scripting",
"cloudflare-worker",
"cloudflare-module",
"cloudflare-module-legacy",
Expand Down Expand Up @@ -641,6 +642,7 @@ export function testNitro(
// TODO: Investigate
ctx.preset === "bun" ||
ctx.preset === "deno-server" ||
ctx.preset === "bunny-edge-scripting" ||
ctx.preset === "nitro-dev"
)("sourcemap works", async () => {
const { data } = await callHandler({ url: "/error-stack" });
Expand Down
Loading