diff --git a/apps/svelte.dev/content/blog/2023-03-09-zero-config-type-safety.md b/apps/svelte.dev/content/blog/2023-03-09-zero-config-type-safety.md index caef68418d..30f49326dd 100644 --- a/apps/svelte.dev/content/blog/2023-03-09-zero-config-type-safety.md +++ b/apps/svelte.dev/content/blog/2023-03-09-zero-config-type-safety.md @@ -44,6 +44,12 @@ This is where our automatic type generation comes in. Every route directory has ```js /// file: src/routes/blog/[slug]/+page.server.ts +const database = { + getPost(slug: string | undefined): Promise { + return Promise.resolve('hello world'); + } +}; +// ---cut--- ---import type { ServerLoadEvent } from '@sveltejs/kit';--- +++import type { PageServerLoadEvent } from './$types';+++ @@ -133,7 +139,14 @@ src/ Thanks to the automatic type generation we get advanced type safety. Wouldn't it be great though if we could just omit writing the types at all? As of today you can do exactly that: ```js +// @errors: 7006 /// file: src/routes/blog/[slug]/+page.server.ts +const database = { + getPost(slug: string | undefined): Promise { + return Promise.resolve('hello world'); + } +}; +// ---cut--- ---import type { PageServerLoadEvent } from './$types';--- export async function load(event---: PageServerLoadEvent---) { diff --git a/apps/svelte.dev/content/docs/kit/20-core-concepts/60-remote-functions.md b/apps/svelte.dev/content/docs/kit/20-core-concepts/60-remote-functions.md index aa6f0c83cb..d87f175e0a 100644 --- a/apps/svelte.dev/content/docs/kit/20-core-concepts/60-remote-functions.md +++ b/apps/svelte.dev/content/docs/kit/20-core-concepts/60-remote-functions.md @@ -524,7 +524,14 @@ In addition to declarative schema validation, you can programmatically mark fiel - It accepts multiple arguments that can be strings (for issues relating to the form as a whole — these will only show up in `fields.allIssues()`) or standard-schema-compliant issues (for those relating to a specific field). Use the `issue` parameter for type-safe creation of such issues: ```js +// @errors: 18046 /// file: src/routes/shop/data.remote.js +// @filename: ambient.d.ts +declare module '$lib/server/database' { + export function buy(qty: number): Promise +} +// @filename: index.js +// ---cut--- import * as v from 'valibot'; import { invalid } from '@sveltejs/kit'; import { form } from '$app/server'; @@ -1166,7 +1173,7 @@ As long as _you're_ not passing invalid data to your remote functions, there are In the second case, we don't want to give the attacker any help, so SvelteKit will generate a generic [400 Bad Request](https://http.dog/400) response. You can control the message by implementing the [`handleValidationError`](hooks#Server-hooks-handleValidationError) server hook, which, like [`handleError`](hooks#Shared-hooks-handleError), must return an [`App.Error`](errors#Type-safety) (which defaults to `{ message: string }`): ```js -/// file: src/hooks.server.ts +/// file: src/hooks.server.js /** @type {import('@sveltejs/kit').HandleValidationError} */ export function handleValidationError({ event, issues }) { return { @@ -1193,13 +1200,25 @@ Inside `query`, `form` and `command` you can use [`getRequestEvent`]($app-server ```ts /// file: user.remote.ts +// @filename: ambient.d.ts +interface User { + name: string; + avatar: string; +} + +declare module '$lib/server/database' { + export function findUser(sessionId: string | undefined): Promise; +} + +// @filename: index.js +// ---cut--- import { getRequestEvent, query } from '$app/server'; import { findUser } from '$lib/server/database'; export const getProfile = query(async () => { const user = await getUser(); - return { + return user && { name: user.name, avatar: user.avatar }; diff --git a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/50-adapter-static.md b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/50-adapter-static.md index b148f3576e..9ff6db32dd 100644 --- a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/50-adapter-static.md +++ b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/50-adapter-static.md @@ -12,6 +12,7 @@ This will prerender your entire site as a collection of static files. If you'd l Install with `npm i -D @sveltejs/adapter-static`, then add the adapter to your `svelte.config.js`: ```js +// @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-static'; @@ -56,6 +57,7 @@ Some platforms have zero-config support (more to come in future): On these platforms, you should omit the adapter options so that `adapter-static` can provide the optimal configuration: ```js +// @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-static'; @@ -81,7 +83,7 @@ The directory to write static assets (the contents of `static`, plus client-side ### fallback -To create a [single page app (SPA)](single-page-apps) you must specify the name of the fallback page to be generated by SvelteKit, which is used as the entry point for URLs that have not been prerendered. This is commonly `200.html`, but can vary depending on your deployment platform. You should avoid `index.html` where possible to avoid conflicting with a prerendered homepage. +To create a [single page app (SPA)](single-page-apps) you must specify the name of the fallback page to be generated by SvelteKit, which is used as the entry point for URLs that have not been prerendered. This is commonly `200.html`, but can vary depending on your deployment platform. You should avoid `index.html` where possible to avoid conflicting with a prerendered homepage. > This option has large negative performance and SEO impacts. It is only recommended in certain circumstances such as wrapping the site in a mobile app. See the [single page apps](single-page-apps) documentation for more details and alternatives. @@ -102,7 +104,7 @@ You'll also want to generate a fallback `404.html` page to replace the default 4 A config for GitHub Pages might look like the following: ```js -// @errors: 2322 +// @errors: 2307 2322 /// file: svelte.config.js import adapter from '@sveltejs/adapter-static'; diff --git a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/55-single-page-apps.md b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/55-single-page-apps.md index 4210a1b5ed..b8e7d5a226 100644 --- a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/55-single-page-apps.md +++ b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/55-single-page-apps.md @@ -20,6 +20,7 @@ export const ssr = false; If you don't have any server-side logic (i.e. `+page.server.js`, `+layout.server.js` or `+server.js` files) you can use [`adapter-static`](adapter-static) to create your SPA. Install `adapter-static` with `npm i -D @sveltejs/adapter-static` and add it to your `svelte.config.js` with the `fallback` option: ```js +// @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-static'; diff --git a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/60-adapter-cloudflare.md b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/60-adapter-cloudflare.md index 27eef1690a..eb8882852d 100644 --- a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/60-adapter-cloudflare.md +++ b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/60-adapter-cloudflare.md @@ -18,6 +18,7 @@ This adapter will be installed by default when you use [`adapter-auto`](adapter- Install with `npm i -D @sveltejs/adapter-cloudflare`, then add the adapter to your `svelte.config.js`: ```js +// @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-cloudflare'; diff --git a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/80-adapter-netlify.md b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/80-adapter-netlify.md index 68befc3715..549c600d25 100644 --- a/apps/svelte.dev/content/docs/kit/25-build-and-deploy/80-adapter-netlify.md +++ b/apps/svelte.dev/content/docs/kit/25-build-and-deploy/80-adapter-netlify.md @@ -12,6 +12,7 @@ This adapter will be installed by default when you use [`adapter-auto`](adapter- Install with `npm i -D @sveltejs/adapter-netlify`, then add the adapter to your `svelte.config.js`: ```js +// @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-netlify'; @@ -54,6 +55,7 @@ New projects will use the current Node LTS version by default. However, if you'r SvelteKit supports [Netlify Edge Functions](https://docs.netlify.com/build/edge-functions/overview/). If you pass the option `edge: true` to the `adapter` function, server-side rendering will happen in a Deno-based edge function that's deployed close to the site visitor. If set to `false` (the default), the site will deploy to Node-based Netlify Functions. ```js +// @errors: 2307 /// file: svelte.config.js import adapter from '@sveltejs/adapter-netlify'; diff --git a/apps/svelte.dev/content/docs/kit/30-advanced/68-observability.md b/apps/svelte.dev/content/docs/kit/30-advanced/68-observability.md index 24b41f3b80..cddc4ce5c9 100644 --- a/apps/svelte.dev/content/docs/kit/30-advanced/68-observability.md +++ b/apps/svelte.dev/content/docs/kit/30-advanced/68-observability.md @@ -75,6 +75,7 @@ To view your first trace, you'll need to set up a local collector. We'll use [Ja - Create `src/instrumentation.server.js` with the following: ```js +// @errors: 2307 /// file: src/instrumentation.server.js import { NodeSDK } from '@opentelemetry/sdk-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; @@ -98,4 +99,4 @@ Now, server-side requests will begin generating traces, which you can view in Ja ## `@opentelemetry/api` -SvelteKit uses `@opentelemetry/api` to generate its spans. This is declared as an optional peer dependency so that users not needing traces see no impact on install size or runtime performance. In most cases, if you're configuring your application to collect SvelteKit's spans, you'll end up installing a library like `@opentelemetry/sdk-node` or `@vercel/otel`, which in turn depend on `@opentelemetry/api`, which will satisfy SvelteKit's dependency as well. If you see an error from SvelteKit telling you it can't find `@opentelemetry/api`, it may just be because you haven't set up your trace collection yet. If you _have_ done that and are still seeing the error, you can install `@opentelemetry/api` yourself. +SvelteKit uses `@opentelemetry/api` to generate its spans. This is declared as an optional peer dependency so that users not needing traces see no impact on install size or runtime performance. In most cases, if you're configuring your application to collect SvelteKit's spans, you'll end up installing a library like `@opentelemetry/sdk-node` or `@vercel/otel`, which in turn depend on `@opentelemetry/api`, which will satisfy SvelteKit's dependency as well. If you see an error from SvelteKit telling you it can't find `@opentelemetry/api`, it may just be because you haven't set up your trace collection yet. If you _have_ done that and are still seeing the error, you can install `@opentelemetry/api` yourself. diff --git a/apps/svelte.dev/content/docs/kit/40-best-practices/10-accessibility.md b/apps/svelte.dev/content/docs/kit/40-best-practices/10-accessibility.md index 655f9a82df..12357186c0 100644 --- a/apps/svelte.dev/content/docs/kit/40-best-practices/10-accessibility.md +++ b/apps/svelte.dev/content/docs/kit/40-best-practices/10-accessibility.md @@ -66,12 +66,13 @@ If your content is available in multiple languages, you should set the `lang` at ```js /// file: src/hooks.server.js -/** - * @param {import('@sveltejs/kit').RequestEvent} event - */ -function get_lang(event) { +// @filename: utils.ts +export function get_lang(event: import('@sveltejs/kit').RequestEvent) { return 'en'; } + +// @filename: hooks.server.js +import { get_lang } from './utils'; // ---cut--- /** @type {import('@sveltejs/kit').Handle} */ export function handle({ event, resolve }) { diff --git a/apps/svelte.dev/src/lib/server/renderer.ts b/apps/svelte.dev/src/lib/server/renderer.ts index 59b4373126..e286623e3f 100644 --- a/apps/svelte.dev/src/lib/server/renderer.ts +++ b/apps/svelte.dev/src/lib/server/renderer.ts @@ -45,7 +45,7 @@ export const render_content = ( injected.push( `declare module '$env/dynamic/private' { export const env: Record }`, `declare module '$env/dynamic/public' { export const env: Record }`, - `declare module '$env/static/private' { export const API_KEY: string }`, + `declare module '$env/static/private' { export const API_KEY: string; export const VERCEL_COMMIT_REF: string }`, `declare module '$env/static/public' { export const PUBLIC_BASE_URL: string }` ); } @@ -56,8 +56,10 @@ export const render_content = ( `import type * as Kit from '@sveltejs/kit';`, `export type PageLoad = Kit.Load>;`, `export type PageServerLoad = Kit.ServerLoad>;`, + `export type PageServerLoadEvent = Parameters[0];`, `export type LayoutLoad = Kit.Load>;`, `export type LayoutServerLoad = Kit.ServerLoad>;`, + `export type LayoutServerLoadEvent = Parameters[0];`, `export type RequestHandler = Kit.RequestHandler>;`, `export type Action = Kit.Action>;`, `export type Actions = Kit.Actions>;`, diff --git a/packages/site-kit/src/lib/docs/Tooltip.svelte b/packages/site-kit/src/lib/docs/Tooltip.svelte index 42cb9ac555..1b58d3aeee 100644 --- a/packages/site-kit/src/lib/docs/Tooltip.svelte +++ b/packages/site-kit/src/lib/docs/Tooltip.svelte @@ -95,7 +95,7 @@ font: var(--sk-font-body-small); } - .tags { + .twoslash-popup-docs-tags { display: grid; grid-template-columns: auto 1fr; column-gap: 1rem; @@ -105,10 +105,6 @@ .param { font: var(--sk-font-mono); } - - .tag { - min-width: 8rem; - } } /* Disable highlight styles inside tooltips (popup content) */ diff --git a/packages/site-kit/src/lib/markdown/renderer.ts b/packages/site-kit/src/lib/markdown/renderer.ts index e3ba7a4a58..bf5fee6978 100644 --- a/packages/site-kit/src/lib/markdown/renderer.ts +++ b/packages/site-kit/src/lib/markdown/renderer.ts @@ -449,7 +449,12 @@ export async function render_content_markdown( [, prelude = '// ---cut---\n', source] = match; const banner = twoslashBanner?.(filename, source); - if (banner) prelude = '// @filename: injected.d.ts\n' + banner + '\n' + prelude; + if (banner) + prelude = + '// @filename: injected.d.ts\n' + + banner + + (options.file ? `\n// @filename: ${options.file.split('/').pop()}\n` : '\n') + + prelude; } source = source.replace( @@ -1130,7 +1135,7 @@ async function syntax_highlight({ const redactions: string[] = []; const sub = delimiter_substitutes['---']; - const pattern = new RegExp(`${sub}(?:[^ ]|[^ ][^]+?[^ ])${sub}`, 'g'); + const pattern = new RegExp(`${sub}([^ ]|[^ ][^]+?[^ ])${sub}`, 'g'); const redacted = source.replace(pattern, (_, content) => { redactions.push(content); @@ -1166,7 +1171,7 @@ async function syntax_highlight({ html = html.replace( new RegExp(` {${delimiter_substitutes['---'].length + 1},}`, 'g'), - () => redactions.shift()! + () => `${redactions.shift()!}` ); if (check) { @@ -1206,7 +1211,17 @@ async function syntax_highlight({ for (const match of html.matchAll( /([^]+?)<\/span>([^]+?)<\/span><\/span>/g )) { + const start = match.index; + const end = match.index + match[0].length; + const tag = match[1]; + + if (tag === '@type') { + // remove `@type` tags altogether + replacements.push({ start, end, content: '' }); + continue; + } + let value = match[2]; let content = `
${tag}
`; @@ -1234,11 +1249,7 @@ async function syntax_highlight({ content += '
'; - replacements.push({ - start: match.index, - end: match.index + match[0].length, - content: '
' + content + '
' - }); + replacements.push({ start, end, content }); } while (replacements.length > 0) { @@ -1246,6 +1257,9 @@ async function syntax_highlight({ html = html.slice(0, start) + content + html.slice(end); } + // if no tags, remove this
to avoid an unnecessary flex gap + html = html.replace('
', ''); + html = injectReferenceLinks(html, references, extractImportedSymbols(source)); } } catch (e) {