diff --git a/sites/svelte.dev/src/routes/docs.html/+server.js b/sites/svelte.dev/src/routes/docs.html/+server.js new file mode 100644 index 000000000000..e036e3cfce26 --- /dev/null +++ b/sites/svelte.dev/src/routes/docs.html/+server.js @@ -0,0 +1,2 @@ +export const prerender = true; +export { GET } from '../docs/+server.js'; diff --git a/sites/svelte.dev/src/routes/docs/+page.svelte b/sites/svelte.dev/src/routes/docs/+page.svelte deleted file mode 100644 index 3dec6b3a56d5..000000000000 --- a/sites/svelte.dev/src/routes/docs/+page.svelte +++ /dev/null @@ -1,216 +0,0 @@ - diff --git a/sites/svelte.dev/src/routes/docs/+server.js b/sites/svelte.dev/src/routes/docs/+server.js new file mode 100644 index 000000000000..81e57b4c7b4e --- /dev/null +++ b/sites/svelte.dev/src/routes/docs/+server.js @@ -0,0 +1,13 @@ +// @ts-ignore custom suffix doesn't have types and cba to add them just for this +import js from 'virtual:minified-raw:./redirect.js'; + +// avoid outputting a file named "docs" that would conflict with prerendered "docs" directory +export const prerender = false; + +export function GET() { + return new Response(``, { + headers: { + 'content-type': 'text/html' + } + }); +} diff --git a/sites/svelte.dev/src/routes/docs/redirect.js b/sites/svelte.dev/src/routes/docs/redirect.js new file mode 100644 index 000000000000..4f4c63c0fea3 --- /dev/null +++ b/sites/svelte.dev/src/routes/docs/redirect.js @@ -0,0 +1,58 @@ +/** @type {[RegExp, string][]}*/ +const pages_regex_map = [ + // Basic ones + [/(before-we-begin|getting-started)$/i, 'introduction'], + [/template-syntax$/i, 'basic-markup'], + [/component-format$/i, 'svelte-components'], + [/run-time$/i, 'svelte'], + [/compile-time$/i, 'svelte-compiler'], + [/(accessibility-warnings)$/i, '$1'], + + // component-format- + [/component-format-(script|style|script-context-module)$/i, 'svelte-components#$1'], + [/component-format-(script)(?:-?(.*))$/i, 'svelte-components#$1-$2'], + + // template-syntax + [/template-syntax-((?:element|component)-directives)-?(.*)/i, '$1#$2'], + [/template-syntax-slot$/i, 'special-elements#slot'], + [/template-syntax-(slot)-?(.*)/i, 'special-elements#$1-$2'], + [/template-syntax-(if|each|await|key)$/i, 'logic-blocks#$1'], + [/template-syntax-(const|debug|html)$/i, 'special-tags#$1'], + [/template-syntax-(tags|attributes-and-props|text-expressions|comments)$/i, 'basic-markup#$1'], + // !!!! This one should stay at the bottom of `template-syntax`, or it may end up hijacking logic blocks and special tags + [/template-syntax-(.+)/i, 'special-elements#$1'], + + // run-time + [/run-time-(svelte-(?:store|motion|transition|animate))-?(.*)/i, '$1#$2'], + [/run-time-(client-side-component-api)-?(.*)/i, '$1#$2'], + [/run-time-(svelte-easing|server-side-component-api|custom-element-api|svelte-register)$/i, '$1'], + // Catch all, should be at the end or will include store, motion, transition and other modules starting with svelte + [/run-time-(svelte)(?:-(.+))?/i, '$1#$2'], + + // Compile time + [/compile-time-svelte-?(.*)/i, 'svelte-compiler#$1'], + + // Accessibility warnings + [/(accessibility-warnings)-?(.+)/i, '$1#$2'] +]; + +function get_url_to_redirect_to() { + const hash = location.hash.slice(1); + if (!hash) return '/docs/introduction'; + + for (const [regex, replacement] of pages_regex_map) { + if (regex.test(hash)) { + return `/docs/${ + hash + .replace(regex, replacement) + .replace(/#$/, '') // Replace trailing # at the end + .replace('#--', '#') // have to do the -- replacement because of `--style-props` in old being `style-props` in new + }`; + } + } + + // ID doesn't match anything, take the user to intro page only + return '/docs/introduction'; +} + +location.href = new URL(get_url_to_redirect_to(), location.origin).href; diff --git a/sites/svelte.dev/vite.config.js b/sites/svelte.dev/vite.config.js index c02c0d66a8ee..eedee8100f60 100644 --- a/sites/svelte.dev/vite.config.js +++ b/sites/svelte.dev/vite.config.js @@ -2,23 +2,7 @@ import { sveltekit } from '@sveltejs/kit/vite'; import { browserslistToTargets } from 'lightningcss'; import { readFile } from 'node:fs/promises'; import browserslist from 'browserslist'; - -const plugins = [raw(['.ttf']), sveltekit()]; - -// Only enable sharp if we're not in a webcontainer env -if (!process.versions.webcontainer) { - plugins.push( - (await import('vite-imagetools')).imagetools({ - defaultDirectives: (url) => { - if (url.searchParams.has('big-image')) { - return new URLSearchParams('w=640;1280;2560;3840&format=avif;webp;png&as=picture'); - } - - return new URLSearchParams(); - } - }) - ); -} +import { transformWithEsbuild } from 'vite'; /** * @param {string[]} ext @@ -36,6 +20,50 @@ function raw(ext) { }; } +/** @returns {import('vite').Plugin} */ +function minified_raw_plugin() { + const prefix = 'virtual:minified-raw:'; + + return { + name: 'minified-raw-js', + async resolveId(id, importer) { + if (id.startsWith(prefix)) { + const resolved = await this.resolve(id.slice(prefix.length), importer, { skipSelf: true }); + return '\0' + prefix + resolved.id; + } + }, + async load(id) { + if (id.startsWith('\0' + prefix)) { + const real_id = id.slice(1 + prefix.length); + const original = await readFile(real_id, 'utf-8'); + const { code } = await transformWithEsbuild(original, real_id, { + minify: true, + format: 'esm' + }); + return `export default ${JSON.stringify(code)}`; + } + } + }; +} + +/** @type {import('vite').Plugin[]} */ +const plugins = [raw(['.ttf']), sveltekit(), minified_raw_plugin()]; + +// Only enable sharp if we're not in a webcontainer env +if (!process.versions.webcontainer) { + plugins.push( + (await import('vite-imagetools')).imagetools({ + defaultDirectives: (url) => { + if (url.searchParams.has('big-image')) { + return new URLSearchParams('w=640;1280;2560;3840&format=avif;webp;png&as=picture'); + } + + return new URLSearchParams(); + } + }) + ); +} + /** @type {import('vite').UserConfig} */ const config = { logLevel: 'info',