UNPKG

svelte-adapter-appengine

Version:

Adapter for Svelte that integrates with Google Cloud Appengine

209 lines (185 loc) 6.02 kB
import { copyFileSync, existsSync, readFileSync, writeFileSync } from "node:fs"; import { join, posix } from "node:path"; import { fileURLToPath } from "node:url"; import YAML from "yaml"; import esbuild from "esbuild"; const files = fileURLToPath(new URL("files", import.meta.url)); /** @type {import('.').default} */ export default function entrypoint(options = {}) { const { out = "build", external = [], useCloudLogging = false, useCloudTracing = false, dependencies = {}, nodejsRuntime = 22, } = options; return { name: "svelte-adapter-appengine", async adapt(builder) { const temporary = builder.getBuildDirectory("svelte-adapter-appengine"); builder.rimraf(out); builder.rimraf(temporary); builder.log.minor("Copying assets"); builder.writePrerendered( `${out}/storage${builder.config.kit.paths.base}`, ); const clientFiles = builder.writeClient( `${out}/storage${builder.config.kit.paths.base}`, ); const relativePath = posix.relative( temporary, builder.getServerDirectory(), ); // Copy server handler builder.copy(files, temporary, { replace: { SERVER: `${relativePath}/index.js`, MANIFEST: "./manifest.js", USE_CLOUD_LOGGING: useCloudLogging, USE_CLOUD_TRACING: useCloudTracing, }, }); writeFileSync( `${temporary}/manifest.js`, `export const manifest = ${builder.generateManifest({ relativePath, })};\n`, ); // Add dependencies for logging and tracing external.push( "@google-cloud/trace-agent", "@google-cloud/logging-bunyan", "bunyan", ); if (useCloudTracing) { dependencies["@google-cloud/trace-agent"] = "^7.0.0"; } if (useCloudLogging) { dependencies["@google-cloud/logging-bunyan"] = "^4.0.0"; dependencies.bunyan = "^1.8.0"; } await esbuild.build({ entryPoints: [`${temporary}/entry.js`], outfile: `${out}/index.js`, target: `node${nodejsRuntime}`, bundle: true, platform: "node", format: "cjs", sourcemap: "linked", external, }); writeFileSync( `${out}/package.json`, JSON.stringify( { type: "commonjs", dependencies, }, null, 2, ), ); const prerenderedPages = Array.from( builder.prerendered.pages, ([src, page]) => ({ url: `${src}/?$`, // eslint-disable-next-line camelcase static_files: join("storage", page.file).replaceAll("\\", "/"), upload: join("storage", page.file).replaceAll("\\", "/"), secure: "always", }), ); const prerenderedAssets = Array.from( builder.prerendered.assets, ([path, { type }]) => ({ url: path, // eslint-disable-next-line camelcase static_files: join("storage", path).replaceAll("\\", "/"), upload: join("storage", path).replaceAll("\\", "/"), secure: "always", // eslint-disable-next-line camelcase mime_type: type, }), ); const prerenderedRedirects = Array.from( builder.prerendered.redirects, ([src]) => ({ url: src, secure: "always", script: "auto", }), ); // Add yaml entries for all files outside _app directory, such as favicons const additionalClientAssets = clientFiles .filter((file) => !file.startsWith("_app/")) .map((file) => ({ url: `/${file}`, // eslint-disable-next-line camelcase static_files: join("storage", file).replaceAll("\\", "/"), upload: join("storage", file).replaceAll("\\", "/"), secure: "always", })); // Load existing app.yaml if it exists let yaml = {}; if (existsSync("app.yaml")) { builder.log.minor("Existing app.yaml found"); yaml = YAML.parse(readFileSync("app.yaml").toString()); } const serverRoutes = [ ...(yaml.handlers ?? []), ...prerenderedPages, ...prerenderedRedirects, ...prerenderedAssets, ...additionalClientAssets, { url: `/${builder.config.kit.appDir}/immutable/`, // eslint-disable-next-line camelcase static_dir: `storage/${builder.config.kit.appDir}/immutable`, expiration: "30d 0h", secure: "always", }, { url: `/${builder.config.kit.appDir}/`, // eslint-disable-next-line camelcase static_dir: `storage/${builder.config.kit.appDir}`, secure: "always", }, { url: "/.*", secure: "always", script: "auto", }, ]; if (serverRoutes.length > 99) { builder.log.error( `You've exceeded the maximum number of routes (99) allowed in AppEngine app.yaml, and you have ${serverRoutes.length} routes.`, ); builder.log.error( "This often happens when you have a lot of static assets.", ); builder.log.error( "If possible, use vites asset importing instead: https://kit.svelte.dev/docs/assets", ); } writeFileSync( join(out, "app.yaml"), YAML.stringify({ ...yaml, runtime: `nodejs${nodejsRuntime}`, entrypoint: "node index.js", // eslint-disable-next-line camelcase default_expiration: "0h", handlers: serverRoutes, }), ); // Copy cron.yaml if it exists if (existsSync("cron.yaml")) { copyFileSync("cron.yaml", join(out, "cron.yaml")); } builder.log.success( `To deploy, run "gcloud app deploy --project <CLOUD_PROJECT_ID> ${out}/app.yaml"`, ); }, }; }