Merge remote-tracking branch 'origin/master' into feat/copy-code-button

pull/8995/head
Puru 3 years ago
commit e5db07c1c1

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: css sourcemap generation with unicode filenames

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: head duplication when binding is present

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: take custom attribute name into account when reflecting property

@ -46,7 +46,7 @@ For all the patches and performance updates from this month, check out the [Svel
**Learning Resources** **Learning Resources**
_Featuring Svelte Contributors and Ambassadors_ _Featuring Svelte Contributors and Ambassadors_
- [Exploring Svelte 4 w/ Kevin AK: Performance, Compatibility, & Web Component Support | Modern Web Pod](https://www.youtube.com/watch?v=YOL0HGGVib4) by This Dot Media - [Exploring Svelte 4 w/ Kevin AK: Performance, Compatibility, & Web Component Support | Modern Web Pod](https://www.youtube.com/watch?v=YOL0HGGVib4) by This Dot Media
- [Svelte Sirens Stream Design Systems: Lessons Learned](https://www.youtube.com/live/YHZaiIGSqsE?feature=share) featuring Eric Liu creator of Carbon Components Svelte and Svelde the docgen library - [Svelte Sirens Stream Design Systems: Lessons Learned](https://www.youtube.com/live/YHZaiIGSqsE?feature=share) featuring Eric Liu, creator of Carbon Components Svelte and the `sveld` docgen library
- This Week in Svelte: - This Week in Svelte:
- [2023 June 30](https://www.youtube.com/watch?v=sDz4_BLoYQ4) - Svelte 4.0.1, SK 1.21, lists, screen readers, loading - [2023 June 30](https://www.youtube.com/watch?v=sDz4_BLoYQ4) - Svelte 4.0.1, SK 1.21, lists, screen readers, loading
- [2023 July 7](https://www.youtube.com/watch?v=0tq1ph4DDFA) - Svelte 4.0.5, Kit 1.22.1, Svelte 5, local storage and markdown - [2023 July 7](https://www.youtube.com/watch?v=0tq1ph4DDFA) - Svelte 4.0.5, Kit 1.22.1, Svelte 5, local storage and markdown

@ -0,0 +1,264 @@
---
title: Unlocking view transitions in SvelteKit 1.24
description: Streamlined page transitions with onNavigate
author: Geoff Rich
authorURL: https://geoffrich.net
---
The [view transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/) has been sweeping the web development world lately, and for good reason. It streamlines the process of animating between two page states, which is especially useful for page transitions.
However, until now, you couldnt easily use this API in a SvelteKit app, since it was difficult to slot into the right place in the navigation lifecycle. SvelteKit 1.24 brought a new [`onNavigate`](https://kit.svelte.dev/docs/modules#$app-navigation-onnavigate) lifecycle hook to make view transitions integration much easier lets dive in.
## How view transitions work
You can trigger a view transition by calling `document.startViewTransition` and passing a callback that updates the DOM somehow. For our purposes today, SvelteKit will update the DOM as the user navigates. Once the callback finishes, the browser will transition to the new page state — by default, it does a crossfade between the old and the new states.
```js
// @errors: 2339
const domUpdate = async () => {};
// ---cut---
document.startViewTransition(async () => {
await domUpdate(); // mock function for demonstration purposes
});
```
Behind the scenes, the browser does something really clever. When the transition starts, it captures the current state of the page and takes a screenshot. It then holds that screenshot in place while the DOM is updating. Once the DOM has finished updating, it captures the new state, and animates between the two states.
While its only implemented in Chrome (and other Chromium-based browsers) for now, [WebKit is also in favor](https://github.com/WebKit/standards-positions/issues/48#issuecomment-1679760489) of it. Even if youre on an unsupported browser, its a perfect candidate for progressive enhancement since we can always fall back to a non-animated navigation.
Its important to note that view transitions is a browser API, not a SvelteKit one. `onNavigate` is the only SvelteKit-specific API well use today. Everything else can be used wherever you write for the web! For more on the view transitions API, I highly recommend the [Chrome explainer](https://developer.chrome.com/docs/web-platform/view-transitions/) by Jake Archibald.
## How `onNavigate` works
Before learning how to write view transitions, let's highlight the function that makes it all possible: [`onNavigate`](https://kit.svelte.dev/docs/modules#$app-navigation-onnavigate).
Until recently, SvelteKit had two navigation lifecycle functions: [`beforeNavigate`](https://kit.svelte.dev/docs/modules#$app-navigation-beforenavigate), which fires before a navigation starts, and [`afterNavigate`](https://kit.svelte.dev/docs/modules#$app-navigation-afternavigate), which fires after the page has been updated following a navigation. SvelteKit 1.24 introduces a third: `onNavigate`, which will fire on every navigation, immediately before the new page is rendered. Importantly, it will run _after_ any data loading for the page has completed since starting a view transition prevents any interaction with the page, we want to start it as late as possible.
You can also return a promise from `onNavigate`, which will suspend the navigation until it resolves. This will let us wait to complete the navigation until the view transition has started.
```js
// @errors: 2304 7006
function delayNavigation() {
return new Promise((res) => setTimeout(res, 100));
}
onNavigate(async (navigation) => {
// do some work immediately before the navigation completes
// optionally return a promise to delay navigation until it resolves
return delayNavigation();
});
```
With that out of the way, let's see how you can use view transitions in your SvelteKit app.
## Getting started with view transitions
The best way to see view transitions in action is to try it yourself. You can spin up the SvelteKit demo app by running `npm create svelte@latest` in your local terminal, or in your browser on [StackBlitz](https://sveltekit.new). Make sure to use a browser that supports the view transitions API. Once you have the app running, add the following to the script block in `src/routes/+layout.svelte`.
```js
// @errors: 2305 7006 2339 2810
import { onNavigate } from '$app/navigation';
onNavigate((navigation) => {
if (!document.startViewTransition) return;
return new Promise((resolve) => {
document.startViewTransition(async () => {
resolve();
await navigation.complete;
});
});
});
```
With that, every navigation that occurs will trigger a view transition. You can already see this in action by default, the browser will crossfade between the old and new pages.
<video src="https://sveltejs.github.io/assets/video/vt-demo-1.mp4" controls muted playsinline></video>
<details>
<summary>How the code works</summary>
This code may look a bit intimidating if you're curious, I can break it down line-by-line, but for now its enough to know that adding it will allow you to interact with the view transitions API during navigation.
As mentioned above, the `onNavigate` callback will run immediately before the new page is rendered after a navigation. Inside the callback, we check if `document.startViewTransition` exists. If it doesnt (i.e. the browser doesnt support it), we exit early.
We then return a promise to delay completing the navigation until the view transition has started. We use a [promise constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) so that we can control when the promise resolves.
```js
// @errors: 1108
return new Promise((resolve) => {
document.startViewTransition(async () => {
resolve();
await navigation.complete;
});
});
```
Inside the promise constructor, we start the view transition. Inside the view transition callback we resolve the promise we just returned, which indicates to SvelteKit that it should finish the navigation. Its important that the navigation waits to finish until _after_ we start the view transition the browser needs to snapshot the old state so it can transition to the new state.
Finally, inside the view transition callback we wait for SvelteKit to finish the navigation by awaiting `navigation.complete`. Once `navigation.complete` resolves, the new page has been loaded into the DOM and the browser can animate between the two states.
Its a bit of a mouthful, but by not abstracting it we allow you to interact with the view transition directly and make any customizations you require.
</details>
## Customizing the transition with CSS
We can also customize this page transition using CSS animation. In the style block of your `+layout.svelte`, add the following CSS rules.
```css
@keyframes fade-in {
from {
opacity: 0;
}
}
@keyframes fade-out {
to {
opacity: 0;
}
}
@keyframes slide-from-right {
from {
transform: translateX(30px);
}
}
@keyframes slide-to-left {
to {
transform: translateX(-30px);
}
}
:root::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out, 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
:root::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms cubic-bezier(0.4, 0, 0.2, 1) both
slide-from-right;
}
```
Now when you navigate between pages, the old page will fade out and slide to the left, and the new page will fade in and slide from the right. These particular animation styles come from Jake Archibalds excellent [Chrome Developers article on view transitions](https://developer.chrome.com/docs/web-platform/view-transitions/), which is well worth a read if you want to understand everything you can do with this API.
Note that we have to add `:root` before the `::view-transition` pseudoelements these elements are only on the root of the document, so we dont want Svelte to [scope them](/docs/svelte-components#style) to the component.
You might have noticed that the entire page slides in and out, even though the header is the same on both the old and new page. To make for a smoother transition, we can give the header a unique `view-transition-name` so that it is animated separately from the rest of the page. In `src/routes/Header.svelte`, find the `header` CSS selector in the style block and add a view transition name.
```css
header {
display: flex;
justify-content: space-between;
view-transition-name: header;
}
```
Now, the header will not transition in and out on navigation, but the rest of the page will.
<video src="https://sveltejs.github.io/assets/video/vt-demo-2.mp4" controls muted playsinline></video>
<details>
<summary>Fixing the types</summary>
Since `startViewTransition` is not supported by all browsers, your IDE may not know that it exists. To make the errors go away and get the correct typings, add the following to your `app.d.ts`:
```ts
declare global {
// preserve any customizations you have here
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
// add these lines
interface ViewTransition {
updateCallbackDone: Promise<void>;
ready: Promise<void>;
finished: Promise<void>;
skipTransition: () => void;
}
interface Document {
startViewTransition(updateCallback: () => Promise<void>): ViewTransition;
}
}
export {};
```
</details>
## Transitioning individual elements
We just saw how giving an element a `view-transition-name` separates it out from the rest of the page's animation. Setting a `view-transition-name` also instructs the browser to smoothly animate it to its new position after the transition completes. The `view-transition-name` acts as a unique identifier so the browser can identify matching elements from the old and new states.
Lets see what that looks like our demo apps navigation has a small triangle indicating the active page. Right now, it abruptly appears in the new position after we navigate. Lets give it a `view-transition-name` so the browser animates it to its new position instead.
Inside `src/routes/Header.svelte`, find the CSS rule creating the active page indicator and give it a `view-transition-name`:
```css
li[aria-current='page']::before {
/* other existing rules */
view-transition-name: active-page;
}
```
By adding that single line, the indicator will now smoothly slide to its new position instead of jumping.
<video src="https://sveltejs.github.io/assets/video/vt-demo-3.mp4" controls muted playsinline></video>
(It might be easy to miss the difference look at the small moving triangle indicator at the top of the screen!)
## Reduced motion
Its important to respect our users [motion preferences](https://web.dev/prefers-reduced-motion/) while implementing animation on the web. Just because you can implement an extreme page transition doesnt mean you should. To disable all page transitions for users who prefer reduced motion, you can add the following to the global `styles.css`:
```css
@media (prefers-reduced-motion) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
```
While this may be the safest option, reduced motion does not necessarily mean no animation. Instead, you could consider your view transitions on a case-by-case basis. For instance, maybe we disable the sliding animation, but leave the default crossfade (which doesnt involve motion). You can do so by wrapping the `::view-transition` rules you want to disable in a `prefers-reduced-motion: no-preference` media-query:
```css
@media (prefers-reduced-motion: no-preference) {
:root::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out, 300ms cubic-bezier(0.4, 0, 0.2, 1) both
slide-to-left;
}
:root::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms cubic-bezier(
0.4,
0,
0.2,
1
) both slide-from-right;
}
}
```
## Whats next?
As you can see, SvelteKit doesnt abstract a whole lot about _how_ view transitions work youre interacting directly with the browsers built-in `document.startViewTransition` and `::view-transition` APIs, rather than framework abstractions like those found in Nuxt and Astro. Were eager to see how people end up using view transitions in SvelteKit apps, and whether it makes sense to add higher level abstractions of our own in future.
## Resources
You can find the demo code from this post [on GitHub](https://github.com/geoffrich/sveltekit-onnavigate-demo) and the live version [deployed to Vercel](https://sveltekit-onnavigate-demo.vercel.app/). Here are some other view transitions resources you may find helpful:
- [MDN view transitions docs](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
- [Chrome view transitions API explainer](https://developer.chrome.com/docs/web-platform/view-transitions/)
- [Rich Harris demoing view transitions with onNavigate](https://www.youtube.com/shorts/weOCWOD2UIo)
- [My Svelte Summit video showing how to use view transitions for FLIP animations](https://youtu.be/K95TQ-Yh7Cw)
- [Fruit list demo](https://sveltekit-shared-element-transitions-codelab.vercel.app/fruits) ([source](https://github.com/geoffrich/sveltekit-view-transitions))
- [Svelte Summit video list demo](https://http-203-svelte.vercel.app/) (based on a [Jake Archibald demo](https://http203-playlist.netlify.app/)) ([source](https://github.com/geoffrich/http-203-svelte))

@ -0,0 +1,97 @@
---
title: "What's new in Svelte: September 2023"
description: "New parameters in SvelteKit's redirect and an onNavigate lifecycle function come to life"
author: Dani Sandoval
authorURL: https://dreamindani.com
---
Happy September y'all! With all the [sneak peeks at what's coming soon in Svelte 5](https://twitter.com/Rich_Harris/status/1688581184018583558), we thought it'd be best to look back at the last month to see what's shipped and what the community is building with Svelte.
Before we jump in, a warm welcome to the new Svelte Ambassadors: [@cainux](https://github.com/cainux) and [@grischaerbe](https://github.com/grischaerbe)! Welcome to the crew ⛴️
## What's new in Svelte & Language Tools
- `svelteHTML` has moved from language-tools into Svelte core so that `svelte/element` types will now load correctly (**4.2.0** in Svelte, **107.10.0** in Language Tools)
## What's new in SvelteKit
- `URL` is now accepted in the `redirect` function (**1.23.0**, [Docs](https://kit.svelte.dev/docs/modules#sveltejs-kit-redirect), [#10570](https://github.com/sveltejs/kit/pull/10570))
- Mistyped route filenames will now throw a warning (**1.23.0**, [#10558](https://github.com/sveltejs/kit/pull/10558))
- The new `onNavigate` lifecycle function enables view transitions - Check out the [blog post](https://svelte.dev/blog/view-transitions) for more info (**1.24.0**, [Docs](https://kit.svelte.dev/docs/modules#app-navigation-onnavigate), [#9605](https://github.com/sveltejs/kit/pull/9605))
But that's just the new features! For all the patches and performance updates from this month, check out the [SvelteKit CHANGELOG](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md). You can also find adapter-specific CHANGELOGs in each of [the `adapter` directories](https://github.com/sveltejs/kit/tree/master/packages).
---
## Community Showcase
**Apps & Sites built with Svelte**
- [Planet Of The Bugs](https://planetofthebugs.xyz/) allows developers to practice and hone their skill-sets by exposing them to an endless supply of unique, curated issues and bugs from popular open-source projects on Github
- [Minesweeper](https://github.com/ProductionPanic/minesweeper/tree/main) is an Android game built with SvelteKit, Capacitor, TailwindCSS and DaisyUI (check it out on the [Google Play Store](https://play.google.com/store/apps/details?id=com.production.panic.minesweeper&pli=1))
- [Pendor](https://www.pendor.ai/) is an AI component generator for Svelte
- [Avatars Pro](https://senja.io/testimonial-widgets/avatars-pro) is a social proof widget made for the web
- [Pomodoro Focus](https://github.com/con-dog/pomodoro-focus) is a pomodoro timer browser extension
- [memegen](https://github.com/bhupeshpr25/memegen) is a Firefox web extension that allows users to generate memes using various templates
- [Resgen](https://resgen.app/) is a Chrome extension that tailors resumes based on job descriptions and your experiences
- [Icono Search](https://www.icono-search.com) is an AI-powered video search engine
- [digital-paper](https://github.com/danferns/digital-paper) is a writing app with no backspace or undo
- [Ubuntu 22.04 in Svelte](https://github.com/manhhungpc/ubuntu2204-svelte) aims to replicate the Ubuntu 22.04 desktop experience on the web
- [My Queue](https://www.myqueue.so/) creates a playlist of written articles by turning them into audio stories
**Learning Resources**
_Featuring Svelte Contributors and Ambassadors_
- [Svelte Society - London August 2023](https://www.youtube.com/watch?v=90Psdk5rAnU)
- [Building a Blog using SvelteKit and Nostr as a CMS (Part 1](https://kevinak.se/blog/building-a-blog-using-sveltekit-and-nostr-as-a-cms-part-1-1690807337563)) by Kev
- [Mastering SvelteKit with Geoff Rich | JS Drops](https://www.youtube.com/watch?v=MaF8kRbHbi0) by This Dot Media
- [Using GitHub Contributions To Flex On The Normies](https://youtu.be/f9fd1L1FEts?si=3hbihW-X5-GKSJxN), [Learn Svelte By Making A Matching Game](https://www.youtube.com/watch?v=w2q9caYXgkg) and [Who Needs API Permission When You Can Use Web Scraping](https://www.youtube.com/watch?v=T-lBPpeokfY) by Joy of Code
- [The missing guide to understanding adapter-static in SvelteKit](https://khromov.se/the-missing-guide-to-understanding-adapter-static-in-sveltekit/) by Stanislav Khromov
- This Week in Svelte:
- [2023 July 28](https://www.youtube.com/watch?v=mvTEQ_C0qRQ) - Screen reader market share, Svelte to plain JS, Web Components
- [2023 Aug 4](https://www.youtube.com/watch?v=Ye8cCJyPZjg) - Svelte 4.1.2, SvelteKit 1.22.4, ES Modules, Types in markup
- [2023 August 11](https://www.youtube.com/watch?v=A8XUaiCVkCI) - Svelte 4.2.0, SvelteKit 1.22.5, How to create Toggle Switches
- [2023 August 18](https://www.youtube.com/watch?v=nJ5Wf3uL7dM) - SvelteKit 1.22.6, accessible form error summaries
- [2023 August 25](https://www.youtube.com/watch?v=JoPzvlBKXXE) - SvelteKit 1.23.0, Bun and SvelteKit, Enhanced search
- Svienna (Svelte Society Vienna) Sessions
- [Ermin Celikovic - You might not need a slider library](https://www.youtube.com/watch?v=dSUmtijkFOc)
- [Lukas Stracke - How to use sentry.io in your SvelteKit App](https://www.youtube.com/watch?v=u41-MtPGH04)
- [Jean-Yves Couet - SvelteKit & Remult... fullstack apps in minutes!](https://www.youtube.com/watch?v=N8d290fTzq8)
- Sirens Sessions
- [Prismic Slice Machines & SvelteKit](https://www.youtube.com/watch?v=19Meb-yMsAg) with Sam Littlefair
- [Medusa and SvelteKit E-Commerce Stack](https://www.youtube.com/watch?v=rVVHxows9dY) with Lacey Pevey
- [Design Systems: Lessons Learned](https://www.youtube.com/watch?v=YHZaiIGSqsE) with Eric Liu
_To Watch_
- [Image optimization in SvelteKit with vite-imagetools](https://www.youtube.com/watch?v=285vSLe9LQ8) by hartenfellerdev
- [Building a Todo App with Rust and SvelteKit: Complete Tutorial](https://www.youtube.com/watch?v=w7is2bCTUg0) and [Stripe Payment In SvelteKit With Dynamic Pricing](https://www.youtube.com/watch?v=o8gvCLgz1vs) by SvelteRust
- [Leaflet maps in SvelteKit like it's 2023 (HowTo)](https://www.youtube.com/watch?v=JFctWXEzFZw)
ShipBit
_To Read_
- [Internationalization in SvelteKit (Series)](https://blog.aakashgoplani.in/series/i18n-in-sveltekit) by Aakash Goplani
- [The easiest Chatbot you will ever build](https://simon-prammer.vercel.app/blog/post/sveltekit-langchain) and [Intro to LangSmith🦜🛠](https://simon-prammer.vercel.app/blog/post/langsmith) by Simon Prammer
- [SvelteKit: How to make code-based router, instead of file-based router [August 2023]](https://dev.to/maxcore/sveltekit-how-to-make-code-based-router-instead-of-file-based-router-august-2023-5f9) by Max Core
- [SvelteKit Hydration Gotcha](https://www.captaincodeman.com/sveltekit-hydration-gotcha) by Captain Codeman
- [Automatically generate sitemap.xml in SvelteKit](https://alex-schnabl.medium.com/automatically-generate-sitemap-xml-in-sveltekit-910bd09d17e7) by Alex Schnabl
- [Discovering Svelte: Things I Learned While Using Svelte](https://www.tronic247.com/discovering-svelte-things-i-learned-while-using-svelte/) by Posandu Mapa
- [Typed fetch with Sveltekit and Hono using RPC](https://dev.to/subhendupsingh/typed-fetch-with-sveltekit-and-hono-using-rpc-2clf) by Subhendu Pratap Singh
- [Svelte Context Module Scripts Explained](https://raqueebuddinaziz.com/blog/svelte-context-module-scripts-explained) by raqueebuddin aziz
- [Building with GPT4 and Svelte](https://kvak.io/meoweler) by levmiseri
- [Type-safe User Authentication in SvelteKit with Lucia, Planetscale, and Upstash Redis](https://upstash.com/blog/lucia-sveltekit) by Chris Jayden
- [Document Svelte Projects with HTML and JSDoc Comments](https://blog.robino.dev/posts/doc-comments-svelte) by Ross Robino
**Libraries, Tools & Components**
- [Carta](https://github.com/BearToCode/carta-md) is a lightweight, fast and extensible Svelte Markdown editor and viewer, based on Marked
- [Threlte](https://threlte.xyz/), the 3D framework built from Svelte and Three.js has released version 6
- [vite-plugin-web-extension](https://vite-plugin-web-extension.aklinker1.io/guide/frontend-frameworks.html#svelte-integration) works great with Svelte to make building browser extensions easier
- [Salvia-kit Svelte Dashboards](https://github.com/salvia-kit/svelte-dashboards) contains 10 free dashboard templates for SvelteKit
- [drab](https://github.com/rossrobino/drab) is an Unstyled Svelte component library
- [svelte-img-previewer](https://www.npmjs.com/package/svelte-img-previewer?activeTab=readme) is a tool for displaying images from input file types in Svelte
- [sveltekit-search-params](https://github.com/paoloricciuti/sveltekit-search-params) describes itself as the fastest way to read AND write from query search params in SvelteKit
That's it for this month! Feel free to let us know if we missed anything on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.gg/svelte).
Until next time 👋

@ -21,7 +21,7 @@ SvelteKit will handle calling [the Svelte compiler](https://www.npmjs.com/packag
### Alternatives to SvelteKit ### Alternatives to SvelteKit
If you don't want to use SvelteKit for some reason, you can also use Svelte with Vite (but without SvelteKit) by running `npm init vite` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS and CSS files inside the `dist` directory. In most cases, you will probably need to [choose a routing library](/faq#is-there-a-router) as well. If you don't want to use SvelteKit for some reason, you can also use Svelte with Vite (but without SvelteKit) by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS and CSS files inside the `dist` directory. In most cases, you will probably need to [choose a routing library](/faq#is-there-a-router) as well.
Alternatively, there are [plugins for all the major web bundlers](https://sveltesociety.dev/tools#bundling) to handle Svelte compilation — which will output `.js` and `.css` that you can insert into your HTML — but most others won't handle SSR. Alternatively, there are [plugins for all the major web bundlers](https://sveltesociety.dev/tools#bundling) to handle Svelte compilation — which will output `.js` and `.css` that you can insert into your HTML — but most others won't handle SSR.

@ -56,8 +56,9 @@ All other attributes are included unless their value is [nullish](https://develo
An expression might include characters that would cause syntax highlighting to fail in regular HTML, so quoting the value is permitted. The quotes do not affect how the value is parsed: An expression might include characters that would cause syntax highlighting to fail in regular HTML, so quoting the value is permitted. The quotes do not affect how the value is parsed:
<!-- prettier-ignore -->
```svelte ```svelte
<button disabled={number !== 42}>...</button> <button disabled="{number !== 42}">...</button>
``` ```
When the attribute name and value match (`name={name}`), they can be replaced with `{name}`. When the attribute name and value match (`name={name}`), they can be replaced with `{name}`.

@ -143,6 +143,26 @@ declare namespace svelteHTML {
Then make sure that `d.ts` file is referenced in your `tsconfig.json`. If it reads something like `"include": ["src/**/*"]` and your `d.ts` file is inside `src`, it should work. You may need to reload for the changes to take effect. Then make sure that `d.ts` file is referenced in your `tsconfig.json`. If it reads something like `"include": ["src/**/*"]` and your `d.ts` file is inside `src`, it should work. You may need to reload for the changes to take effect.
Since Svelte version 4.2 / `svelte-check` version 3.5 / VS Code extension version 107.10.0 you can also declare the typings by augmenting the `svelte/elements` module like this:
```ts
/// file: additional-svelte-typings.d.ts
import { HTMLButtonAttributes } from 'svelte/elements'
declare module 'svelte/elements' {
export interface SvelteHTMLElements {
'custom-button': HTMLButtonAttributes;
}
// allows for more granular control over what element to add the typings to
export interface HTMLButtonAttributes {
'veryexperimentalattribute'?: string;
}
}
export {}; // ensure this is not an ambient module, else types will be overridden instead of augmented
```
## Experimental advanced typings ## Experimental advanced typings
A few features are missing from taking full advantage of TypeScript in more advanced use cases like typing that a component implements a certain interface, explicitly typing slots, or using generics. These things are possible using experimental advanced type capabilities. See [this RFC](https://github.com/dummdidumm/rfcs/blob/ts-typedefs-within-svelte-components/text/ts-typing-props-slots-events.md) for more information on how to make use of them. A few features are missing from taking full advantage of TypeScript in more advanced use cases like typing that a component implements a certain interface, explicitly typing slots, or using generics. These things are possible using experimental advanced type capabilities. See [this RFC](https://github.com/dummdidumm/rfcs/blob/ts-typedefs-within-svelte-components/text/ts-typing-props-slots-events.md) for more information on how to make use of them.

@ -68,6 +68,10 @@
</div> </div>
<style> <style>
:root {
scrollbar-gutter: stable;
}
.easing-vis { .easing-vis {
display: flex; display: flex;
max-height: 95%; max-height: 95%;

@ -74,18 +74,14 @@
ul { ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
display: flex; display: grid;
flex-direction: column; grid-template-columns: 1fr;
align-items: flex-start; gap: 3px;
font-size: 18px; font-size: 18px;
} }
li { li {
padding: 5px 10px; display: grid;
background: #eee;
border-radius: 2px;
margin: 3px 0;
cursor: pointer;
} }
li:hover { li:hover {
@ -93,9 +89,16 @@
color: white; color: white;
} }
.selected { button {
border: none;
border-radius: 2px;
padding: 2px;
}
.selected > button {
background: #ff3e00; background: #ff3e00;
color: white; color: white;
font-weight: bold;
} }
h3 { h3 {

@ -1,5 +1,11 @@
# svelte # svelte
## 4.2.0
### Minor Changes
- feat: move `svelteHTML` from language-tools into core to load the correct `svelte/element` types ([#9070](https://github.com/sveltejs/svelte/pull/9070))
## 4.1.2 ## 4.1.2
### Patch Changes ### Patch Changes

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "4.1.2", "version": "4.2.0",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"type": "module", "type": "module",
"module": "src/runtime/index.js", "module": "src/runtime/index.js",
@ -19,6 +19,7 @@
"motion.d.ts", "motion.d.ts",
"action.d.ts", "action.d.ts",
"elements.d.ts", "elements.d.ts",
"svelte-html.d.ts",
"README.md" "README.md"
], ],
"exports": { "exports": {

@ -16,7 +16,7 @@ const GLOBAL_TS_PATH = './src/compiler/utils/globals.js';
const SPECIALS = ['global', 'globalThis', 'InternalError', 'process', 'undefined']; const SPECIALS = ['global', 'globalThis', 'InternalError', 'process', 'undefined'];
const get_url = (name) => const get_url = (name) =>
`https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.${name}.d.ts`; `https://raw.githubusercontent.com/microsoft/TypeScript/main/src/lib/${name}.d.ts`;
const extract_name = (split) => split.match(/^[a-zA-Z0-9_$]+/)[0]; const extract_name = (split) => split.match(/^[a-zA-Z0-9_$]+/)[0];
const extract_functions_and_references = (name, data) => { const extract_functions_and_references = (name, data) => {

@ -144,9 +144,13 @@ export default function ssr(component, options) {
? b` ? b`
let $$settled; let $$settled;
let $$rendered; let $$rendered;
let #previous_head = $$result.head;
do { do {
$$settled = true; $$settled = true;
// $$result.head is mutated by the literal expression
// need to reset it if we're looping back to prevent duplication
$$result.head = #previous_head;
${reactive_declarations} ${reactive_declarations}

@ -1,6 +1,6 @@
/** ---------------------------------------------------------------------- /** ----------------------------------------------------------------------
This file is automatically generated by `scripts/globals-extractor.js`. This file is automatically generated by `scripts/globals-extractor.js`.
Generated At: 2023-05-24T13:16:20.777Z Generated At: 2023-08-11T04:11:50.562Z
---------------------------------------------------------------------- */ ---------------------------------------------------------------------- */
export default new Set([ export default new Set([

@ -292,7 +292,18 @@ export function apply_preprocessor_sourcemap(filename, svelte_map, preprocessor_
toUrl: { toUrl: {
enumerable: false, enumerable: false,
value: function toUrl() { value: function toUrl() {
return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString()); let b64 = '';
if (typeof window !== 'undefined' && window.btoa) {
// btoa doesn't support multi-byte characters
b64 = window.btoa(unescape(encodeURIComponent(this.toString())));
} else if (typeof Buffer !== 'undefined') {
b64 = Buffer.from(this.toString(), 'utf8').toString('base64');
} else {
throw new Error(
'Unsupported environment: `window.btoa` or `Buffer` should be present to use toUrl.'
);
}
return 'data:application/json;charset=utf-8;base64,' + b64;
} }
} }
}); });

@ -283,7 +283,7 @@ if (typeof HTMLElement === 'function') {
'toAttribute' 'toAttribute'
); );
if (attribute_value == null) { if (attribute_value == null) {
this.removeAttribute(key); this.removeAttribute(this.$$p_d[key].attribute || key);
} else { } else {
this.setAttribute(this.$$p_d[key].attribute || key, attribute_value); this.setAttribute(this.$$p_d[key].attribute || key, attribute_value);
} }

@ -6,5 +6,5 @@
* https://svelte.dev/docs/svelte-compiler#svelte-version * https://svelte.dev/docs/svelte-compiler#svelte-version
* @type {string} * @type {string}
*/ */
export const VERSION = '4.1.2'; export const VERSION = '4.2.0';
export const PUBLIC_VERSION = '4'; export const PUBLIC_VERSION = '4';

@ -0,0 +1,252 @@
/// <reference lib="dom" />
// This file is deliberately not exposed through the exports map.
// It's meant to be loaded directly by the Svelte language server
/* eslint-disable @typescript-eslint/no-empty-interface */
import * as svelteElements from './elements.js';
/**
* @internal do not use
*/
type HTMLProps<Property extends string, Override> = Omit<
import('./elements.js').SvelteHTMLElements[Property],
keyof Override
> &
Override;
declare global {
/**
* This namespace does not exist in the runtime, it is only used for typings
*/
namespace svelteHTML {
// Every namespace eligible for use needs to implement the following two functions
/**
* @internal do not use
*/
function mapElementTag<K extends keyof ElementTagNameMap>(tag: K): ElementTagNameMap[K];
function mapElementTag<K extends keyof SVGElementTagNameMap>(tag: K): SVGElementTagNameMap[K];
function mapElementTag(tag: any): any; // needs to be any because used in context of <svelte:element>
/**
* @internal do not use
*/
function createElement<Elements extends IntrinsicElements, Key extends keyof Elements>(
// "undefined | null" because of <svelte:element>
element: Key | undefined | null,
attrs: string extends Key ? svelteElements.HTMLAttributes<any> : Elements[Key]
): Key extends keyof ElementTagNameMap
? ElementTagNameMap[Key]
: Key extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[Key]
: any;
function createElement<Elements extends IntrinsicElements, Key extends keyof Elements, T>(
// "undefined | null" because of <svelte:element>
element: Key | undefined | null,
attrsEnhancers: T,
attrs: (string extends Key ? svelteElements.HTMLAttributes<any> : Elements[Key]) & T
): Key extends keyof ElementTagNameMap
? ElementTagNameMap[Key]
: Key extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[Key]
: any;
// For backwards-compatibility and ease-of-use, in case someone enhanced the typings from import('svelte/elements').HTMLAttributes/SVGAttributes
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface HTMLAttributes<T extends EventTarget = any> {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface SVGAttributes<T extends EventTarget = any> {}
/**
* Avoid using this interface directly. Instead use the `SvelteHTMLElements` interface exported by `svelte/elements`
* This should only be used if you need to extend the interface with custom elements
*/
interface IntrinsicElements extends svelteElements.SvelteHTMLElements {
a: HTMLProps<'a', HTMLAttributes>;
abbr: HTMLProps<'abbr', HTMLAttributes>;
address: HTMLProps<'address', HTMLAttributes>;
area: HTMLProps<'area', HTMLAttributes>;
article: HTMLProps<'article', HTMLAttributes>;
aside: HTMLProps<'aside', HTMLAttributes>;
audio: HTMLProps<'audio', HTMLAttributes>;
b: HTMLProps<'b', HTMLAttributes>;
base: HTMLProps<'base', HTMLAttributes>;
bdi: HTMLProps<'bdi', HTMLAttributes>;
bdo: HTMLProps<'bdo', HTMLAttributes>;
big: HTMLProps<'big', HTMLAttributes>;
blockquote: HTMLProps<'blockquote', HTMLAttributes>;
body: HTMLProps<'body', HTMLAttributes>;
br: HTMLProps<'br', HTMLAttributes>;
button: HTMLProps<'button', HTMLAttributes>;
canvas: HTMLProps<'canvas', HTMLAttributes>;
caption: HTMLProps<'caption', HTMLAttributes>;
cite: HTMLProps<'cite', HTMLAttributes>;
code: HTMLProps<'code', HTMLAttributes>;
col: HTMLProps<'col', HTMLAttributes>;
colgroup: HTMLProps<'colgroup', HTMLAttributes>;
data: HTMLProps<'data', HTMLAttributes>;
datalist: HTMLProps<'datalist', HTMLAttributes>;
dd: HTMLProps<'dd', HTMLAttributes>;
del: HTMLProps<'del', HTMLAttributes>;
details: HTMLProps<'details', HTMLAttributes>;
dfn: HTMLProps<'dfn', HTMLAttributes>;
dialog: HTMLProps<'dialog', HTMLAttributes>;
div: HTMLProps<'div', HTMLAttributes>;
dl: HTMLProps<'dl', HTMLAttributes>;
dt: HTMLProps<'dt', HTMLAttributes>;
em: HTMLProps<'em', HTMLAttributes>;
embed: HTMLProps<'embed', HTMLAttributes>;
fieldset: HTMLProps<'fieldset', HTMLAttributes>;
figcaption: HTMLProps<'figcaption', HTMLAttributes>;
figure: HTMLProps<'figure', HTMLAttributes>;
footer: HTMLProps<'footer', HTMLAttributes>;
form: HTMLProps<'form', HTMLAttributes>;
h1: HTMLProps<'h1', HTMLAttributes>;
h2: HTMLProps<'h2', HTMLAttributes>;
h3: HTMLProps<'h3', HTMLAttributes>;
h4: HTMLProps<'h4', HTMLAttributes>;
h5: HTMLProps<'h5', HTMLAttributes>;
h6: HTMLProps<'h6', HTMLAttributes>;
head: HTMLProps<'head', HTMLAttributes>;
header: HTMLProps<'header', HTMLAttributes>;
hgroup: HTMLProps<'hgroup', HTMLAttributes>;
hr: HTMLProps<'hr', HTMLAttributes>;
html: HTMLProps<'html', HTMLAttributes>;
i: HTMLProps<'i', HTMLAttributes>;
iframe: HTMLProps<'iframe', HTMLAttributes>;
img: HTMLProps<'img', HTMLAttributes>;
input: HTMLProps<'input', HTMLAttributes>;
ins: HTMLProps<'ins', HTMLAttributes>;
kbd: HTMLProps<'kbd', HTMLAttributes>;
keygen: HTMLProps<'keygen', HTMLAttributes>;
label: HTMLProps<'label', HTMLAttributes>;
legend: HTMLProps<'legend', HTMLAttributes>;
li: HTMLProps<'li', HTMLAttributes>;
link: HTMLProps<'link', HTMLAttributes>;
main: HTMLProps<'main', HTMLAttributes>;
map: HTMLProps<'map', HTMLAttributes>;
mark: HTMLProps<'mark', HTMLAttributes>;
menu: HTMLProps<'menu', HTMLAttributes>;
menuitem: HTMLProps<'menuitem', HTMLAttributes>;
meta: HTMLProps<'meta', HTMLAttributes>;
meter: HTMLProps<'meter', HTMLAttributes>;
nav: HTMLProps<'nav', HTMLAttributes>;
noscript: HTMLProps<'noscript', HTMLAttributes>;
object: HTMLProps<'object', HTMLAttributes>;
ol: HTMLProps<'ol', HTMLAttributes>;
optgroup: HTMLProps<'optgroup', HTMLAttributes>;
option: HTMLProps<'option', HTMLAttributes>;
output: HTMLProps<'output', HTMLAttributes>;
p: HTMLProps<'p', HTMLAttributes>;
param: HTMLProps<'param', HTMLAttributes>;
picture: HTMLProps<'picture', HTMLAttributes>;
pre: HTMLProps<'pre', HTMLAttributes>;
progress: HTMLProps<'progress', HTMLAttributes>;
q: HTMLProps<'q', HTMLAttributes>;
rp: HTMLProps<'rp', HTMLAttributes>;
rt: HTMLProps<'rt', HTMLAttributes>;
ruby: HTMLProps<'ruby', HTMLAttributes>;
s: HTMLProps<'s', HTMLAttributes>;
samp: HTMLProps<'samp', HTMLAttributes>;
slot: HTMLProps<'slot', HTMLAttributes>;
script: HTMLProps<'script', HTMLAttributes>;
section: HTMLProps<'section', HTMLAttributes>;
select: HTMLProps<'select', HTMLAttributes>;
small: HTMLProps<'small', HTMLAttributes>;
source: HTMLProps<'source', HTMLAttributes>;
span: HTMLProps<'span', HTMLAttributes>;
strong: HTMLProps<'strong', HTMLAttributes>;
style: HTMLProps<'style', HTMLAttributes>;
sub: HTMLProps<'sub', HTMLAttributes>;
summary: HTMLProps<'summary', HTMLAttributes>;
sup: HTMLProps<'sup', HTMLAttributes>;
table: HTMLProps<'table', HTMLAttributes>;
template: HTMLProps<'template', HTMLAttributes>;
tbody: HTMLProps<'tbody', HTMLAttributes>;
td: HTMLProps<'td', HTMLAttributes>;
textarea: HTMLProps<'textarea', HTMLAttributes>;
tfoot: HTMLProps<'tfoot', HTMLAttributes>;
th: HTMLProps<'th', HTMLAttributes>;
thead: HTMLProps<'thead', HTMLAttributes>;
time: HTMLProps<'time', HTMLAttributes>;
title: HTMLProps<'title', HTMLAttributes>;
tr: HTMLProps<'tr', HTMLAttributes>;
track: HTMLProps<'track', HTMLAttributes>;
u: HTMLProps<'u', HTMLAttributes>;
ul: HTMLProps<'ul', HTMLAttributes>;
var: HTMLProps<'var', HTMLAttributes>;
video: HTMLProps<'video', HTMLAttributes>;
wbr: HTMLProps<'wbr', HTMLAttributes>;
webview: HTMLProps<'webview', HTMLAttributes>;
// SVG
svg: HTMLProps<'svg', SVGAttributes>;
animate: HTMLProps<'animate', SVGAttributes>;
animateMotion: HTMLProps<'animateMotion', SVGAttributes>;
animateTransform: HTMLProps<'animateTransform', SVGAttributes>;
circle: HTMLProps<'circle', SVGAttributes>;
clipPath: HTMLProps<'clipPath', SVGAttributes>;
defs: HTMLProps<'defs', SVGAttributes>;
desc: HTMLProps<'desc', SVGAttributes>;
ellipse: HTMLProps<'ellipse', SVGAttributes>;
feBlend: HTMLProps<'feBlend', SVGAttributes>;
feColorMatrix: HTMLProps<'feColorMatrix', SVGAttributes>;
feComponentTransfer: HTMLProps<'feComponentTransfer', SVGAttributes>;
feComposite: HTMLProps<'feComposite', SVGAttributes>;
feConvolveMatrix: HTMLProps<'feConvolveMatrix', SVGAttributes>;
feDiffuseLighting: HTMLProps<'feDiffuseLighting', SVGAttributes>;
feDisplacementMap: HTMLProps<'feDisplacementMap', SVGAttributes>;
feDistantLight: HTMLProps<'feDistantLight', SVGAttributes>;
feDropShadow: HTMLProps<'feDropShadow', SVGAttributes>;
feFlood: HTMLProps<'feFlood', SVGAttributes>;
feFuncA: HTMLProps<'feFuncA', SVGAttributes>;
feFuncB: HTMLProps<'feFuncB', SVGAttributes>;
feFuncG: HTMLProps<'feFuncG', SVGAttributes>;
feFuncR: HTMLProps<'feFuncR', SVGAttributes>;
feGaussianBlur: HTMLProps<'feGaussianBlur', SVGAttributes>;
feImage: HTMLProps<'feImage', SVGAttributes>;
feMerge: HTMLProps<'feMerge', SVGAttributes>;
feMergeNode: HTMLProps<'feMergeNode', SVGAttributes>;
feMorphology: HTMLProps<'feMorphology', SVGAttributes>;
feOffset: HTMLProps<'feOffset', SVGAttributes>;
fePointLight: HTMLProps<'fePointLight', SVGAttributes>;
feSpecularLighting: HTMLProps<'feSpecularLighting', SVGAttributes>;
feSpotLight: HTMLProps<'feSpotLight', SVGAttributes>;
feTile: HTMLProps<'feTile', SVGAttributes>;
feTurbulence: HTMLProps<'feTurbulence', SVGAttributes>;
filter: HTMLProps<'filter', SVGAttributes>;
foreignObject: HTMLProps<'foreignObject', SVGAttributes>;
g: HTMLProps<'g', SVGAttributes>;
image: HTMLProps<'image', SVGAttributes>;
line: HTMLProps<'line', SVGAttributes>;
linearGradient: HTMLProps<'linearGradient', SVGAttributes>;
marker: HTMLProps<'marker', SVGAttributes>;
mask: HTMLProps<'mask', SVGAttributes>;
metadata: HTMLProps<'metadata', SVGAttributes>;
mpath: HTMLProps<'mpath', SVGAttributes>;
path: HTMLProps<'path', SVGAttributes>;
pattern: HTMLProps<'pattern', SVGAttributes>;
polygon: HTMLProps<'polygon', SVGAttributes>;
polyline: HTMLProps<'polyline', SVGAttributes>;
radialGradient: HTMLProps<'radialGradient', SVGAttributes>;
rect: HTMLProps<'rect', SVGAttributes>;
stop: HTMLProps<'stop', SVGAttributes>;
switch: HTMLProps<'switch', SVGAttributes>;
symbol: HTMLProps<'symbol', SVGAttributes>;
text: HTMLProps<'text', SVGAttributes>;
textPath: HTMLProps<'textPath', SVGAttributes>;
tspan: HTMLProps<'tspan', SVGAttributes>;
use: HTMLProps<'use', SVGAttributes>;
view: HTMLProps<'view', SVGAttributes>;
// Svelte specific
'svelte:window': HTMLProps<'svelte:window', HTMLAttributes>;
'svelte:body': HTMLProps<'svelte:body', HTMLAttributes>;
'svelte:document': HTMLProps<'svelte:document', HTMLAttributes>;
'svelte:fragment': { slot?: string };
'svelte:options': HTMLProps<'svelte:options', HTMLAttributes>;
'svelte:head': { [name: string]: any };
[name: string]: { [name: string]: any };
}
}
}

@ -0,0 +1,23 @@
<svelte:options
customElement={{
tag: 'custom-element',
props: {
expanded: { reflect: true, type: 'Boolean', attribute: 'aria-expanded' }
}
}}
/>
<script>
export let expanded = false;
</script>
<div>
<button on:click={() => (expanded = !expanded)}>Toggle</button>
<div class:hidden={!expanded}>Hidden Text</div>
</div>
<style>
.hidden {
display: none;
}
</style>

@ -0,0 +1,19 @@
import * as assert from 'assert.js';
import { tick } from 'svelte';
import './main.svelte';
export default async function (target) {
const element = document.createElement('custom-element');
target.appendChild(element);
await tick();
const el = target.querySelector('custom-element');
el.shadowRoot.querySelector('button').click();
await tick();
assert.equal(el.getAttribute('aria-expanded'), '');
el.shadowRoot.querySelector('button').click();
await tick();
assert.equal(el.getAttribute('aria-expanded'), null);
}

@ -0,0 +1,2 @@
<link rel="canonical" href="/test">
<meta name="description" content="test">

@ -0,0 +1,11 @@
<script>
import Foo from './Foo.svelte';
let bar;
</script>
<svelte:head>
<link rel="canonical" href="/test" />
<meta name="description" content="test" />
</svelte:head>
<Foo bind:bar />

@ -0,0 +1,7 @@
<script>
import Bla from './Bla.svelte';
</script>
<Bla>
<button slot="foo" class:bar on:click={clickFn} let:bar let:clickFn>{bar}</button>
</Bla>

@ -1,5 +1,5 @@
import { readFileSync } from 'node:fs'; import { readFileSync } from 'node:fs';
import { compile } from '../svelte/src/compiler/index.js'; import { compile } from '../../packages/svelte/src/compiler/index.js';
const code = readFileSync('src/App.svelte', 'utf8'); const code = readFileSync('src/App.svelte', 'utf8');

@ -3,9 +3,10 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { watch } from 'rollup'; import { watch } from 'rollup';
import serve from 'rollup-plugin-serve'; import serve from 'rollup-plugin-serve';
import * as svelte from '../svelte/src/compiler/index.js'; import * as svelte from '../../packages/svelte/src/compiler/index.js';
const __dirname = fileURLToPath(new URL('.', import.meta.url)); const __dirname = fileURLToPath(new URL('.', import.meta.url));
const runtime_path = path.resolve(__dirname, '../../packages/svelte/src/runtime');
/** @returns {import('rollup').Plugin}*/ /** @returns {import('rollup').Plugin}*/
function create_plugin(ssr = false) { function create_plugin(ssr = false) {
@ -13,12 +14,9 @@ function create_plugin(ssr = false) {
name: 'custom-svelte-ssr-' + ssr, name: 'custom-svelte-ssr-' + ssr,
resolveId(id) { resolveId(id) {
if (id === 'svelte') { if (id === 'svelte') {
return path.resolve( return path.resolve(runtime_path, ssr ? 'ssr.js' : 'index.js');
__dirname,
ssr ? '../svelte/src/runtime/ssr.js' : '../svelte/src/runtime/index.js'
);
} else if (id.startsWith('svelte/')) { } else if (id.startsWith('svelte/')) {
return path.resolve(__dirname, `../svelte/src/runtime/${id.slice(7)}/index.js`); return path.resolve(runtime_path, `${id.slice(7)}/index.js`);
} }
}, },
transform(code, id) { transform(code, id) {
@ -69,11 +67,12 @@ const watcher = watch([
async generateBundle(_, bundle) { async generateBundle(_, bundle) {
const result = bundle['entry-server.js']; const result = bundle['entry-server.js'];
const mod = (0, eval)(result.code); const mod = (0, eval)(result.code);
const { html } = mod.render(); const { html, head } = mod.render();
writeFileSync( writeFileSync(
'dist/index.html', 'dist/index.html',
readFileSync('src/template.html', 'utf-8') readFileSync('src/template.html', 'utf-8')
.replace('<!--app-head-->', head)
.replace('<!--app-html-->', html) .replace('<!--app-html-->', html)
.replace('<!--app-title-->', svelte.VERSION) .replace('<!--app-title-->', svelte.VERSION)
); );

File diff suppressed because it is too large Load Diff

@ -1,3 +1,4 @@
packages: packages:
- 'sites/*'
- 'packages/*' - 'packages/*'
- 'playgrounds/*'
- 'sites/*'

@ -0,0 +1,10 @@
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}
export {};

@ -0,0 +1,6 @@
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
return await resolve(event, {
preload: ({ type }) => type === 'js' || type === 'css' || type === 'font'
});
}

@ -2,9 +2,7 @@ import * as session from '$lib/db/session';
/** @type {import('@sveltejs/adapter-vercel').Config} */ /** @type {import('@sveltejs/adapter-vercel').Config} */
export const config = { export const config = {
// regions: ['pdx1', 'sfo1', 'cle1', 'iad1'], runtime: 'nodejs18.x' // see https://github.com/sveltejs/svelte/pull/9136
regions: 'all',
runtime: 'edge'
}; };
export async function load({ request }) { export async function load({ request }) {

@ -5,6 +5,7 @@ export function load({ url }) {
const gist = query.get('gist'); const gist = query.get('gist');
const example = query.get('example'); const example = query.get('example');
const version = query.get('version'); const version = query.get('version');
const vim = query.get('vim');
// redirect to v2 REPL if appropriate // redirect to v2 REPL if appropriate
if (/^[^>]?[12]/.test(version)) { if (/^[^>]?[12]/.test(version)) {
@ -12,7 +13,12 @@ export function load({ url }) {
} }
const id = gist || example || 'hello-world'; const id = gist || example || 'hello-world';
const q = version ? `?version=${version}` : ``; // we need to filter out null values
const q = new URLSearchParams(
throw redirect(301, `/repl/${id}${q}`); Object.entries({
version,
vim
}).filter(([, value]) => value !== null)
).toString();
throw redirect(301, `/repl/${id}?${q}`);
} }

@ -0,0 +1,18 @@
import { browser } from '$app/environment';
export function load({ data, url }) {
// initialize vim with the search param
const vim_search_params = url.searchParams.get('vim');
let vim = vim_search_params !== null && vim_search_params !== 'false';
// when in the browser check if there's a local storage entry and eventually override
// vim if there's not a search params otherwise update the local storage
if (browser) {
const vim_local_storage = window.localStorage.getItem('svelte:vim-enabled');
if (vim_search_params !== null) {
window.localStorage.setItem('svelte:vim-enabled', vim.toString());
} else if (vim_local_storage) {
vim = vim_local_storage !== 'false';
}
}
return { ...data, vim };
}

@ -61,6 +61,8 @@
: `https://unpkg.com/svelte@${version}`; : `https://unpkg.com/svelte@${version}`;
$: relaxed = data.gist.relaxed || (data.user && data.user.id === data.gist.owner); $: relaxed = data.gist.relaxed || (data.user && data.user.id === data.gist.owner);
$: vim = data.vim;
</script> </script>
<svelte:head> <svelte:head>
@ -87,6 +89,7 @@
bind:this={repl} bind:this={repl}
{svelteUrl} {svelteUrl}
{relaxed} {relaxed}
{vim}
injectedJS={mapbox_setup} injectedJS={mapbox_setup}
showModified showModified
showAst showAst

@ -31,10 +31,6 @@
let selected = examples[0]; let selected = examples[0];
</script> </script>
<svelte:head>
<link rel="prefetch" href="/fonts/overpass/overpass-latin-400.woff2" />
</svelte:head>
<Section --background="var(--sk-back-2)"> <Section --background="var(--sk-back-2)">
<h3>build with ease</h3> <h3>build with ease</h3>

@ -96,7 +96,6 @@
border-radius: var(--sk-border-radius); border-radius: var(--sk-border-radius);
box-shadow: 0px 6px 14px rgba(0, 0, 0, 0.08); box-shadow: 0px 6px 14px rgba(0, 0, 0, 0.08);
color: #fff; color: #fff;
color: color-mix(in hwb, hsl(var(--sk-theme-1-hsl)) 10%, var(--sk-back-1) 95%);
transition: 0.5s var(--quint-out); transition: 0.5s var(--quint-out);
transition-property: box-shadow, color; transition-property: box-shadow, color;
} }

@ -0,0 +1,5 @@
<svelte:head>
<meta name="robots" content="noindex">
</svelte:head>
<slot />

@ -1,2 +1,2 @@
User-agent: * User-agent: *
Disallow: /tutorial/* # new tutorial is at learn.svelte.dev Disallow:

Loading…
Cancel
Save