UNPKG

@ptkdev/sveltekit-cordova-adapter

Version:

Adapter for SvelteKit apps that prerenders your entire site as a collection of static files for use with Cordova or Ionic Capacitor (android/ios)

197 lines (162 loc) 6.58 kB
/* eslint-disable @typescript-eslint/ban-ts-comment */ import path from "path"; import glob from "tiny-glob"; import replace from "replace-in-file"; import { platforms } from "./platforms.js"; /** @type {import('.').default} */ export default function (options) { return { name: "@ptkdev/sveltekit-cordova-adapter", async adapt(builder) { if (!options?.fallback) { /** @type {string[]} */ const dynamic_routes = []; // this is a bit of a hack — it allows us to know whether there are dynamic // (i.e. prerender = false/'auto') routes without having dedicated API // surface area for it builder.createEntries((route) => { dynamic_routes.push(route.id); return { id: "", filter: () => false, // eslint-disable-next-line @typescript-eslint/no-empty-function complete: () => {}, }; }); if (dynamic_routes.length > 0 && options?.strict !== false) { const prefix = path.relative(".", builder.config.kit.files.routes); const has_param_routes = dynamic_routes.some((route) => route.includes("[")); const config_option = has_param_routes || JSON.stringify(builder.config.kit.prerender.entries) !== '["*"]' ? ` - adjust the \`prerender.entries\` config option ${ has_param_routes ? "(routes with parameters are not part of entry points by default)" : "" } — see https://kit.svelte.dev/docs/configuration#prerender for more info.` : ""; builder.log.error( `@ptkdev/sveltekit-cordova-adapter: all routes must be fully prerenderable, but found the following routes that are dynamic: ${dynamic_routes.map((id) => ` - ${path.posix.join(prefix, id)}`).join("\n")} You have the following options: - set the \`fallback\` option — see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode for more info. - add \`export const prerender = true\` to your root \`+layout.js/.ts\` or \`+layout.server.js/.ts\` file. This will try to prerender all pages. - add \`export const prerender = true\` to any \`+server.js/ts\` files that are not fetched by page \`load\` functions. ${config_option} - pass \`strict: false\` to \`adapter-static\` to ignore this error. Only do this if you are sure you don't need the routes in question in your final app, as they will be unavailable. See https://github.com/sveltejs/kit/tree/master/packages/adapter-static#strict for more info. If this doesn't help, you may need to use a different adapter. @ptkdev/sveltekit-cordova-adapter can only be used for sites that don't need a server for dynamic rendering, and can run on just a static file server. See https://kit.svelte.dev/docs/page-options#prerender for more details`, ); throw new Error("Encountered dynamic routes"); } } const platform = platforms.find((platform) => platform.test()); if (platform) { if (options) { builder.log.warn( `Detected ${platform.name}. Please remove adapter-static options to enable zero-config mode`, ); } else { builder.log.info(`Detected ${platform.name}, using zero-config mode`); } } const { pages = "build", assets = pages, fallback, precompress, } = options ?? platform?.defaults ?? /** @type {import('./index').AdapterOptions} */ ({}); builder.rimraf(assets); builder.rimraf(pages); builder.writeClient(assets); builder.writePrerendered(pages); const HTML_pages = await glob("**/*.html", { cwd: pages, dot: true, absolute: true, filesOnly: true, }); HTML_pages.forEach(async (path) => { let href = path.split("/").pop(); let regex_input = new RegExp(`href="/${href.replace(".html", "")}"`, "g"); let regex_replace = `href="${`./${href}`}"`; if (href === "index.html") { regex_input = new RegExp(`href="/"`, "g"); regex_replace = `href="./index.html"`; } await replace.sync({ files: [`${pages}/**/*.html`], // @ts-ignore processor: (input) => input.replace(regex_input, regex_replace), }); }); const HTML_assets = await glob("_app/**/*", { cwd: pages, dot: true, absolute: false, filesOnly: true, }); HTML_assets.forEach(async () => { let regex_input = new RegExp(`([^.])(/_app/immutable)`, "g"); await replace.sync({ files: [`${pages}/**/*`], // @ts-ignore processor: (input) => input.replace(regex_input, "$1.$2"), }); }); let regex_input = new RegExp(`</body>`, "g"); let regex_replace = `<script src="cordova.js"></script></body>`; await replace.sync({ files: [`${pages}/**/*.html`], // @ts-ignore processor: (input) => input.replace(regex_input, regex_replace), }); regex_input = new RegExp(`http-equiv="content-security-policy" content=""`, "g"); const policy = ""; regex_replace = `http-equiv="content-security-policy" content="${ options?.policy ? options.policy : policy }"`; await replace.sync({ files: [`${pages}/**/*.html`], // @ts-ignore processor: (input) => input.replace(regex_input, regex_replace), }); regex_input = new RegExp(`name="viewport" content="width=device-width"`, "g"); const viewport = "width=device-width, initial-scale=1.0, viewport-fit=cover"; regex_replace = `name="viewport" content="${options?.viewport ? options.viewport : viewport}"`; await replace.sync({ files: [`${pages}/**/*.html`], // @ts-ignore processor: (input) => input.replace(regex_input, regex_replace), }); options?.safearea === undefined ? (options.safearea = true) : ""; if (options?.safearea) { regex_input = new RegExp(`</head>`, "g"); regex_replace = `<style>body { padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }</style></head>`; await replace.sync({ files: [`${pages}/**/*.html`], // @ts-ignore processor: (input) => input.replace(regex_input, regex_replace), }); } if (fallback) { builder.generateFallback(path.join(pages, fallback)); } if (precompress) { builder.log.minor("Compressing assets and pages"); if (pages === assets) { await builder.compress(assets); } else { await Promise.all([builder.compress(assets), builder.compress(pages)]); } } if (pages === assets) { builder.log(`Wrote site to "${pages}"`); } else { builder.log(`Wrote pages to "${pages}" and assets to "${assets}"`); } if (!options) { platform?.done(builder); } }, }; }