feat: init
This commit is contained in:
289
node_modules/nitropack/dist/presets/cloudflare/utils.mjs
generated
vendored
Normal file
289
node_modules/nitropack/dist/presets/cloudflare/utils.mjs
generated
vendored
Normal file
@@ -0,0 +1,289 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { relative, dirname, extname } from "node:path";
|
||||
import { writeFile } from "nitropack/kit";
|
||||
import { parseTOML, parseJSONC } from "confbox";
|
||||
import { readGitConfig, readPackageJSON, findNearestFile } from "pkg-types";
|
||||
import { defu } from "defu";
|
||||
import { globby } from "globby";
|
||||
import { provider } from "std-env";
|
||||
import { join, resolve } from "pathe";
|
||||
import {
|
||||
joinURL,
|
||||
hasProtocol,
|
||||
withLeadingSlash,
|
||||
withTrailingSlash,
|
||||
withoutLeadingSlash
|
||||
} from "ufo";
|
||||
import {
|
||||
workerdHybridNodeCompatPlugin,
|
||||
unenvWorkerdWithNodeCompat
|
||||
} from "../_unenv/preset-workerd.mjs";
|
||||
export async function writeCFRoutes(nitro) {
|
||||
const _cfPagesConfig = nitro.options.cloudflare?.pages || {};
|
||||
const routes = {
|
||||
version: _cfPagesConfig.routes?.version || 1,
|
||||
include: _cfPagesConfig.routes?.include || ["/*"],
|
||||
exclude: _cfPagesConfig.routes?.exclude || []
|
||||
};
|
||||
const writeRoutes = () => writeFile(
|
||||
resolve(nitro.options.output.dir, "_routes.json"),
|
||||
JSON.stringify(routes, void 0, 2),
|
||||
true
|
||||
);
|
||||
if (_cfPagesConfig.defaultRoutes === false) {
|
||||
await writeRoutes();
|
||||
return;
|
||||
}
|
||||
const explicitPublicAssets = nitro.options.publicAssets.filter(
|
||||
(dir, index, array) => {
|
||||
if (dir.fallthrough || !dir.baseURL) {
|
||||
return false;
|
||||
}
|
||||
const normalizedBase = withoutLeadingSlash(dir.baseURL);
|
||||
return !array.some(
|
||||
(otherDir, otherIndex) => otherIndex !== index && normalizedBase.startsWith(
|
||||
withoutLeadingSlash(withTrailingSlash(otherDir.baseURL))
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
routes.exclude.push(
|
||||
...explicitPublicAssets.map((asset) => joinURL(nitro.options.baseURL, asset.baseURL || "/", "*")).sort(comparePaths)
|
||||
);
|
||||
const publicAssetFiles = await globby("**", {
|
||||
cwd: nitro.options.output.dir,
|
||||
absolute: false,
|
||||
dot: true,
|
||||
ignore: [
|
||||
"_worker.js",
|
||||
"_worker.js.map",
|
||||
"nitro.json",
|
||||
...routes.exclude.map(
|
||||
(path) => withoutLeadingSlash(path.replace(/\/\*$/, "/**"))
|
||||
)
|
||||
]
|
||||
});
|
||||
routes.exclude.push(
|
||||
...publicAssetFiles.map(
|
||||
(i) => withLeadingSlash(i).replace(/\/index\.html$/, "").replace(/\.html$/, "") || "/"
|
||||
).sort(comparePaths)
|
||||
);
|
||||
routes.exclude.splice(100 - routes.include.length);
|
||||
await writeRoutes();
|
||||
}
|
||||
function comparePaths(a, b) {
|
||||
return a.split("/").length - b.split("/").length || a.localeCompare(b);
|
||||
}
|
||||
export async function writeCFHeaders(nitro, outdir) {
|
||||
const headersPath = join(
|
||||
outdir === "public" ? nitro.options.output.publicDir : nitro.options.output.dir,
|
||||
"_headers"
|
||||
);
|
||||
const contents = [];
|
||||
const rules = Object.entries(nitro.options.routeRules).sort(
|
||||
(a, b) => b[0].split(/\/(?!\*)/).length - a[0].split(/\/(?!\*)/).length
|
||||
);
|
||||
for (const [path, routeRules] of rules.filter(
|
||||
([_, routeRules2]) => routeRules2.headers
|
||||
)) {
|
||||
const headers = [
|
||||
joinURL(nitro.options.baseURL, path.replace("/**", "/*")),
|
||||
...Object.entries({ ...routeRules.headers }).map(
|
||||
([header, value]) => ` ${header}: ${value}`
|
||||
)
|
||||
].join("\n");
|
||||
contents.push(headers);
|
||||
}
|
||||
if (existsSync(headersPath)) {
|
||||
const currentHeaders = await readFile(headersPath, "utf8");
|
||||
if (/^\/\* /m.test(currentHeaders)) {
|
||||
nitro.logger.info(
|
||||
"Not adding Nitro fallback to `_headers` (as an existing fallback was found)."
|
||||
);
|
||||
return;
|
||||
}
|
||||
nitro.logger.info(
|
||||
"Adding Nitro fallback to `_headers` to handle all unmatched routes."
|
||||
);
|
||||
contents.unshift(currentHeaders);
|
||||
}
|
||||
await writeFile(headersPath, contents.join("\n"), true);
|
||||
}
|
||||
export async function writeCFPagesRedirects(nitro) {
|
||||
const redirectsPath = join(nitro.options.output.dir, "_redirects");
|
||||
const staticFallback = existsSync(
|
||||
join(nitro.options.output.publicDir, "404.html")
|
||||
) ? `${joinURL(nitro.options.baseURL, "/*")} ${joinURL(nitro.options.baseURL, "/404.html")} 404` : "";
|
||||
const contents = [staticFallback];
|
||||
const rules = Object.entries(nitro.options.routeRules).sort(
|
||||
(a, b) => a[0].split(/\/(?!\*)/).length - b[0].split(/\/(?!\*)/).length
|
||||
);
|
||||
for (const [key, routeRules] of rules.filter(
|
||||
([_, routeRules2]) => routeRules2.redirect
|
||||
)) {
|
||||
const code = routeRules.redirect.statusCode;
|
||||
const from = joinURL(nitro.options.baseURL, key.replace("/**", "/*"));
|
||||
const to = hasProtocol(routeRules.redirect.to, { acceptRelative: true }) ? routeRules.redirect.to : joinURL(nitro.options.baseURL, routeRules.redirect.to);
|
||||
contents.unshift(`${from} ${to} ${code}`);
|
||||
}
|
||||
if (existsSync(redirectsPath)) {
|
||||
const currentRedirects = await readFile(redirectsPath, "utf8");
|
||||
if (/^\/\* /m.test(currentRedirects)) {
|
||||
nitro.logger.info(
|
||||
"Not adding Nitro fallback to `_redirects` (as an existing fallback was found)."
|
||||
);
|
||||
return;
|
||||
}
|
||||
nitro.logger.info(
|
||||
"Adding Nitro fallback to `_redirects` to handle all unmatched routes."
|
||||
);
|
||||
contents.unshift(currentRedirects);
|
||||
}
|
||||
await writeFile(redirectsPath, contents.join("\n"), true);
|
||||
}
|
||||
export async function enableNodeCompat(nitro) {
|
||||
nitro.options.cloudflare ??= {};
|
||||
if (nitro.options.cloudflare.deployConfig === void 0 && provider === "cloudflare_workers") {
|
||||
nitro.options.cloudflare.deployConfig = true;
|
||||
}
|
||||
if (nitro.options.cloudflare.nodeCompat === void 0) {
|
||||
const { config } = await readWranglerConfig(nitro);
|
||||
const userCompatibilityFlags = new Set(config?.compatibility_flags || []);
|
||||
if (userCompatibilityFlags.has("nodejs_compat") || userCompatibilityFlags.has("nodejs_compat_v2") || nitro.options.cloudflare.deployConfig) {
|
||||
nitro.options.cloudflare.nodeCompat = true;
|
||||
}
|
||||
}
|
||||
if (!nitro.options.cloudflare.nodeCompat) {
|
||||
if (nitro.options.cloudflare.nodeCompat === void 0) {
|
||||
nitro.logger.warn("[cloudflare] Node.js compatibility is not enabled.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
nitro.options.unenv.push(unenvWorkerdWithNodeCompat);
|
||||
nitro.options.rollupConfig.plugins ??= [];
|
||||
nitro.options.rollupConfig.plugins.push(
|
||||
workerdHybridNodeCompatPlugin
|
||||
);
|
||||
}
|
||||
const extensionParsers = {
|
||||
".json": JSON.parse,
|
||||
".jsonc": parseJSONC,
|
||||
".toml": parseTOML
|
||||
};
|
||||
async function readWranglerConfig(nitro) {
|
||||
const configPath = await findNearestFile(
|
||||
["wrangler.json", "wrangler.jsonc", "wrangler.toml"],
|
||||
{
|
||||
startingFrom: nitro.options.rootDir
|
||||
}
|
||||
).catch(() => void 0);
|
||||
if (!configPath) {
|
||||
return {};
|
||||
}
|
||||
const userConfigText = await readFile(configPath, "utf8");
|
||||
const parser = extensionParsers[extname(configPath)];
|
||||
if (!parser) {
|
||||
throw new Error(`Unsupported config file format: ${configPath}`);
|
||||
}
|
||||
const config = parser(userConfigText);
|
||||
return { configPath, config };
|
||||
}
|
||||
export async function writeWranglerConfig(nitro, cfTarget) {
|
||||
if (!nitro.options.cloudflare?.deployConfig) {
|
||||
return;
|
||||
}
|
||||
const wranglerConfigDir = nitro.options.output.serverDir;
|
||||
const wranglerConfigPath = join(wranglerConfigDir, "wrangler.json");
|
||||
const defaults = {};
|
||||
const overrides = {};
|
||||
defaults.compatibility_date = nitro.options.compatibilityDate.cloudflare || nitro.options.compatibilityDate.default;
|
||||
if (cfTarget === "pages") {
|
||||
overrides.pages_build_output_dir = relative(
|
||||
wranglerConfigDir,
|
||||
nitro.options.output.dir
|
||||
);
|
||||
} else {
|
||||
overrides.main = relative(
|
||||
wranglerConfigDir,
|
||||
join(nitro.options.output.serverDir, "index.mjs")
|
||||
);
|
||||
overrides.assets = {
|
||||
binding: "ASSETS",
|
||||
directory: relative(
|
||||
wranglerConfigDir,
|
||||
resolve(
|
||||
nitro.options.output.publicDir,
|
||||
"..".repeat(nitro.options.baseURL.split("/").filter(Boolean).length)
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
const { config: userConfig = {} } = await readWranglerConfig(nitro);
|
||||
const ctxConfig = nitro.options.cloudflare?.wrangler || {};
|
||||
for (const key in overrides) {
|
||||
if (key in userConfig || key in ctxConfig) {
|
||||
nitro.logger.warn(
|
||||
`[cloudflare] Wrangler config \`${key}\`${key in ctxConfig ? "set by config or modules" : ""} is overridden and will be ignored.`
|
||||
);
|
||||
}
|
||||
}
|
||||
const wranglerConfig = defu(
|
||||
overrides,
|
||||
ctxConfig,
|
||||
userConfig,
|
||||
defaults
|
||||
);
|
||||
if (!wranglerConfig.name) {
|
||||
wranglerConfig.name = await generateWorkerName(nitro);
|
||||
nitro.logger.info(
|
||||
`Using auto generated worker name: \`${wranglerConfig.name}\``
|
||||
);
|
||||
}
|
||||
const compatFlags = new Set(wranglerConfig.compatibility_flags || []);
|
||||
if (nitro.options.cloudflare?.nodeCompat) {
|
||||
if (compatFlags.has("nodejs_compat_v2") && compatFlags.has("no_nodejs_compat_v2")) {
|
||||
nitro.logger.warn(
|
||||
"[cloudflare] Wrangler config `compatibility_flags` contains both `nodejs_compat_v2` and `no_nodejs_compat_v2`. Ignoring `nodejs_compat_v2`."
|
||||
);
|
||||
compatFlags.delete("nodejs_compat_v2");
|
||||
}
|
||||
if (compatFlags.has("nodejs_compat_v2")) {
|
||||
nitro.logger.warn(
|
||||
"[cloudflare] Please consider replacing `nodejs_compat_v2` with `nodejs_compat` in your `compatibility_flags` or USE IT AT YOUR OWN RISK as it can cause issues with nitro."
|
||||
);
|
||||
} else {
|
||||
compatFlags.add("nodejs_compat");
|
||||
compatFlags.add("no_nodejs_compat_v2");
|
||||
}
|
||||
}
|
||||
wranglerConfig.compatibility_flags = [...compatFlags];
|
||||
await writeFile(
|
||||
wranglerConfigPath,
|
||||
JSON.stringify(wranglerConfig, null, 2),
|
||||
true
|
||||
);
|
||||
const configPath = join(
|
||||
nitro.options.rootDir,
|
||||
".wrangler/deploy/config.json"
|
||||
);
|
||||
await writeFile(
|
||||
configPath,
|
||||
JSON.stringify({
|
||||
configPath: relative(dirname(configPath), wranglerConfigPath)
|
||||
}),
|
||||
true
|
||||
);
|
||||
}
|
||||
async function generateWorkerName(nitro) {
|
||||
const gitConfig = await readGitConfig(nitro.options.rootDir).catch(
|
||||
() => void 0
|
||||
);
|
||||
const gitRepo = gitConfig?.remote?.origin?.url?.replace(/\.git$/, "").match(/[/:]([^/]+\/[^/]+)$/)?.[1];
|
||||
const pkgJSON = await readPackageJSON(nitro.options.rootDir).catch(
|
||||
() => void 0
|
||||
);
|
||||
const pkgName = pkgJSON?.name;
|
||||
const subpath = relative(nitro.options.workspaceDir, nitro.options.rootDir);
|
||||
return `${gitRepo || pkgName}/${subpath}`.toLowerCase().replace(/[^a-zA-Z0-9-]/g, "-").replace(/-$/, "");
|
||||
}
|
||||
Reference in New Issue
Block a user