Skip to content

Commit

Permalink
feat(cloudflare-pages): rewrite with module syntax (#1004)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 authored Mar 3, 2023
1 parent c4fcbb1 commit c578df8
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 194 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ jobs:
- run: pnpm test:types
- run: pnpm build
- run: pnpm vitest --coverage
env:
NODE_OPTIONS: --experimental-vm-modules
- uses: codecov/codecov-action@v3
- name: Release Edge
if: |
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ package-lock.json
# Generated dirs
dist
.nuxt
.nuxt-*
.output
.gen
.tmp
nuxt.d.ts

# Junit reports
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"prepack": "pnpm build",
"release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
"stub": "unbuild --stub",
"test": "pnpm lint && vitest run --silent",
"vitest-es": "NODE_OPTIONS=--experimental-vm-modules vitest",
"test": "pnpm lint && pnpm vitest-es run --silent",
"test:types": "tsc --noEmit && pnpm test:fixture:types",
"test:fixture:types": "pnpm stub && jiti ./test/scripts/gen-fixture-types.ts && cd test/fixture && tsc --noEmit"
},
Expand Down Expand Up @@ -106,6 +107,7 @@
"unstorage": "^1.2.0"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20230228.0",
"@types/aws-lambda": "^8.10.111",
"@types/etag": "^1.8.1",
"@types/fs-extra": "^11.0.1",
Expand All @@ -124,6 +126,7 @@
"prettier": "^2.8.4",
"typescript": "^4.9.5",
"unbuild": "^1.1.2",
"undici": "^5.20.0",
"vitest": "^0.29.2"
},
"packageManager": "pnpm@7.28.0",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 95 additions & 0 deletions src/presets/cloudflare-pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { promises as fsp } from "node:fs";
import { resolve } from "pathe";
import { joinURL, withLeadingSlash, withoutLeadingSlash } from "ufo";
import { globby } from "globby";
import { defineNitroPreset } from "../preset";
import type { Nitro } from "../types";

export const cloudflarePages = defineNitroPreset({
extends: "cloudflare",
entry: "#internal/nitro/entries/cloudflare-pages",
commands: {
preview: "npx wrangler pages dev ./",
deploy: "npx wrangler pages publish ./",
},
output: {
dir: "{{ rootDir }}/dist",
publicDir: "{{ output.dir }}",
serverDir: "{{ output.dir }}",
},
alias: {
// Hotfix: Cloudflare appends /index.html if mime is not found and things like ico are not in standard lite.js!
// https://github.com/unjs/nitro/pull/933
_mime: "mime/index.js",
},
rollupConfig: {
output: {
entryFileNames: "_worker.js",
format: "esm",
},
},
hooks: {
async compiled(nitro: Nitro) {
await writeCFRoutes(nitro);
},
},
});

/**
* https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes
*/
interface CloudflarePagesRoutes {
version: 1;
include: string[];
exclude: string[];
}

async function writeCFRoutes(nitro: Nitro) {
const routes: CloudflarePagesRoutes = {
version: 1,
include: ["/*"],
exclude: [],
};

// Exclude public assets from hitting the worker
const explicitPublicAssets = nitro.options.publicAssets.filter(
(i) => !i.fallthrough
);

// Explicit prefixes
routes.exclude.push(
...explicitPublicAssets
.map((dir) => joinURL(dir.baseURL, "*"))
.sort(comparePaths)
);

// Unprefixed assets
const publicAssetFiles = await globby("**", {
cwd: nitro.options.output.publicDir,
absolute: false,
dot: true,
ignore: [
"_worker.js",
"_worker.js.map",
"nitro.json",
...explicitPublicAssets.map((dir) =>
withoutLeadingSlash(joinURL(dir.baseURL, "**"))
),
],
});
routes.exclude.push(
...publicAssetFiles.map((i) => withLeadingSlash(i)).sort(comparePaths)
);

// Only allow 100 rules in total (include + exclude)
routes.exclude.splice(100 - routes.include.length);

await fsp.writeFile(
resolve(nitro.options.output.publicDir, "_routes.json"),
JSON.stringify(routes, undefined, 2)
);
}

function comparePaths(a: string, b: string) {
return a.split("/").length - b.split("/").length || a.localeCompare(b);
}
94 changes: 1 addition & 93 deletions src/presets/cloudflare.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { join, resolve } from "pathe";
import fse from "fs-extra";
import { joinURL, withLeadingSlash, withoutLeadingSlash } from "ufo";
import { globby } from "globby";
import { resolve } from "pathe";
import { writeFile } from "../utils";
import { defineNitroPreset } from "../preset";
import type { Nitro } from "../types";
Expand All @@ -26,92 +23,3 @@ export const cloudflare = defineNitroPreset({
},
},
});

/**
* https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes
*/
interface CloudflarePagesRoutes {
version: 1;
include: string[];
exclude: string[];
}

export const cloudflarePages = defineNitroPreset({
extends: "cloudflare",
entry: "#internal/nitro/entries/cloudflare-pages",
commands: {
preview: "npx wrangler pages dev .output/public",
deploy: "npx wrangler pages publish .output/public",
},
output: {
serverDir: "{{ rootDir }}/functions",
},
alias: {
// Hotfix: Cloudflare appends /index.html if mime is not found and things like ico are not in standard lite.js!
// https://github.com/unjs/nitro/pull/933
_mime: "mime/index.js",
},
rollupConfig: {
output: {
entryFileNames: "path.js",
format: "esm",
},
},
hooks: {
async compiled(nitro: Nitro) {
await fse.move(
resolve(nitro.options.output.serverDir, "path.js"),
resolve(nitro.options.output.serverDir, "[[path]].js")
);
await fse.move(
resolve(nitro.options.output.serverDir, "path.js.map"),
resolve(nitro.options.output.serverDir, "[[path]].js.map")
);

const routes: CloudflarePagesRoutes = {
version: 1,
include: ["/*"],
exclude: [],
};

// Exclude public assets from hitting the worker
const explicitPublicAssets = nitro.options.publicAssets.filter(
(i) => !i.fallthrough
);

// Explicit prefixes
routes.exclude.push(
...explicitPublicAssets
.map((dir) => joinURL(dir.baseURL, "*"))
.sort(comparePaths)
);

// Unprefixed assets
const publicAssetFiles = await globby("**", {
cwd: nitro.options.output.publicDir,
absolute: false,
dot: true,
ignore: [
...explicitPublicAssets.map((dir) =>
withoutLeadingSlash(joinURL(dir.baseURL, "**"))
),
],
});
routes.exclude.push(
...publicAssetFiles.map((i) => withLeadingSlash(i)).sort(comparePaths)
);

// Only allow 100 rules in total (include + exclude)
routes.exclude.splice(100 - routes.include.length);

await fse.writeFile(
resolve(nitro.options.output.publicDir, "_routes.json"),
JSON.stringify(routes, undefined, 2)
);
},
},
});

function comparePaths(a: string, b: string) {
return a.split("/").length - b.split("/").length || a.localeCompare(b);
}
1 change: 1 addition & 0 deletions src/presets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from "./azure-functions";
export * from "./azure";
export * from "./base-worker";
export * from "./cloudflare";
export * from "./cloudflare-pages";
export * from "./deno";
export * from "./digital-ocean";
export * from "./firebase";
Expand Down
Loading

0 comments on commit c578df8

Please sign in to comment.