From 545286dade31ae1be9a0390113456dbd522c3637 Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Sun, 21 Aug 2022 11:00:13 +0200 Subject: [PATCH 01/15] WIP: Replace `sveltekit:prefetch` with `data-sveltekit-prefetch` at build time. --- packages/kit/src/runtime/client/client.js | 2 +- packages/kit/src/vite/index.js | 40 +++++++++++++++++++ .../source/pages/prefetching/+page.svelte | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 214d8843ccb5..78240689435d 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -1065,7 +1065,7 @@ export function create_client({ target, base, trailing_slash }) { /** @param {Event} event */ const trigger_prefetch = (event) => { const a = find_anchor(event); - if (a && a.href && a.hasAttribute('sveltekit:prefetch')) { + if (a && a.href && a.hasAttribute('data-sveltekit-prefetch')) { prefetch(get_href(a)); } }; diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index 4f4471d952c0..0b8047d3f3ea 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -324,6 +324,46 @@ function kit() { } }, + // IDEA: Maybe the attribute replacement could be done when rendering the chunks to avoid looping an extra time (as is the case with generateBundle). + // /** @type {import('rollup').RenderChunkHook} */ + // renderChunk(code, chunk) { + // for (const [attribute, replacement] of [['sveltekit:prefetch', 'data-sveltekit-prefetch']]) { + // if (code.includes(attribute)) { + // console.log(`[${chunk.name}]: Replacing "${attribute}" with "${replacement}"`); + + // return code.replace(attribute, replacement); + // } + // } + + // return code; + // }, + + // TODO: Ensure the replacement only happens for attributes + // TODO: Ensure the replacement happens for prerendered HTML too + // This might be read from the svelte source file which means we need to replace it when server side rendering the HTML response too. + /** + * @param {import('rollup').OutputOptions} _options + * @param {{ [fileName: string]: any }} bundle + */ + generateBundle(_options, bundle) { + for (const entry of Object.values(bundle)) { + if (entry.type !== 'chunk') continue; + + for (const [attribute, replacement] of [ + ['sveltekit:prefetch', 'data-sveltekit-prefetch'] + ]) { + if (entry.code.includes(attribute)) { + console.log(`[${entry.fileName}]: Replacing "${attribute}" with "${replacement}"`); + + bundle[entry.fileName] = { + ...entry, + code: entry.code.replaceAll(attribute, replacement) + }; + } + } + } + }, + /** * Vite builds a single bundle. We need three bundles: client, server, and service worker. * The user's package.json scripts will invoke the Vite CLI to execute the client build. We diff --git a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte index 07b287bef1f4..dc742748eba9 100644 --- a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte +++ b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte @@ -1 +1 @@ -click me +click me for sveltekit:prefetch From ee56dc75f8b7f2f3239414e8396f52e51af111e2 Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Sun, 21 Aug 2022 22:01:26 +0200 Subject: [PATCH 02/15] WIP: Use svelte-preprocess to replace values. Significant progress! PoC works great if run from the user's svelte.config.js, but we need to extend the user config and still make it work. Currently it only works when run with the default svelte config loading. --- packages/kit/src/core/config/index.js | 19 +++++++++++++++++++ packages/kit/src/vite/index.js | 13 +++++++++++++ .../source/pages/prefetching/+page.svelte | 2 ++ .../kit/test/apps/options/svelte.config.js | 16 +++++++++++++++- 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/kit/src/core/config/index.js b/packages/kit/src/core/config/index.js index f903bb086b05..30d91eb790e0 100644 --- a/packages/kit/src/core/config/index.js +++ b/packages/kit/src/core/config/index.js @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import * as url from 'url'; import options from './options.js'; +import preprocess from 'svelte-preprocess'; /** * Loads the template (src/app.html by default) and validates that it has the @@ -63,6 +64,24 @@ function process_config(config, { cwd = process.cwd() } = {}) { validated.kit.outDir = path.resolve(cwd, validated.kit.outDir); + const replaceSveltkitAttributes = preprocess({ + // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. + // replace: [[/sveltekit\:prefetch/g, 'data-sveltekit-prefetch']] + replace: [ + [/sveltekit:attribute/g, 'data-sveltekit-attribute'], + [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'] + ] + }); + + // TODO: Update types of `config.preprocess` to get type safety here. Use correct typing and validation from vite-plugin-svelte + // TODO: This needs to support all valid configs for preprocess, possibly including objects and not just arrays. + // TODO: Ensure the svelte.preprocess API can run multiple instances of `svelte-preprocess` if the user has their own config too. + if (Array.isArray(validated.preprocess)) { + validated.preprocess.push(replaceSveltkitAttributes); + } else { + validated.preprocess = [replaceSveltkitAttributes]; + } + for (const key in validated.kit.files) { // @ts-expect-error this is typescript at its stupidest validated.kit.files[key] = path.resolve(cwd, validated.kit.files[key]); diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index 0b8047d3f3ea..870a978dbe0c 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -62,6 +62,16 @@ const enforced_config = { * @return {import('vite').Plugin[]} */ export function sveltekit() { + // TODO: find out if this is the right place to ensure we add preprocessing for replacing sveltekit specific attributes + // NOTE: OR maybe it is autimatically passed in, since it uses the svelte.config.js file where we might have additional preprocessing + // TODO: Ensure preprocessing works with multiple calls to `svelte-preprocess`. + // Seems like it should be find though, as it likely is using an internal closure to keep state, and returning the callback to actually execute the transform. + + // IDEA: We could use svelte-preprocess to create the needed config for preprocessing `sveltekit:*` + // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. + // import preprocess from 'svelte-preprocess' + // preprocess({ replace: [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'] }) + return [...svelte(), kit()]; } @@ -197,6 +207,9 @@ function kit() { async config(config, config_env) { vite_config_env = config_env; svelte_config = await load_config(); + + console.log('vite svelte.config.js preprocess', svelte_config.preprocess); + env = get_env(vite_config_env.mode, svelte_config.kit.env.publicPrefix); // The config is created in build_server for SSR mode and passed inline diff --git a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte index dc742748eba9..7cafcd653907 100644 --- a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte +++ b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte @@ -1 +1,3 @@ click me for sveltekit:prefetch +
+click me for sveltekit:attribute diff --git a/packages/kit/test/apps/options/svelte.config.js b/packages/kit/test/apps/options/svelte.config.js index a5b1b65dc595..a740e299cf3d 100644 --- a/packages/kit/test/apps/options/svelte.config.js +++ b/packages/kit/test/apps/options/svelte.config.js @@ -1,3 +1,5 @@ +import preprocess from 'svelte-preprocess'; + /** @type {import('@sveltejs/kit').Config} */ const config = { extensions: ['.jesuslivesineveryone', '.whokilledthemuffinman', '.svelte.md', '.svelte'], @@ -23,7 +25,19 @@ const config = { base: '/path-base', assets: 'https://cdn.example.com/stuff' } - } + }, + preprocess: [ + // IDEA: We could use svelte-preprocess to create the needed config for preprocessing `sveltekit:*` + // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. + // preprocess({ + // // TODO: Find a way to create a combined preprocess() inside of sveltekit. + // // This works perfectly, but we shouldn't have to expose this detail to app developers. There must be a way to combine it. + // replace: [ + // [/sveltekit\:attribute/g, 'data-sveltekit-attribute'], + // [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'] + // ] + // }) + ] }; export default config; From ca440d28028cc7b2a8052dc472ad2143b0afaf56 Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Mon, 22 Aug 2022 08:25:56 +0200 Subject: [PATCH 03/15] Improve attribute replacement and make it work even if app devs have custom preprocessing config. Auto-reloading doesn't work though, so that needs to be fixed, along with regex specificity. --- packages/kit/src/core/config/index.js | 8 +-- packages/kit/src/runtime/client/client.js | 4 +- packages/kit/src/vite/index.js | 55 ++----------------- .../source/pages/prefetching/+page.svelte | 6 ++ .../kit/test/apps/options/svelte.config.js | 17 +++--- 5 files changed, 23 insertions(+), 67 deletions(-) diff --git a/packages/kit/src/core/config/index.js b/packages/kit/src/core/config/index.js index 30d91eb790e0..bff17961bc75 100644 --- a/packages/kit/src/core/config/index.js +++ b/packages/kit/src/core/config/index.js @@ -66,16 +66,16 @@ function process_config(config, { cwd = process.cwd() } = {}) { const replaceSveltkitAttributes = preprocess({ // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // replace: [[/sveltekit\:prefetch/g, 'data-sveltekit-prefetch']] + // TODO: Ensure the replacement happens for prerendered HTML too replace: [ - [/sveltekit:attribute/g, 'data-sveltekit-attribute'], - [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'] + [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], + [/sveltekit\:reload/g, 'data-sveltekit-reload'], + [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] ] }); // TODO: Update types of `config.preprocess` to get type safety here. Use correct typing and validation from vite-plugin-svelte // TODO: This needs to support all valid configs for preprocess, possibly including objects and not just arrays. - // TODO: Ensure the svelte.preprocess API can run multiple instances of `svelte-preprocess` if the user has their own config too. if (Array.isArray(validated.preprocess)) { validated.preprocess.push(replaceSveltkitAttributes); } else { diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 78240689435d..6ab977b64b66 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -1122,7 +1122,7 @@ export function create_client({ target, base, trailing_slash }) { if ( a.hasAttribute('download') || rel.includes('external') || - a.hasAttribute('sveltekit:reload') + a.hasAttribute('data-sveltekit-reload') ) { return; } @@ -1149,7 +1149,7 @@ export function create_client({ target, base, trailing_slash }) { navigate({ url, - scroll: a.hasAttribute('sveltekit:noscroll') ? scroll_state() : null, + scroll: a.hasAttribute('data-sveltekit-noscroll') ? scroll_state() : null, keepfocus: false, redirect_chain: [], details: { diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index 870a978dbe0c..9a08d034f746 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -58,21 +58,14 @@ const enforced_config = { root: true }; +// TODO: Figure out how to reload the svelte.config.js when changes happen. +const svelte_config = await load_config(); + /** * @return {import('vite').Plugin[]} */ export function sveltekit() { - // TODO: find out if this is the right place to ensure we add preprocessing for replacing sveltekit specific attributes - // NOTE: OR maybe it is autimatically passed in, since it uses the svelte.config.js file where we might have additional preprocessing - // TODO: Ensure preprocessing works with multiple calls to `svelte-preprocess`. - // Seems like it should be find though, as it likely is using an internal closure to keep state, and returning the callback to actually execute the transform. - - // IDEA: We could use svelte-preprocess to create the needed config for preprocessing `sveltekit:*` - // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // import preprocess from 'svelte-preprocess' - // preprocess({ replace: [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'] }) - - return [...svelte(), kit()]; + return [...svelte({ configFile: false, ...svelte_config }), kit()]; } /** @@ -337,46 +330,6 @@ function kit() { } }, - // IDEA: Maybe the attribute replacement could be done when rendering the chunks to avoid looping an extra time (as is the case with generateBundle). - // /** @type {import('rollup').RenderChunkHook} */ - // renderChunk(code, chunk) { - // for (const [attribute, replacement] of [['sveltekit:prefetch', 'data-sveltekit-prefetch']]) { - // if (code.includes(attribute)) { - // console.log(`[${chunk.name}]: Replacing "${attribute}" with "${replacement}"`); - - // return code.replace(attribute, replacement); - // } - // } - - // return code; - // }, - - // TODO: Ensure the replacement only happens for attributes - // TODO: Ensure the replacement happens for prerendered HTML too - // This might be read from the svelte source file which means we need to replace it when server side rendering the HTML response too. - /** - * @param {import('rollup').OutputOptions} _options - * @param {{ [fileName: string]: any }} bundle - */ - generateBundle(_options, bundle) { - for (const entry of Object.values(bundle)) { - if (entry.type !== 'chunk') continue; - - for (const [attribute, replacement] of [ - ['sveltekit:prefetch', 'data-sveltekit-prefetch'] - ]) { - if (entry.code.includes(attribute)) { - console.log(`[${entry.fileName}]: Replacing "${attribute}" with "${replacement}"`); - - bundle[entry.fileName] = { - ...entry, - code: entry.code.replaceAll(attribute, replacement) - }; - } - } - } - }, - /** * Vite builds a single bundle. We need three bundles: client, server, and service worker. * The user's package.json scripts will invoke the Vite CLI to execute the client build. We diff --git a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte index 7cafcd653907..28ba6017045b 100644 --- a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte +++ b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte @@ -1,3 +1,9 @@ click me for sveltekit:prefetch
click me for sveltekit:attribute +
+click me for sveltekit:noscroll +
+click me for sveltekit:reload +
+click me for sveltekit:something diff --git a/packages/kit/test/apps/options/svelte.config.js b/packages/kit/test/apps/options/svelte.config.js index a740e299cf3d..59eed8019b5b 100644 --- a/packages/kit/test/apps/options/svelte.config.js +++ b/packages/kit/test/apps/options/svelte.config.js @@ -27,16 +27,13 @@ const config = { } }, preprocess: [ - // IDEA: We could use svelte-preprocess to create the needed config for preprocessing `sveltekit:*` - // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // preprocess({ - // // TODO: Find a way to create a combined preprocess() inside of sveltekit. - // // This works perfectly, but we shouldn't have to expose this detail to app developers. There must be a way to combine it. - // replace: [ - // [/sveltekit\:attribute/g, 'data-sveltekit-attribute'], - // [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'] - // ] - // }) + // Test how combined user preprocessing works together with internal sveltekit preprocessing. + preprocess({ + replace: [ + [/sveltekit\:attribute/g, 'data-sveltekit-attribute'], + [/sveltekit\:something/g, 'data-sveltekit-something'] + ] + }) ] }; From c512b27c461c6d5134649a5e77c87ecce5a02d28 Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Mon, 22 Aug 2022 08:36:19 +0200 Subject: [PATCH 04/15] WIP: Explore how to combine the svelte config by the user with the options needed by sveltekit. --- packages/kit/src/core/config/index.js | 34 +++++++++++++-------------- packages/kit/src/vite/index.js | 23 ++++++++++++++---- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/kit/src/core/config/index.js b/packages/kit/src/core/config/index.js index bff17961bc75..f456df024452 100644 --- a/packages/kit/src/core/config/index.js +++ b/packages/kit/src/core/config/index.js @@ -64,23 +64,23 @@ function process_config(config, { cwd = process.cwd() } = {}) { validated.kit.outDir = path.resolve(cwd, validated.kit.outDir); - const replaceSveltkitAttributes = preprocess({ - // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // TODO: Ensure the replacement happens for prerendered HTML too - replace: [ - [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], - [/sveltekit\:reload/g, 'data-sveltekit-reload'], - [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] - ] - }); - - // TODO: Update types of `config.preprocess` to get type safety here. Use correct typing and validation from vite-plugin-svelte - // TODO: This needs to support all valid configs for preprocess, possibly including objects and not just arrays. - if (Array.isArray(validated.preprocess)) { - validated.preprocess.push(replaceSveltkitAttributes); - } else { - validated.preprocess = [replaceSveltkitAttributes]; - } + // const replaceSveltkitAttributes = preprocess({ + // // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. + // // TODO: Ensure the replacement happens for prerendered HTML too + // replace: [ + // [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], + // [/sveltekit\:reload/g, 'data-sveltekit-reload'], + // [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] + // ] + // }); + + // // TODO: Update types of `config.preprocess` to get type safety here. Use correct typing and validation from vite-plugin-svelte + // // TODO: This needs to support all valid configs for preprocess, possibly including objects and not just arrays. + // if (Array.isArray(validated.preprocess)) { + // validated.preprocess.push(replaceSveltkitAttributes); + // } else { + // validated.preprocess = [replaceSveltkitAttributes]; + // } for (const key in validated.kit.files) { // @ts-expect-error this is typescript at its stupidest diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index 9a08d034f746..d5867d31a4b2 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -17,6 +17,7 @@ import { preview } from './preview/index.js'; import { get_aliases, resolve_entry, prevent_illegal_rollup_imports, get_env } from './utils.js'; import { fileURLToPath } from 'node:url'; import { create_module } from '../core/env.js'; +import preprocess from 'svelte-preprocess'; const cwd = process.cwd(); @@ -58,14 +59,28 @@ const enforced_config = { root: true }; -// TODO: Figure out how to reload the svelte.config.js when changes happen. -const svelte_config = await load_config(); - /** * @return {import('vite').Plugin[]} */ export function sveltekit() { - return [...svelte({ configFile: false, ...svelte_config }), kit()]; + return [ + ...svelte({ + // IDEA: Maybe vite-plugin-svelte can me modified to allow extending the user's svelte.config.js + // This would allow us to add inlineOptions with the preprocessing we need, without overwriting preprocessing from the user's config. + preprocess: [ + preprocess({ + // // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. + // // TODO: Ensure the replacement happens for prerendered HTML too + replace: [ + [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], + [/sveltekit\:reload/g, 'data-sveltekit-reload'], + [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] + ] + }) + ] + }), + kit() + ]; } /** From 17a0183207b99df981e2f6d768440acacd85ff14 Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Mon, 22 Aug 2022 21:58:54 +0200 Subject: [PATCH 05/15] Improve type definition for `config.preprocess` to match what's used internally. Also allow object configs. --- packages/kit/src/core/config/index.js | 33 +++++++++++++++++---------- packages/kit/types/index.d.ts | 3 ++- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/kit/src/core/config/index.js b/packages/kit/src/core/config/index.js index f456df024452..0d7bb5e6abf7 100644 --- a/packages/kit/src/core/config/index.js +++ b/packages/kit/src/core/config/index.js @@ -64,20 +64,29 @@ function process_config(config, { cwd = process.cwd() } = {}) { validated.kit.outDir = path.resolve(cwd, validated.kit.outDir); - // const replaceSveltkitAttributes = preprocess({ - // // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // // TODO: Ensure the replacement happens for prerendered HTML too - // replace: [ - // [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], - // [/sveltekit\:reload/g, 'data-sveltekit-reload'], - // [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] - // ] - // }); - - // // TODO: Update types of `config.preprocess` to get type safety here. Use correct typing and validation from vite-plugin-svelte - // // TODO: This needs to support all valid configs for preprocess, possibly including objects and not just arrays. + const replaceSveltkitAttributes = preprocess({ + // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. + // TODO: Ensure the replacement happens for prerendered HTML too + // TODO: Ensure the replacement happens for SvelteKit packages too + replace: [ + [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], + [/sveltekit\:reload/g, 'data-sveltekit-reload'], + [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] + ] + }); + + /** @ts-expect-error RecursiveRequired is messing up the regular Config which is all we need for `preprocess` */ + validated.preprocess = Array.isArray(validated.preprocess) + ? [...validated.preprocess, replaceSveltkitAttributes] + : typeof validated.preprocess === 'object' + ? [validated.preprocess, replaceSveltkitAttributes] + : [replaceSveltkitAttributes]; + + // NOTE: This would be much cleaner with distinct if/else statements, but would require fixing the types. // if (Array.isArray(validated.preprocess)) { // validated.preprocess.push(replaceSveltkitAttributes); + // } else if (typeof validated.preprocess === 'object') { + // validated.preprocess = [validated.preprocess, replaceSveltkitAttributes]; // } else { // validated.preprocess = [replaceSveltkitAttributes]; // } diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 294330e193fe..009f15def3f8 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -4,6 +4,7 @@ import './ambient.js'; import { CompileOptions } from 'svelte/types/compiler/interfaces'; +import type { SvelteOptions } from '@sveltejs/vite-plugin-svelte'; import { AdapterEntry, CspDirectives, @@ -113,7 +114,7 @@ export interface Config { exports?: (filepath: string) => boolean; files?: (filepath: string) => boolean; }; - preprocess?: any; + preprocess?: SvelteOptions['preprocess']; [key: string]: any; } From 0aabdde38cc766a5ef18dabbba15caa4bd9d891c Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Mon, 22 Aug 2022 22:42:52 +0200 Subject: [PATCH 06/15] Use API from vite-plugin-svelte to add internal SvelteKit preprocessing Much cleaner solution, which also should be a tiny bit more performant than before. --- packages/kit/src/core/config/index.js | 28 ---------------- packages/kit/src/vite/index.js | 32 ++++++++----------- .../kit/test/apps/options/svelte.config.js | 1 - 3 files changed, 14 insertions(+), 47 deletions(-) diff --git a/packages/kit/src/core/config/index.js b/packages/kit/src/core/config/index.js index 0d7bb5e6abf7..f903bb086b05 100644 --- a/packages/kit/src/core/config/index.js +++ b/packages/kit/src/core/config/index.js @@ -2,7 +2,6 @@ import fs from 'fs'; import path from 'path'; import * as url from 'url'; import options from './options.js'; -import preprocess from 'svelte-preprocess'; /** * Loads the template (src/app.html by default) and validates that it has the @@ -64,33 +63,6 @@ function process_config(config, { cwd = process.cwd() } = {}) { validated.kit.outDir = path.resolve(cwd, validated.kit.outDir); - const replaceSveltkitAttributes = preprocess({ - // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // TODO: Ensure the replacement happens for prerendered HTML too - // TODO: Ensure the replacement happens for SvelteKit packages too - replace: [ - [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], - [/sveltekit\:reload/g, 'data-sveltekit-reload'], - [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] - ] - }); - - /** @ts-expect-error RecursiveRequired is messing up the regular Config which is all we need for `preprocess` */ - validated.preprocess = Array.isArray(validated.preprocess) - ? [...validated.preprocess, replaceSveltkitAttributes] - : typeof validated.preprocess === 'object' - ? [validated.preprocess, replaceSveltkitAttributes] - : [replaceSveltkitAttributes]; - - // NOTE: This would be much cleaner with distinct if/else statements, but would require fixing the types. - // if (Array.isArray(validated.preprocess)) { - // validated.preprocess.push(replaceSveltkitAttributes); - // } else if (typeof validated.preprocess === 'object') { - // validated.preprocess = [validated.preprocess, replaceSveltkitAttributes]; - // } else { - // validated.preprocess = [replaceSveltkitAttributes]; - // } - for (const key in validated.kit.files) { // @ts-expect-error this is typescript at its stupidest validated.kit.files[key] = path.resolve(cwd, validated.kit.files[key]); diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index d5867d31a4b2..dd675375633b 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -63,24 +63,7 @@ const enforced_config = { * @return {import('vite').Plugin[]} */ export function sveltekit() { - return [ - ...svelte({ - // IDEA: Maybe vite-plugin-svelte can me modified to allow extending the user's svelte.config.js - // This would allow us to add inlineOptions with the preprocessing we need, without overwriting preprocessing from the user's config. - preprocess: [ - preprocess({ - // // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // // TODO: Ensure the replacement happens for prerendered HTML too - replace: [ - [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], - [/sveltekit\:reload/g, 'data-sveltekit-reload'], - [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] - ] - }) - ] - }), - kit() - ]; + return [...svelte(), kit()]; } /** @@ -208,6 +191,19 @@ function kit() { return { name: 'vite-plugin-svelte-kit', + api: { + // Replace custom attributes with valid HTML attributes + sveltePreprocess: preprocess({ + // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. + // TODO: Ensure the replacement happens for SvelteKit packages too + replace: [ + [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], + [/sveltekit\:reload/g, 'data-sveltekit-reload'], + [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] + ] + }) + }, + /** * Build the SvelteKit-provided Vite config to be merged with the user's vite.config.js file. * @see https://vitejs.dev/guide/api-plugin.html#config diff --git a/packages/kit/test/apps/options/svelte.config.js b/packages/kit/test/apps/options/svelte.config.js index 59eed8019b5b..76f4628eae83 100644 --- a/packages/kit/test/apps/options/svelte.config.js +++ b/packages/kit/test/apps/options/svelte.config.js @@ -27,7 +27,6 @@ const config = { } }, preprocess: [ - // Test how combined user preprocessing works together with internal sveltekit preprocessing. preprocess({ replace: [ [/sveltekit\:attribute/g, 'data-sveltekit-attribute'], From bc03a40c28dae09db3fa7c5ca1048a55696da396 Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Mon, 22 Aug 2022 23:54:51 +0200 Subject: [PATCH 07/15] Cleanup --- packages/kit/src/vite/index.js | 2 -- .../test/apps/options/source/pages/prefetching/+page.svelte | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index dd675375633b..4cca6882534d 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -212,8 +212,6 @@ function kit() { vite_config_env = config_env; svelte_config = await load_config(); - console.log('vite svelte.config.js preprocess', svelte_config.preprocess); - env = get_env(vite_config_env.mode, svelte_config.kit.env.publicPrefix); // The config is created in build_server for SSR mode and passed inline diff --git a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte index 28ba6017045b..16e618d3a7d2 100644 --- a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte +++ b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte @@ -1,9 +1,11 @@ click me for sveltekit:prefetch
-click me for sveltekit:attribute -
click me for sveltekit:noscroll
click me for sveltekit:reload + +
click me for sveltekit:something +
+click me for sveltekit:attribute From 6c21f2338f8e3eb6cd68b3c0aa18595fdd7755ef Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Tue, 23 Aug 2022 08:06:07 +0200 Subject: [PATCH 08/15] Breaking: Rename sveltekit:prefetch to data-sveltekit-precfetch --- documentation/docs/09-a-options.md | 6 +++--- documentation/docs/80-migrating.md | 4 ++-- .../templates/default/src/lib/header/Header.svelte | 6 +++--- .../core/prerender/fixtures/basic-href/input.html | 4 ++-- packages/kit/src/vite/index.js | 14 -------------- .../options/source/pages/prefetching/+page.svelte | 12 +----------- packages/kit/test/apps/options/svelte.config.js | 12 +----------- packages/kit/types/ambient.d.ts | 2 +- sites/kit.svelte.dev/src/lib/docs/Contents.svelte | 6 +++--- .../src/lib/search/SearchResultList.svelte | 2 +- sites/kit.svelte.dev/src/routes/+page.svelte | 6 +++--- 11 files changed, 20 insertions(+), 54 deletions(-) diff --git a/documentation/docs/09-a-options.md b/documentation/docs/09-a-options.md index ac5f6206ac8f..d6e7e7a67caf 100644 --- a/documentation/docs/09-a-options.md +++ b/documentation/docs/09-a-options.md @@ -2,16 +2,16 @@ title: Anchor options --- -### sveltekit:prefetch +### data-sveltekit-prefetch SvelteKit uses code splitting to break your app into small chunks (one per route), ensuring fast startup times. For _dynamic_ routes, such as our `src/routes/blog/[slug]/+page.svelte` example, that's not enough. In order to render the blog post, we need to fetch the data for it, and we can't do that until we know what `slug` is. In the worst case, that could cause lag as the browser waits for the data to come back from the server. -We can mitigate that by _prefetching_ the data. Adding a `sveltekit:prefetch` attribute to a link... +We can mitigate that by _prefetching_ the data. Adding a `data-sveltekit-prefetch` attribute to a link... ```html -What is SvelteKit? +What is SvelteKit? ``` ...will cause SvelteKit to run the page's `load` function as soon as the user hovers over the link (on a desktop) or touches it (on mobile), rather than waiting for the `click` event to trigger navigation. Typically, this buys us an extra couple of hundred milliseconds, which is the difference between a user interface that feels laggy, and one that feels snappy. diff --git a/documentation/docs/80-migrating.md b/documentation/docs/80-migrating.md index ce59f49a194a..342e3f03bc60 100644 --- a/documentation/docs/80-migrating.md +++ b/documentation/docs/80-migrating.md @@ -135,8 +135,8 @@ This caused problems and is no longer the case in SvelteKit. Instead, relative U #### <a> attributes -- `sapper:prefetch` is now `sveltekit:prefetch` -- `sapper:noscroll` is now `sveltekit:noscroll` +- `sapper:prefetch` is now `data-sveltekit-prefetch` +- `sapper:noscroll` is now `data-sveltekit-noscroll` ### Endpoints diff --git a/packages/create-svelte/templates/default/src/lib/header/Header.svelte b/packages/create-svelte/templates/default/src/lib/header/Header.svelte index 9d3120f3e6fd..4293c2389930 100644 --- a/packages/create-svelte/templates/default/src/lib/header/Header.svelte +++ b/packages/create-svelte/templates/default/src/lib/header/Header.svelte @@ -15,12 +15,12 @@ https://external.com /wheee - /wheee - /wheee + /wheee + /wheee /wheee diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index 4cca6882534d..6e6504996e86 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -17,7 +17,6 @@ import { preview } from './preview/index.js'; import { get_aliases, resolve_entry, prevent_illegal_rollup_imports, get_env } from './utils.js'; import { fileURLToPath } from 'node:url'; import { create_module } from '../core/env.js'; -import preprocess from 'svelte-preprocess'; const cwd = process.cwd(); @@ -191,19 +190,6 @@ function kit() { return { name: 'vite-plugin-svelte-kit', - api: { - // Replace custom attributes with valid HTML attributes - sveltePreprocess: preprocess({ - // TODO: Update regex to only match attributes and not all string values, to prevent it from replacing text content. - // TODO: Ensure the replacement happens for SvelteKit packages too - replace: [ - [/sveltekit\:prefetch/g, 'data-sveltekit-prefetch'], - [/sveltekit\:reload/g, 'data-sveltekit-reload'], - [/sveltekit\:noscroll/g, 'data-sveltekit-noscroll'] - ] - }) - }, - /** * Build the SvelteKit-provided Vite config to be merged with the user's vite.config.js file. * @see https://vitejs.dev/guide/api-plugin.html#config diff --git a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte index 16e618d3a7d2..4d55ffcdf64e 100644 --- a/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte +++ b/packages/kit/test/apps/options/source/pages/prefetching/+page.svelte @@ -1,11 +1 @@ -click me for sveltekit:prefetch -
-click me for sveltekit:noscroll -
-click me for sveltekit:reload - - -
-click me for sveltekit:something -
-click me for sveltekit:attribute +click me diff --git a/packages/kit/test/apps/options/svelte.config.js b/packages/kit/test/apps/options/svelte.config.js index 76f4628eae83..a5b1b65dc595 100644 --- a/packages/kit/test/apps/options/svelte.config.js +++ b/packages/kit/test/apps/options/svelte.config.js @@ -1,5 +1,3 @@ -import preprocess from 'svelte-preprocess'; - /** @type {import('@sveltejs/kit').Config} */ const config = { extensions: ['.jesuslivesineveryone', '.whokilledthemuffinman', '.svelte.md', '.svelte'], @@ -25,15 +23,7 @@ const config = { base: '/path-base', assets: 'https://cdn.example.com/stuff' } - }, - preprocess: [ - preprocess({ - replace: [ - [/sveltekit\:attribute/g, 'data-sveltekit-attribute'], - [/sveltekit\:something/g, 'data-sveltekit-something'] - ] - }) - ] + } }; export default config; diff --git a/packages/kit/types/ambient.d.ts b/packages/kit/types/ambient.d.ts index 678de3ebe48d..bcd8195d6736 100644 --- a/packages/kit/types/ambient.d.ts +++ b/packages/kit/types/ambient.d.ts @@ -160,7 +160,7 @@ declare module '$app/navigation' { * 1. ensuring that the code for the page is loaded, and * 2. calling the page's load function with the appropriate options. * - * This is the same behaviour that SvelteKit triggers when the user taps or mouses over an `` element with `sveltekit:prefetch`. + * This is the same behaviour that SvelteKit triggers when the user taps or mouses over an `` element with `data-sveltekit-prefetch`. * If the next navigation is to `href`, the values returned from load will be used, making navigation instantaneous. * Returns a Promise that resolves when the prefetch is complete. * diff --git a/sites/kit.svelte.dev/src/lib/docs/Contents.svelte b/sites/kit.svelte.dev/src/lib/docs/Contents.svelte index 1b538565f360..dbed3dfcf5a5 100644 --- a/sites/kit.svelte.dev/src/lib/docs/Contents.svelte +++ b/sites/kit.svelte.dev/src/lib/docs/Contents.svelte @@ -82,7 +82,7 @@ {#each contents as section}
  • dispatch('select', { href: result.href })} data-has-node={result.node ? true : undefined} diff --git a/sites/kit.svelte.dev/src/routes/+page.svelte b/sites/kit.svelte.dev/src/routes/+page.svelte index 3aa00a0466a2..a18aa397b6dd 100644 --- a/sites/kit.svelte.dev/src/routes/+page.svelte +++ b/sites/kit.svelte.dev/src/routes/+page.svelte @@ -40,7 +40,7 @@ of an SPA

    -
    read the docs + read the docs
    @@ -50,7 +50,7 @@ support and more

    - read the docs + read the docs
    @@ -77,7 +77,7 @@ cd my-app npm install npm run dev -- --open - get started + get started
    From c8e3bd0a626255f53a7602bf4285f5f04e20b17a Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Tue, 23 Aug 2022 08:06:23 +0200 Subject: [PATCH 09/15] Breaking: Rename sveltekit:noscroll to data-sveltekit-noscroll --- documentation/docs/09-a-options.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/docs/09-a-options.md b/documentation/docs/09-a-options.md index d6e7e7a67caf..9c590b2c465a 100644 --- a/documentation/docs/09-a-options.md +++ b/documentation/docs/09-a-options.md @@ -34,14 +34,14 @@ Adding a `sveltekit:reload` attribute to a link... Links with a `rel="external"` attribute will receive the same treatment. In addition, they will be ignored during [prerendering](https://kit.svelte.dev/docs/page-options#prerender). -### sveltekit:noscroll +### data-sveltekit-noscroll When navigating to internal links, SvelteKit mirrors the browser's default navigation behaviour: it will change the scroll position to 0,0 so that the user is at the very top left of the page (unless the link includes a `#hash`, in which case it will scroll to the element with a matching ID). -In certain cases, you may wish to disable this behaviour. Adding a `sveltekit:noscroll` attribute to a link... +In certain cases, you may wish to disable this behaviour. Adding a `data-sveltekit-noscroll` attribute to a link... ```html -Path +Path ``` ...will prevent scrolling after the link is clicked. From 13fbc638c2e5a2817d5ada74a5655470944f68e0 Mon Sep 17 00:00:00 2001 From: Samuel Plumppu <6125097+Greenheart@users.noreply.github.com> Date: Tue, 23 Aug 2022 08:08:11 +0200 Subject: [PATCH 10/15] Breaking: Rename sveltekit:reload to data-sveltekit-reload --- documentation/docs/09-a-options.md | 6 +++--- .../kit/test/apps/basics/src/routes/routing/+page.svelte | 2 +- packages/kit/test/apps/basics/test/test.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/docs/09-a-options.md b/documentation/docs/09-a-options.md index 9c590b2c465a..c5184f7793a9 100644 --- a/documentation/docs/09-a-options.md +++ b/documentation/docs/09-a-options.md @@ -20,14 +20,14 @@ Note that prefetching will not work if the [`router`](/docs/page-options#router) You can also programmatically invoke `prefetch` from `$app/navigation`. -### sveltekit:reload +### data-sveltekit-reload By default, the SvelteKit runtime intercepts clicks on `` elements and bypasses the normal browser navigation for relative (same-origin) URLs that match one of your page routes. We sometimes need to tell SvelteKit that certain links need to be handled by normal browser navigation. Examples of this might be linking to another page on your domain that's not part of your SvelteKit app or linking to an endpoint. -Adding a `sveltekit:reload` attribute to a link... +Adding a `data-sveltekit-reload` attribute to a link... ```html -Path +Path ``` ...will cause browser to navigate via a full page reload when the link is clicked. diff --git a/packages/kit/test/apps/basics/src/routes/routing/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/+page.svelte index 81b4fef415f6..61f62ec6f5f5 100644 --- a/packages/kit/test/apps/basics/src/routes/routing/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/routing/+page.svelte @@ -9,6 +9,6 @@ elsewhere static.json -b +b
    diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index 1407da0aeecf..07821949a9c7 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -1419,7 +1419,7 @@ test.describe('Routing', () => { expect(await page.textContent('body')).toBe('ok'); }); - test('does not attempt client-side navigation to links with sveltekit:reload', async ({ + test('does not attempt client-side navigation to links with data-sveltekit-reload', async ({ baseURL, page }) => { From 4fb978173c3cb8db2f14c3342c520a1d0e45f911 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 21:33:12 -0400 Subject: [PATCH 11/15] print console error for removed attributes in dev --- packages/kit/src/runtime/client/client.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 63d7713ac29c..7c78fb29f23e 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -44,6 +44,23 @@ function update_scroll_positions(index) { scroll_positions[index] = scroll_state(); } +/** @type {Record} */ +let warned_about_attributes = {}; + +function check_for_removed_attributes() { + const attrs = ['prefetch', 'noscroll', 'reload']; + for (const attr of attrs) { + if (document.querySelector(`[sveltekit\\:${attr}]`)) { + if (!warned_about_attributes[attr]) { + warned_about_attributes[attr] = true; + console.error( + `The sveltekit:${attr} attribute has been replaced with data-sveltekit-${attr}` + ); + } + } + } +} + /** * @param {{ * target: Element; @@ -271,6 +288,8 @@ export function create_client({ target, base, trailing_slash }) { }; root.$set(navigation_result.props); tick().then(() => (console.warn = warn)); + + check_for_removed_attributes(); } else { root.$set(navigation_result.props); } @@ -369,6 +388,8 @@ export function create_client({ target, base, trailing_slash }) { hydrate: true }); console.warn = warn; + + check_for_removed_attributes(); } else { root = new Root({ target, From 5d0b7987b50a9fc50c310b4df759054dab1bc9b3 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 21:35:39 -0400 Subject: [PATCH 12/15] lint --- .../templates/default/src/lib/header/Header.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/create-svelte/templates/default/src/lib/header/Header.svelte b/packages/create-svelte/templates/default/src/lib/header/Header.svelte index 4293c2389930..a048e0eccf00 100644 --- a/packages/create-svelte/templates/default/src/lib/header/Header.svelte +++ b/packages/create-svelte/templates/default/src/lib/header/Header.svelte @@ -15,7 +15,9 @@
      -
    • Home
    • +
    • + Home +
    • About
    • From 9cbad2de44d998f76b282e2d8d269779ea98d631 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 22:06:48 -0400 Subject: [PATCH 13/15] Update packages/kit/types/index.d.ts --- packages/kit/types/index.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 86a12493f3c8..4e9e6b06be47 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -4,7 +4,6 @@ import './ambient.js'; import { CompileOptions } from 'svelte/types/compiler/interfaces'; -import type { SvelteOptions } from '@sveltejs/vite-plugin-svelte'; import { AdapterEntry, CspDirectives, From 97d289fd9326e0ca78bb703f4604f8cd7206d1b2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 22:06:55 -0400 Subject: [PATCH 14/15] Update packages/kit/types/index.d.ts --- packages/kit/types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 4e9e6b06be47..a4b9cb024db4 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -113,7 +113,7 @@ export interface Config { exports?: (filepath: string) => boolean; files?: (filepath: string) => boolean; }; - preprocess?: SvelteOptions['preprocess']; + preprocess?: any; [key: string]: any; } From 8e9224a2999a7052d8b88119725271332fd0fbc9 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 29 Aug 2022 22:07:24 -0400 Subject: [PATCH 15/15] Create neat-pots-flash.md --- .changeset/neat-pots-flash.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/neat-pots-flash.md diff --git a/.changeset/neat-pots-flash.md b/.changeset/neat-pots-flash.md new file mode 100644 index 000000000000..80fa9c864876 --- /dev/null +++ b/.changeset/neat-pots-flash.md @@ -0,0 +1,6 @@ +--- +"create-svelte": patch +"@sveltejs/kit": patch +--- + +[breaking] Replace `sveltekit:*` with valid HTML attributes like `data-sveltekit-*`