|
| 1 | +/* eslint-disable @typescript-eslint/ban-ts-comment */ |
| 2 | +import path from "path"; |
| 3 | +import glob from "tiny-glob"; |
| 4 | +import replace from "replace-in-file"; |
| 5 | +import { platforms } from "./platforms.js"; |
| 6 | + |
| 7 | +/** @type {import('.').default} */ |
| 8 | +export default function (options) { |
| 9 | + return { |
| 10 | + name: "@ptkdev/sveltekit-cordova-adapter", |
| 11 | + |
| 12 | + async adapt(builder) { |
| 13 | + if (!options?.fallback) { |
| 14 | + /** @type {string[]} */ |
| 15 | + const dynamic_routes = []; |
| 16 | + |
| 17 | + // this is a bit of a hack — it allows us to know whether there are dynamic |
| 18 | + // (i.e. prerender = false/'auto') routes without having dedicated API |
| 19 | + // surface area for it |
| 20 | + builder.createEntries((route) => { |
| 21 | + dynamic_routes.push(route.id); |
| 22 | + |
| 23 | + return { |
| 24 | + id: "", |
| 25 | + filter: () => false, |
| 26 | + // eslint-disable-next-line @typescript-eslint/no-empty-function |
| 27 | + complete: () => {}, |
| 28 | + }; |
| 29 | + }); |
| 30 | + |
| 31 | + if (dynamic_routes.length > 0 && options?.strict !== false) { |
| 32 | + const prefix = path.relative(".", builder.config.kit.files.routes); |
| 33 | + const has_param_routes = dynamic_routes.some((route) => route.includes("[")); |
| 34 | + const config_option = |
| 35 | + has_param_routes || JSON.stringify(builder.config.kit.prerender.entries) !== '["*"]' |
| 36 | + ? ` - adjust the \`prerender.entries\` config option ${ |
| 37 | + has_param_routes |
| 38 | + ? "(routes with parameters are not part of entry points by default)" |
| 39 | + : "" |
| 40 | + } — see https://kit.svelte.dev/docs/configuration#prerender for more info.` |
| 41 | + : ""; |
| 42 | + |
| 43 | + builder.log.error( |
| 44 | + `@ptkdev/sveltekit-cordova-adapter: all routes must be fully prerenderable, but found the following routes that are dynamic: |
| 45 | +${dynamic_routes.map((id) => ` - ${path.posix.join(prefix, id)}`).join("\n")} |
| 46 | +
|
| 47 | +You have the following options: |
| 48 | + - set the \`fallback\` option — see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode for more info. |
| 49 | + - add \`export const prerender = true\` to your root \`+layout.js/.ts\` or \`+layout.server.js/.ts\` file. This will try to prerender all pages. |
| 50 | + - add \`export const prerender = true\` to any \`+server.js/ts\` files that are not fetched by page \`load\` functions. |
| 51 | +${config_option} |
| 52 | + - 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. |
| 53 | +
|
| 54 | +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. |
| 55 | +See https://kit.svelte.dev/docs/page-options#prerender for more details`, |
| 56 | + ); |
| 57 | + throw new Error("Encountered dynamic routes"); |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + const platform = platforms.find((platform) => platform.test()); |
| 62 | + |
| 63 | + if (platform) { |
| 64 | + if (options) { |
| 65 | + builder.log.warn( |
| 66 | + `Detected ${platform.name}. Please remove adapter-static options to enable zero-config mode`, |
| 67 | + ); |
| 68 | + } else { |
| 69 | + builder.log.info(`Detected ${platform.name}, using zero-config mode`); |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + const { |
| 74 | + pages = "build", |
| 75 | + assets = pages, |
| 76 | + fallback, |
| 77 | + precompress, |
| 78 | + } = options ?? platform?.defaults ?? /** @type {import('./index').AdapterOptions} */ ({}); |
| 79 | + |
| 80 | + builder.rimraf(assets); |
| 81 | + builder.rimraf(pages); |
| 82 | + |
| 83 | + builder.writeClient(assets); |
| 84 | + builder.writePrerendered(pages); |
| 85 | + |
| 86 | + const HTML_pages = await glob("**/*.html", { |
| 87 | + cwd: pages, |
| 88 | + dot: true, |
| 89 | + absolute: true, |
| 90 | + filesOnly: true, |
| 91 | + }); |
| 92 | + |
| 93 | + HTML_pages.forEach(async (path) => { |
| 94 | + let href = path.split("/").pop(); |
| 95 | + |
| 96 | + let regex_input = new RegExp(`href="/${href.replace(".html", "")}"`, "g"); |
| 97 | + let regex_replace = `href="${`./${href}`}"`; |
| 98 | + |
| 99 | + if (href === "index.html") { |
| 100 | + regex_input = new RegExp(`href="/"`, "g"); |
| 101 | + regex_replace = `href="./index.html"`; |
| 102 | + } |
| 103 | + |
| 104 | + await replace.sync({ |
| 105 | + files: [`${pages}/**/*.html`], |
| 106 | + // @ts-ignore |
| 107 | + processor: (input) => input.replace(regex_input, regex_replace), |
| 108 | + }); |
| 109 | + }); |
| 110 | + |
| 111 | + const HTML_assets = await glob("_app/**/*", { |
| 112 | + cwd: pages, |
| 113 | + dot: true, |
| 114 | + absolute: false, |
| 115 | + filesOnly: true, |
| 116 | + }); |
| 117 | + |
| 118 | + HTML_assets.forEach(async (path) => { |
| 119 | + let regex_input = new RegExp(`[^.](/_app/immutable)`, "g"); |
| 120 | + let regex_replace = `./_app/immutable`; |
| 121 | + |
| 122 | + await replace.sync({ |
| 123 | + files: [`${pages}/**/*`], |
| 124 | + // @ts-ignore |
| 125 | + processor: (input) => input.replace(regex_input, regex_replace), |
| 126 | + }); |
| 127 | + }); |
| 128 | + |
| 129 | + let regex_input = new RegExp(`</body>`, "g"); |
| 130 | + let regex_replace = `<script src="cordova.js"></script></body>`; |
| 131 | + |
| 132 | + await replace.sync({ |
| 133 | + files: [`${pages}/**/*.html`], |
| 134 | + // @ts-ignore |
| 135 | + processor: (input) => input.replace(regex_input, regex_replace), |
| 136 | + }); |
| 137 | + |
| 138 | + regex_input = new RegExp(`http-equiv="content-security-policy" content=""`, "g"); |
| 139 | + const policy = |
| 140 | + "default-src 'self' data: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;"; |
| 141 | + regex_replace = `http-equiv="content-security-policy" content="${ |
| 142 | + options?.policy ? options.policy : policy |
| 143 | + }"`; |
| 144 | + |
| 145 | + await replace.sync({ |
| 146 | + files: [`${pages}/**/*.html`], |
| 147 | + // @ts-ignore |
| 148 | + processor: (input) => input.replace(regex_input, regex_replace), |
| 149 | + }); |
| 150 | + |
| 151 | + regex_input = new RegExp(`name="viewport" content="width=device-width"`, "g"); |
| 152 | + const viewport = "width=device-width, initial-scale=1.0, viewport-fit=cover"; |
| 153 | + regex_replace = `name="viewport" content="${options?.viewport ? options.viewport : viewport}"`; |
| 154 | + |
| 155 | + await replace.sync({ |
| 156 | + files: [`${pages}/**/*.html`], |
| 157 | + // @ts-ignore |
| 158 | + processor: (input) => input.replace(regex_input, regex_replace), |
| 159 | + }); |
| 160 | + |
| 161 | + options?.safearea ?? true; |
| 162 | + |
| 163 | + if (options?.safearea) { |
| 164 | + regex_input = new RegExp(`</head>`, "g"); |
| 165 | + 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>`; |
| 166 | + |
| 167 | + await replace.sync({ |
| 168 | + files: [`${pages}/**/*.html`], |
| 169 | + // @ts-ignore |
| 170 | + processor: (input) => input.replace(regex_input, regex_replace), |
| 171 | + }); |
| 172 | + } |
| 173 | + |
| 174 | + if (fallback) { |
| 175 | + builder.generateFallback(path.join(pages, fallback)); |
| 176 | + } |
| 177 | + |
| 178 | + if (precompress) { |
| 179 | + builder.log.minor("Compressing assets and pages"); |
| 180 | + if (pages === assets) { |
| 181 | + await builder.compress(assets); |
| 182 | + } else { |
| 183 | + await Promise.all([builder.compress(assets), builder.compress(pages)]); |
| 184 | + } |
| 185 | + } |
| 186 | + |
| 187 | + if (pages === assets) { |
| 188 | + builder.log(`Wrote site to "${pages}"`); |
| 189 | + } else { |
| 190 | + builder.log(`Wrote pages to "${pages}" and assets to "${assets}"`); |
| 191 | + } |
| 192 | + |
| 193 | + if (!options) { |
| 194 | + platform?.done(builder); |
| 195 | + } |
| 196 | + }, |
| 197 | + }; |
| 198 | +} |
0 commit comments