start working on v3 site

pull/1890/head
Rich Harris 7 years ago
parent 8d4e514f68
commit bb41b8626f

5
.gitignore vendored

@ -18,4 +18,7 @@ node_modules
/store.umd.js
/yarn-error.log
_actual*.*
_*/
_*/
/site/cypress/screenshots/
/site/__sapper__/

2
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.0.0-alpha3",
"version": "3.0.0-alpha6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

5
site/.gitignore vendored

@ -0,0 +1,5 @@
.DS_Store
node_modules
yarn-error.log
/cypress/screenshots/
/__sapper__/

@ -0,0 +1,11 @@
sudo: false
language: node_js
node_js:
- "stable"
env:
global:
- BUILD_TIMEOUT=10000
install:
- npm install
- npm install cypress

@ -0,0 +1,75 @@
# sapper-template-rollup
A version of the default [Sapper](https://github.com/sveltejs/sapper) template that uses Rollup instead of webpack. To clone it and get started:
```bash
npx degit sveltejs/sapper-template#rollup my-app
cd my-app
npm install # or yarn!
npm run dev
```
Open up [localhost:3000](http://localhost:3000) and start clicking around.
Consult [sapper.svelte.technology](https://sapper.svelte.technology) for help getting started.
*[Click here for the webpack version of this template](https://github.com/sveltejs/sapper-template)*
## Structure
Sapper expects to find three directories in the root of your project — `app`, `assets` and `routes`.
### app
The [app](app) directory contains the entry points for your app — `client.js`, `server.js` and (optionally) a `service-worker.js` — along with a `template.html` file.
### assets
The [assets](assets) directory contains any static assets that should be available. These are served using [sirv](https://github.com/lukeed/sirv).
In your [service-worker.js](app/service-worker.js) file, you can import these as `assets` from the generated manifest...
```js
import { assets } from './manifest/service-worker.js';
```
...so that you can cache them (though you can choose not to, for example if you don't want to cache very large files).
### routes
This is the heart of your Sapper app. There are two kinds of routes — *pages*, and *server routes*.
**Pages** are Svelte components written in `.html` files. When a user first visits the application, they will be served a server-rendered version of the route in question, plus some JavaScript that 'hydrates' the page and initialises a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel. (Sapper will preload and cache the code for these subsequent pages, so that navigation is instantaneous.)
**Server routes** are modules written in `.js` files, that export functions corresponding to HTTP methods. Each function receives Express `request` and `response` objects as arguments, plus a `next` function. This is useful for creating a JSON API, for example.
There are three simple rules for naming the files that define your routes:
* A file called `routes/about.html` corresponds to the `/about` route. A file called `routes/blog/[slug].html` corresponds to the `/blog/:slug` route, in which case `params.slug` is available to the route
* The file `routes/index.html` (or `routes/index.js`) corresponds to the root of your app. `routes/about/index.html` is treated the same as `routes/about.html`.
* Files and directories with a leading underscore do *not* create routes. This allows you to colocate helper modules and components with the routes that depend on them — for example you could have a file called `routes/_helpers/datetime.js` and it would *not* create a `/_helpers/datetime` route
## Rollup config
Sapper uses Rollup to provide code-splitting and dynamic imports, as well as compiling your Svelte components. As long as you don't do anything daft, you can edit the configuration files to add whatever plugins you'd like.
## Production mode and deployment
To start a production version of your app, run `npm run build && npm start`.
You can deploy your application to any environment that supports Node 8 or above. As an example, to deploy to [Now](https://zeit.co/now), run these commands:
```bash
npm install -g now
now
```
## Bugs and feedback
Sapper is in early development, and may have the odd rough edge here and there. Please be vocal over on the [Sapper issue tracker](https://github.com/sveltejs/sapper/issues).

@ -0,0 +1,18 @@
version: "{build}"
shallow_clone: true
init:
- git config --global core.autocrlf false
build: off
environment:
matrix:
# node.js
- nodejs_version: stable
install:
- ps: Install-Product node $env:nodejs_version
- npm install cypress
- npm install

@ -0,0 +1,56 @@
---
title: Frameworks without the framework: why didn't we think of this sooner?
description: You can't write serious applications in vanilla JavaScript without hitting a complexity wall. But a compiler can do it for you.
pubdate: 2016-11-26
author: Rich Harris
authorURL: https://twitter.com/Rich_Harris
---
> Wait, this new framework has a *runtime*? Ugh. Thanks, I'll pass.
> ** front end developers in 2018**
We're shipping too much code to our users. Like a lot of front end developers, I've been in denial about that fact, thinking that it was fine to serve 100kb of JavaScript on page load just use [one less .jpg!](https://twitter.com/miketaylr/status/227056824275333120) and that what *really* mattered was performance once your app was already interactive.
But I was wrong. 100kb of .js isn't equivalent to 100kb of .jpg. It's not just the network time that'll kill your app's startup performance, but the time spent parsing and evaluating your script, during which time the browser becomes completely unresponsive. On mobile, those milliseconds rack up very quickly.
If you're not convinced that this is a problem, follow [Alex Russell](https://twitter.com/slightlylate) on Twitter. Alex [hasn't been making many friends in the framework community lately](https://twitter.com/slightlylate/status/728355959022587905), but he's not wrong. But the proposed alternative to using frameworks like Angular, React and Ember [Polymer](https://www.polymer-project.org/1.0/) hasn't yet gained traction in the front end world, and it's certainly not for a lack of marketing.
Perhaps we need to rethink the whole thing.
## What problem do frameworks *really* solve?
The common view is that frameworks make it easier to manage the complexity of your code: the framework abstracts away all the fussy implementation details with techniques like virtual DOM diffing. But that's not really true. At best, frameworks *move the complexity around*, away from code that you had to write and into code you didn't.
Instead, the reason that ideas like React are so wildly and deservedly successful is that they make it easier to manage the complexity of your *concepts*. Frameworks are primarily a tool for structuring your thoughts, not your code.
Given that, what if the framework *didn't actually run in the browser*? What if, instead, it converted your application into pure vanilla JavaScript, just like Babel converts ES2016+ to ES5? You'd pay no upfront cost of shipping a hefty runtime, and your app would get seriously fast, because there'd be no layers of abstraction between your app and the browser.
## Introducing Svelte
Svelte is a new framework that does exactly that. You write your components using HTML, CSS and JavaScript (plus a few extra bits you can [learn in under 5 minutes](/guide)), and during your build process Svelte compiles them into tiny standalone JavaScript modules. By statically analysing the component template, we can make sure that the browser does as little work as possible.
The [Svelte implementation of TodoMVC](http://svelte-todomvc.surge.sh/) weighs 3.6kb zipped. For comparison, React plus ReactDOM *without any app code* weighs about 45kb zipped. It takes about 10x as long for the browser just to evaluate React as it does for Svelte to be up and running with an interactive TodoMVC.
And once your app *is* up and running, according to [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) **Svelte is fast as heck**. It's faster than React. It's faster than Vue. It's faster than Angular, or Ember, or Ractive, or Preact, or Riot, or Mithril. It's competitive with Inferno, which is probably the fastest UI framework in the world, for now, because [Dominic Gannaway](https://twitter.com/trueadm) is a wizard. (Svelte is slower at removing elements. We're [working on it](https://github.com/sveltejs/svelte/issues/26).)
It's basically as fast as vanilla JS, which makes sense because it *is* vanilla JS  just vanilla JS that you didn't have to write.
## But that's not the important thing
Well, it *is* important performance matters a great deal. What's really exciting about this approach, though, is that we can finally solve some of the thorniest problems in web development.
Consider interoperability. Want to `npm install cool-calendar-widget` and use it in your app? Previously, you could only do that if you were already using (a correct version of) the framework that the widget was designed for if `cool-calendar-widget` was built in React and you're using Angular then, well, hard cheese. But if the widget author used Svelte, apps that use it can be built using whatever technology you like. (On the TODO list: a way to convert Svelte components into web components.)
Or [code splitting](https://twitter.com/samccone/status/797528710085652480). It's a great idea (only load the code the user needs for the initial view, then get the rest later), but there's a problem even if you only initially serve one React component instead of 100, *you still have to serve React itself*. With Svelte, code splitting can be much more effective, because the framework is embedded in the component, and the component is tiny.
Finally, something I've wrestled with a great deal as an open source maintainer: your users always want *their* features prioritised, and underestimate the cost of those features to people who don't need them. A framework author must always balance the long-term health of the project with the desire to meet their users' needs. That's incredibly difficult, because it's hard to anticipate much less articulate the consequences of incremental bloat, and it takes serious soft skills to tell people (who may have been enthusiastically evangelising your tool up to that point) that their feature isn't important enough. But with an approach like Svelte's, many features can be added with absolutely no cost to people who don't use them, because the code that implements those features just doesn't get generated by the compiler if it's unnecessary.
## We're just getting started
Svelte is very new. There's a lot of work still left to do creating build tool integrations, adding a server-side renderer, hot reloading, transitions, more documentation and examples, starter kits, and so on.
But you can already build rich components with it, which is why we've gone straight to a stable 1.0.0 release. [Read the guide](/guide), [try it out in the REPL](/repl), and head over to [GitHub](https://github.com/sveltejs/svelte) to help kickstart the next era of front end development.

@ -0,0 +1,66 @@
---
title: The easiest way to get started with Svelte
description: This'll only take a minute.
pubdate: 2017-08-07
author: Rich Harris
authorURL: https://twitter.com/Rich_Harris
---
Svelte is a [new kind of framework](/blog/frameworks-without-the-framework). Rather than putting a `<script src='svelte.js'>` tag on the page, or bringing it into your app with `import` or `require`, Svelte is a compiler that works behind the scenes to turn your component files into beautifully optimised JavaScript.
Because of that, getting started with it can be a little bit confusing at first. How, you might reasonably ask, do you make a Svelte app?
## 1. Use the REPL
The [Svelte REPL](https://svelte.technology/repl) is the easiest way to begin. You can choose from a list of examples to get you started, and tweak them until they do what you want.
<aside>You'll need to have [Node.js](https://nodejs.org/) installed, and know how to use the terminal</aside>
At some point, your app will outgrow the REPL. Click the **download** button to save a `svelte-app.zip` file to your computer and uncompress it.
Open a terminal window and set the project up...
```bash
cd /path/to/svelte-app
npm install
```
...then start up a development server:
```bash
npm run dev
```
This will serve your app on [localhost:5000](http://localhost:5000) and rebuild it with [Rollup](https://rollupjs.org) every time you make a change to the files in `svelte-app/src`.
## 2. Use degit
When you download from the REPL, you're getting a customised version of the [sveltejs/template](https://github.com/sveltejs/template) repo. You can skip messing around with zip files by using [degit](https://github.com/Rich-Harris/degit), a project scaffolding tool.
In the terminal, install degit globally (you only need to do this once):
```bash
npm install -g degit
```
After that, you can instantly create a new project like so:
```bash
degit sveltejs/template my-new-project
cd my-new-project
npm install
npm run dev
```
Once you've tinkered a bit and understood how everything fits together, you can fork [sveltejs/template](https://github.com/sveltejs/template) and start doing this instead:
```bash
degit your-name/template my-new-project
```
And that's it! Do `npm run build` to create a production-ready version of your app, and check the project template's [README](https://github.com/sveltejs/template/blob/master/README.md) for instructions on how to easily deploy your app to the web with [Now](https://zeit.co/now) or [Surge](http://surge.sh/).
You're not restricted to using Rollup — there are also integrations for [webpack](https://github.com/sveltejs/svelte-loader), [Browserify](https://github.com/tehshrike/sveltify) and others, or you can use the [Svelte CLI](https://github.com/sveltejs/svelte-cli) or the [API](https://github.com/sveltejs/svelte#api) directly. If you make a project template using one of these tools, please share it with the [Svelte Gitter chatroom](https://gitter.im/sveltejs/svelte), or via [@sveltejs](https://twitter.com/sveltejs) on Twitter!

@ -0,0 +1,77 @@
---
title: The zen of Just Writing CSS
description: I would say this is the future, but we're already doing it.
pubdate: 2017-09-06
author: Rich Harris
authorURL: https://twitter.com/Rich_Harris
---
It's fashionable to dislike CSS. There are lots of reasons why that's the case, but it boils down to this: CSS is *unpredictable*. If you've never had the experience of tweaking a style rule and accidentally breaking some layout that you thought was completely unrelated — usually when you're trying to ship — then you're either new at this or you're a much better programmer than the rest of us.
So the JavaScript community rolled up its sleeves and got to work. Over the last couple of years, there's been a Cambrian explosion of libraries aimed at making CSS behave, collectively referred to as *CSS-in-JS*.
What you might not realise is that **the biggest problems with CSS can be solved without CSS-in-JS**. Without those problems, writing CSS isn't just tolerable — it's enjoyable. And you don't have to find solutions to the additional problems that CSS-in-JS introduces.
This article isn't in any way intended as criticism of the hard work the CSS-in-JS community has done. It's one of the most active corners of the JS ecosystem, and new ideas are springing up every week. Instead, my purpose is to illustrate why an alternative approach — based on Single File Components with real CSS — is so damn delightful.
## The biggest problem with CSS
Everything in CSS is global. Because of that, styles intended for one bit of markup often end up affecting another. Because of *that*, developers often resort to wild namespacing conventions (not 'rules', since they're very difficult to enforce) that mostly just increase your risk of RSI.
It gets worse when you're working on a team. No-one dares touch styles authored by someone else, because it's often unclear what they're doing, what markup they apply to, and what disasters will unfold if you remove them.
The consequence of all this is the **append-only stylesheet**. There's no way of knowing which code can safely be removed, so it's common to undo some existing style with another, more specific style — even on relatively small projects.
## Single File Components change all that
The idea behind SFCs is simple: you write your components in an HTML file that (optionally) contains a `<style>` and `<script>` attribute describing the component's styles and behaviour. Svelte, Ractive, Vue and Polymer all follow this basic pattern.
<aside>[Read the introductory blog post](https://svelte.technology/blog/frameworks-without-the-framework) if you're new to Svelte. Or [read](https://twitter.com/padolsey/status/899717303234908160) [the](https://twitter.com/sveltejs/status/901818357644701696) [testimonials](https://twitter.com/sveltejs/status/901818106309476352).</aside>
(For the rest of this article we'll be using Svelte, obviously. But if the idea of using a template language makes you shudder — your fears are misplaced, but that's a topic for another day — then just use Vue which lets you use JSX in your SFCs.)
Several wonderful things happen as a result:
* Your styles are *scoped to the component*. No more leakage, no more unpredictable cascade. And no more sesquipedalian classnames designed to prevent conflicts.
* You don't need to go spelunking through your folder structure to find the rules that are breaking your stuff.
* The compiler (in Svelte's case) can **identify and remove unused styles**. No more append-only stylesheets!
Let's see what that looks like in practice.
<figure>
<video controls poster='https://svelte-technology-assets.surge.sh/just-write-css.jpg'>
<source type='video/mp4' src='https://svelte-technology-assets.surge.sh/just-write-css.mp4'>
</video>
<figcaption>
Is this what they mean by 'use the platform'?
</figcaption>
</figure>
Every code editor already knows about CSS, so there's a good chance that you'll get autocomplete, linting, syntax highlighting and so on — all without additional JS-fatigue-inducing tools.
And because it's real CSS, rather than some camelCased quotes-everywhere impostor, we can take advantage of the 'tweak in devtools, paste back into our source code' workflow, which I personally couldn't live without. Notice that we get CSS sourcemaps out of the box, so you can instantly pinpoint the lines in question. It's hard to overstate the importance of this: when you're in WYSIWYG mode, you're not thinking in terms of your component tree, so having a robust way to figure out *where these damn styles came from* is essential. Doubly so if someone else originally wrote the component. (I promise you, this is the single biggest productivity boost to your CSS workflow. If you're writing styles without sourcemaps, you are almost certainly wasting a lot of time. I know I was.)
Svelte transforms your selectors (using an attribute that's also applied to affected elements, though the exact mechanism is unimportant and subject to change) to achieve the scoping. It warns on and removes any unused rules, then it minifies the result and lets you write it out to a `.css` file. There's also an experimental new option to compile to web components, using shadow DOM to encapsulate the styles, if that's your jam.
This is all possible because your CSS is parsed (with [css-tree](https://github.com/csstree/csstree)) and statically analysed in the context of your markup. Static analysis opens the doors to all kinds of exciting future possibilities — smarter optimisations, a11y hints — that are much harder if your styles are computed dynamically at runtime. We're just getting started.
## But we can add tools to do [x]!
If your reaction to the video was 'fine, but if we use TypeScript and write plugins for each editor then we can get all the autocomplete and syntax highlighting stuff' — in other words, if you believe that in order to achieve parity with CSS it makes sense to build, document, promote and maintain a fleet of ancillary projects — then, well, you and I may never see eye to eye!
## We don't have all the answers — yet
Having said all that, CSS-in-JS does point to answers to some lingering questions:
* How can we install styles from npm?
* How can we reuse constants that are defined in a single place?
* How can we compose declarations?
Personally, I haven't found these issues to outweigh the benefits of the approach outlined above. You may well have a different set of priorities, and they may be reason enough for you to abandon CSS.
But at the end of the day, you have to know CSS anyway. Love it or loathe it, you must at least *learn* it. As custodians of the web, we have a choice: create abstractions that steepen the web dev learning curve yet further, or work together to fix the bad parts of CSS. I know which I choose.

@ -0,0 +1,85 @@
---
title: Sapper: Towards the ideal web app framework
description: Taking the next-plus-one step
pubdate: 2017-12-31
author: Rich Harris
authorURL: https://twitter.com/Rich_Harris
---
> Quickstart for the impatient: [the Sapper docs](https://sapper.svelte.technology), and the [starter template](https://github.com/sveltejs/sapper-template)
If you had to list the characteristics of the perfect Node.js web application framework, you'd probably come up with something like this:
1. It should do server-side rendering, for fast initial loads and no caveats around SEO
2. As a corollary, your app's codebase should be universal — write once for server *and* client
3. The client-side app should *hydrate* the server-rendered HTML, attaching event listeners (and so on) to existing elements rather than re-rendering them
4. Navigating to subsequent pages should be instantaneous
5. Offline, and other Progressive Web App characteristics, must be supported out of the box
6. Only the JavaScript and CSS required for the first page should load initially. That means the framework should do automatic code-splitting at the route level, and support dynamic `import(...)` for more granular manual control
7. No compromise on performance
8. First-rate developer experience, with hot module reloading and all the trimmings
9. The resulting codebase should be easy to grok and maintain
10. It should be possible to understand and customise every aspect of the system — no webpack configs locked up in the framework, and as little hidden 'plumbing' as possible
11. Learning the entire framework in under an hour should be easy, and not just for experienced developers
[Next.js](https://github.com/zeit/next.js) is close to this ideal. If you haven't encountered it yet, I strongly recommend going through the tutorials at [learnnextjs.com](https://learnnextjs.com). Next introduced a brilliant idea: all the pages of your app are files in a `your-project/pages` directory, and each of those files is just a React component.
Everything else flows from that breakthrough design decision. Finding the code responsible for a given page is easy, because you can just look at the filesystem rather than playing 'guess the component name'. Project structure bikeshedding is a thing of the past. And the combination of SSR (server-side rendering) and code-splitting — something the React Router team [gave up on](https://reacttraining.com/react-router/web/guides/code-splitting), declaring 'Godspeed those who attempt the server-rendered, code-split apps' — is trivial.
But it's not perfect. As churlish as it might be to list the flaws in something *so, so good*, there are some:
* Next uses something called 'route masking' to create nice URLs (e.g. `/blog/hello-world` instead of `/post?slug=hello-world`). This undermines the guarantee about directory structure corresponding to app structure, and forces you to maintain configuration that translates between the two forms
* All your routes are assumed to be universal 'pages'. But it's very common to need routes that only render on the server, such as a 301 redirect or an [API endpoint](/api/blog/sapper-towards-the-ideal-web-app-framework) that serves the data for your pages, and Next doesn't have a great solution for this. You can add logic to your `server.js` file to handle these cases, but it feels at odds with the declarative approach taken for pages
* To use the client-side router, links can't be standard `<a>` tags. Instead, you have to use framework-specific `<Link>` components, which is impossible in the markdown content for a blog post such as this one, for example
The real problem, though, is that all that goodness comes for a price. The simplest possible Next app — a single 'hello world' page that renders some static text — involves 66kb of gzipped JavaScript. Unzipped, it's 204kb, which is a non-trivial amount of code for a mobile device to parse at a time when performance is a critical factor determining whether or not your users will stick around. And that's the *baseline*.
We can do better!
## The compiler-as-framework paradigm shift
[Svelte introduced a radical idea](https://svelte.technology/blog/frameworks-without-the-framework): what if your UI framework wasn't a framework at all, but a compiler that turned your components into standalone JavaScript modules? Instead of using a library like React or Vue, which knows nothing about your app and must therefore be a one-size-fits-all solution, we can ship highly-optimised vanilla JavaScript. Just the code your app needs, and without the memory and performance overhead of solutions based on a virtual DOM.
The JavaScript world is [moving towards this model](https://tomdale.net/2017/09/compilers-are-the-new-frameworks/). [Stencil](https://stenciljs.com), a Svelte-inspired framework from the Ionic team, compiles to web components. [Glimmer](https://glimmerjs.com) *doesn't* compile to standalone JavaScript (the pros and cons of which deserve a separate blog post), but the team is doing some fascinating research around compiling templates to bytecode. (React is [getting in on the action](https://twitter.com/trueadm/status/944908776896978946), though their current research focuses on optimising your JSX app code, which is arguably more similar to the ahead-of-time optimisations that Angular, Ractive and Vue have been doing for a few years.)
What happens if we use the new model as a starting point?
## Introducing Sapper
<aside>The [name comes from](https://sapper.svelte.technology/guide#why-the-name-) the term for combat engineers, and is also short for <strong>S</strong>velte <strong>app</strong> mak<strong>er</strong></aside>
[Sapper](https://sapper.svelte.technology) is the answer to that question. **Sapper is a Next.js-style framework that aims to meet the eleven criteria at the top of this article while dramatically reducing the amount of code that gets sent to the browser.** It's implemented as Express-compatible middleware, meaning it's easy to understand and customise.
The same 'hello world' app that took 204kb with React and Next weighs just 7kb with Sapper. That number is likely to fall further in the future as we explore the space of optimisation possibilities, such as not shipping any JavaScript *at all* for pages that aren't interactive, beyond the tiny Sapper runtime that handles client-side routing.
What about a more 'real world' example? Conveniently, the [RealWorld](https://github.com/gothinkster/realworld) project, which challenges frameworks to develop an implementation of a Medium clone, gives us a way to find out. The [Sapper implementation](http://svelte-realworld.now.sh/) takes 39.6kb (11.8kb zipped) to render an interactive homepage.
<aside>Code-splitting isn't free — if the reference implementation used code-splitting, it would be larger still</aside>
The entire app costs 132.7kb (39.9kb zipped), which is significantly smaller than the reference React/Redux implementation at 327kb (85.7kb), but even if was as large it would *feel* faster because of code-splitting. And that's a crucial point. We're told we need to code-split our apps, but if your app uses a traditional framework like React or Vue then there's a hard lower bound on the size of your initial code-split chunk — the framework itself, which is likely to be a significant portion of your total app size. With the Svelte approach, that's no longer the case.
But size is only part of the story. Svelte apps are also extremely performant and memory-efficient, and the framework includes powerful features that you would sacrifice if you chose a 'minimal' or 'simple' UI library.
## Trade-offs
The biggest drawback for many developers evaluating Sapper would be 'but I like React, and I already know how to use it', which is fair.
If you're in that camp, I'd invite you to at least try alternative frameworks. You might be pleasantly surprised! The [Sapper RealWorld](https://github.com/sveltejs/realworld) implementation totals 1,201 lines of source code, compared to 2,377 for the reference implementation, because you're able to express concepts very concisely using Svelte's template syntax (which [takes all of five minutes to master](https://svelte.technology/guide#template-syntax)). You get [scoped CSS](the-zen-of-just-writing-css), with unused style removal and minification built-in, and you can use preprocessors like LESS if you want. You no longer need to use Babel. SSR is ridiculously fast, because it's just string concatenation. And we recently introduced [svelte/store](https://svelte.technology/guide#state-management), a tiny global store that synchronises state across your component hierarchy with zero boilerplate. The worst that can happen is that you'll end up feeling vindicated!
But there are trade-offs nonetheless. Some people have a pathological aversion to any form of 'template language', and maybe that applies to you. JSX proponents will clobber you with the 'it's just JavaScript' mantra, and therein lies React's greatest strength, which is that it is infinitely flexible. That flexibility comes with its own set of trade-offs, but we're not here to discuss those.
And then there's *ecosystem*. The universe around React in particular — the devtools, editor integrations, ancillary libraries, tutorials, StackOverflow answers, hell, even job opportunities — is unrivalled. While it's true that citing 'ecosystem' as the main reason to choose a tool is a sign that you're stuck on a local maximum, apt to be marooned by the rising waters of progress, it's still a major point in favour of incumbents.
## Roadmap
We're not at version 1.0.0 yet, and a few things may change before we get there. Once we do (soon!), there are a lot of exciting possibilities.
I believe the next frontier of web performance is 'whole-app optimisation'. Currently, Svelte's compiler operates at the component level, but a compiler that understood the boundaries *between* those components could generate even more efficient code. The React team's [Prepack research](https://twitter.com/trueadm/status/944908776896978946) is predicated on a similar idea, and the Glimmer team is doing some interesting work in this space. Svelte and Sapper are well positioned to take advantage of these ideas.
Speaking of Glimmer, the idea of compiling components to bytecode is one that we'll probably steal in 2018. A framework like Sapper could conceivably determine which compilation mode to use based on the characteristics of your app. It could even serve JavaScript for the initial route for the fastest possible startup time, then lazily serve a bytecode interpreter for subsequent routes, resulting in the optimal combination of startup size and total app size.
Mostly, though, we want the direction of Sapper to be determined by its users. If you're the kind of developer who enjoys life on the bleeding edge and would like to help shape the future of how we build web apps, please join us on [GitHub](https://github.com/sveltejs/svelte) and [Gitter](https://gitter.im/sveltejs/svelte).

@ -0,0 +1,218 @@
---
title: Svelte v2 is out!
description: Here's what you need to know
pubdate: 2018-04-18
author: Rich Harris
authorURL: https://twitter.com/Rich_Harris
---
<aside>Our motto is 'move slowly and break things'. No, wait, that came out wrong...</aside>
Almost a year after we first started talking about version 2 on the Svelte issue tracker, it's finally time to make some breaking changes. This blog post will explain what changed, why it changed, and what you need to do to bring your apps up to date.
## tl;dr
Each of these items is described in more depth below. If you get stuck, ask for help in our friendly [Gitter chatroom](https://gitter.im/sveltejs/svelte).
<style>
ul {
position: relative;
list-style: none;
}
li input {
position: absolute;
left: -2.5em;
top: 0.3em;
}
</style>
- <input type=checkbox> Install Svelte v2 from npm
- <input type=checkbox> Upgrade your templates with [svelte-upgrade](https://github.com/sveltejs/svelte-upgrade)
- <input type=checkbox> Remove calls to `component.observe`, or add the `observe` method from [svelte-extras](https://github.com/sveltejs/svelte-extras)
- <input type=checkbox> Rewrite calls to `component.get('foo')` as `component.get().foo`
- <input type=checkbox> Return `destroy` from your custom event handlers, rather than `teardown`
- <input type=checkbox> Make sure you're not passing numeric string props to components
## New template syntax
The most visible change: we've made some improvements to the template syntax.
A common piece of feedback we heard was 'ewww, Mustache' or 'ewww, Handlebars'. A lot of people who used string-based templating systems in a previous era of web development *really* dislike them. Because Svelte adopted the `{{curlies}}` from those languages, a lot of people assumed that we somehow shared the limitations of those tools, such as weird scoping rules or an inability to use arbitrary JavaScript expressions.
<aside>If you need to show an actual `{` character, it's as easy as `&amp;#123;`</aside>
Beyond that, JSX proved that double curlies are unnecessary. So we've made our templates more... svelte, by adopting single curlies. The result feels much lighter to look at and is more pleasant to type:
```html
<h1>Hello {name}!</h1>
```
There are a few other updates. But you don't need to make them manually — just run [svelte-upgrade](https://github.com/sveltejs/svelte-upgrade) on your codebase:
```bash
npx svelte-upgrade v2 src
```
This assumes any `.html` files in `src` are Svelte components. You can specify whichever directory you like, or target a different directory — for example, you'd do `npx svelte-upgrade v2 routes` to update a [Sapper](https://sapper.svelte.technology) app.
To see the full set of changes, consult the [svelte-upgrade README](https://github.com/sveltejs/svelte-upgrade#svelte-v2-syntax-changes).
## Computed properties
Another thing that people often found confusing about Svelte is the way computed properties work. To recap, if you had a component with this...
```js
export default {
computed: {
d: (a, b, c) => a = b + c
}
};
```
...then Svelte would first look at the function arguments to see which values `d` depended on, and then it would write code that updated `d` whenever those values changed, by injecting them into the function. That's cool, because it allows you to derive complex values from your component's inputs without worrying about when they need to recomputed, but it's also... *weird*. JavaScript doesn't work that way!
In v2, we use [destructuring](http://www.jstips.co/en/javascript/use-destructuring-in-function-parameters/) instead:
```js
export default {
computed: {
d: ({ a, b, c }) => a = b + c
}
};
```
The Svelte compiler can still see which values `d` depends on, but it's no longer injecting values — it just passes the component state object into each computed property.
Again, you don't need to make this change manually — just run svelte-upgrade on your components, as shown above.
## Sorry, IE11. It's not you, it's...<br>well actually, yeah. It's you
Svelte v1 was careful to only emit ES5 code, so that you wouldn't be forced to faff around with transpilers in order to use it. But it's 2018 now, and almost all browsers support modern JavaScript. By ditching the ES5 constraint, we can generate leaner code.
If you need to support IE11 and friends, you will need to use a transpiler like [Babel](http://babeljs.io/repl) or [Bublé](http://buble.surge.sh/).
## New lifecycle hooks
In addition to `oncreate` and `ondestroy`, Svelte v2 adds two more [lifecycle hooks](guide#lifecycle-hooks) for responding to state changes:
```js
export default {
onstate({ changed, current, previous }) {
// this fires before oncreate, and
// whenever state changes
},
onupdate({ changed, current, previous }) {
// this fires after oncreate, and
// whenever the DOM has been updated
// following a state change
}
};
```
You can also listen to those events programmatically:
```js
component.on('state', ({ changed, current, previous }) => {
// ...
});
```
## component.observe
With the new lifecycle hooks, we no longer need the `component.observe(...)` method:
```js
// before
export default {
oncreate() {
this.observe('foo', foo => {
console.log(`foo is now ${foo}`);
});
}
};
// after
export default {
onstate({ changed, current }) {
if (changed.foo) {
console.log(`foo is now ${current.foo}`);
}
}
};
```
This shrinks the amount of code Svelte needs to generate, and gives you more flexibility. For example, it's now very easy to take action when any one of *several* properties have changed, such as redrawing a canvas without debouncing several observers.
However, if you prefer to use `component.observe(...)`, then you can install it from [svelte-extras](https://github.com/sveltejs/svelte-extras):
```js
import { observe } from 'svelte-extras';
export default {
methods: {
observe
}
};
```
## component.get
This method no longer takes an optional `key` argument — instead, it always returns the entire state object:
```js
// before
const foo = this.get('foo');
const bar = this.get('bar');
// after
const { foo, bar } = this.get();
```
This change might seem annoying initially, but it's the right move: among other things, it's likely to play better with type systems as we explore that space more fully in future.
## event_handler.destroy
If your app has [custom event handlers](guide#custom-event-handlers), they must return an object with a `destroy` method, *not* a `teardown` method (this aligns event handlers with the component API).
## No more type coercion
Previously, numeric values passed to components were treated as numbers:
```html
<Counter start='1'/>
```
That causes unexpected behaviour, and has been changed: if you need to pass a literal number, do so as an expression:
```html
<Counter start={1}/>
```
## Compiler changes
In most cases you'll never need to deal with the compiler directly, so this shouldn't require any action on your part. It's worth noting anyway: the compiler API has changed. Instead of an object with a mish-mash of properties, the compiler now returns `js`, `css`, `ast` and `stats`:
```js
const { js, css, ast, stats } = svelte.compile(source, options);
```
`js` and `css` are both `{ code, map }` objects, where `code` is a string and `map` is a sourcemap. The `ast` is an abstract syntax tree of your component, and the `stats` object contains metadata about the component, and information about the compilation.
Before, there was a `svelte.validate` method which checked your component was valid. That's been removed — if you want to check a component without actually compiling it, just pass the `generate: false` option.
## My app is broken! Help!
Hopefully this covers everything, and the update should be easier for you than it was for us. But if you find bugs, or discover things that aren't mentioned here, swing by [Gitter](https://gitter.im/sveltejs/svelte) or raise an issue on the [tracker](https://github.com/sveltejs/svelte/issues).

@ -0,0 +1,130 @@
<!--
https://github.com/eugenkiss/7guis/wiki#circle-drawer
Click on the canvas to draw a circle. Click on a circle
to select it. Right-click on the canvas to adjust the
radius of the selected circle.
-->
<div class='controls'>
<button on:click='travel(-1)' disabled='{i === 0}'>undo</button>
<button on:click='travel(+1)' disabled='{i === undoStack.length -1}'>redo</button>
</div>
<svg on:click='handleClick(event)' on:contextmenu='adjust(event)'>
{#each circles as circle}
<circle cx='{circle.cx}' cy='{circle.cy}' r='{circle.r}'
on:click='select(circle, event)'
fill='{circle === selected ? "#ccc": "white"}'
/>
{/each}
</svg>
{#if adjusting}
<div class='adjuster'>
<p>adjust diameter of circle at {selected.cx}, {selected.cy}</p>
<input type='range' bind:value='selected.r' on:input='set({ adjusted: true })'>
</div>
{/if}
<style>
.controls {
position: absolute;
width: 100%;
text-align: center;
}
svg {
background-color: #eee;
width: 100%;
height: 100%;
}
circle {
stroke: black;
}
.adjuster {
position: absolute;
width: 80%;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
padding: 1em;
text-align: center;
background-color: rgba(255,255,255,0.5);
}
input[type='range'] {
width: 100%;
}
</style>
<script>
export default {
data() {
return {
i: 0,
undoStack: [[]],
adjusting: false,
adjusted: false,
circles: []
};
},
methods: {
handleClick(event) {
if (this.get().adjusting) {
this.set({ adjusting: false });
// if nothing changed, rewind
if (this.get().adjusted) this.push();
return;
}
const circle = {
cx: event.clientX,
cy: event.clientY,
r: 50
};
const circles = this.get().circles;
circles.push(circle);
this.set({ circles, selected: circle });
this.push();
},
adjust(event) {
event.preventDefault();
if (!this.get().selected) return;
this.set({ adjusting: true, adjusted: false });
},
select(circle, event) {
if (!this.get().adjusting) {
event.stopPropagation();
this.set({ selected: circle });
}
},
// undo stack management
push() {
let { i, undoStack, circles } = this.get();
undoStack.splice(++i);
undoStack.push(clone(circles));
this.set({ i, undoStack });
},
travel(d) {
let { i, undoStack } = this.get();
const circles = clone(undoStack[i += d]);
this.set({ circles, i, adjusting: false });
}
}
};
function clone(circles) {
return circles.map(({ cx, cy, r }) => ({ cx, cy, r }));
}
</script>

@ -0,0 +1,3 @@
<!-- https://github.com/eugenkiss/7guis/wiki#counter -->
<input type='number' bind:value='count'>
<button on:click='set({ count: count + 1 })'>count</button>

@ -0,0 +1,112 @@
<!-- https://github.com/eugenkiss/7guis/wiki#crud -->
<input placeholder='filter prefix' bind:value='prefix'>
<select bind:value='i' size='5'>
{#each filteredPeople as person, i}
<option value='{i}'>{person.last}, {person.first}</option>
{/each}
</select>
<label><input bind:value='first' placeholder='first'></label>
<label><input bind:value='last' placeholder='last'></label>
<div class='buttons'>
<button on:click='create()' disabled='{!first || !last}'>create</button>
<button on:click='update()' disabled='{!first || !last || !selected}'>update</button>
<button on:click='remove()' disabled='{!selected}'>delete</button>
</div>
<style>
* {
font-family: inherit;
font-size: inherit;
}
input {
display: block;
margin: 0 0 0.5em 0;
}
select {
float: left;
margin: 0 1em 1em 0;
width: 14em;
}
.buttons {
clear: both;
}
</style>
<script>
export default {
data() {
return {
prefix: '',
first: '',
last: '',
people: [],
selected: null
};
},
computed: {
selected: ({ filteredPeople, i }) => {
return filteredPeople[i];
},
filteredPeople({ people, prefix }) {
if (!prefix) return people;
prefix = prefix.toLowerCase();
return people.filter(person => {
const name = `${person.last}, ${person.first}`;
return name.toLowerCase().startsWith(prefix);
});
}
},
onstate({ changed, current }) {
if (changed.selected && current.selected) {
this.set(current.selected);
}
},
methods: {
create() {
const { first, last, people } = this.get();
people.push({ first, last });
this.set({
people,
first: '',
last: '',
i: people.length - 1
});
},
update() {
const { first, last, selected, people } = this.get();
selected.first = first;
selected.last = last;
this.set({ people });
},
remove() {
const { people, selected, i } = this.get();
const index = people.indexOf(selected);
people.splice(index, 1);
this.set({
people,
first: '',
last: '',
i: Math.min(i, people.length - 1)
});
}
}
};
</script>

@ -0,0 +1,16 @@
{
"people": [
{
"first": "Hans",
"last": "Emil"
},
{
"first": "Max",
"last": "Mustermann"
},
{
"first": "Roman",
"last": "Tisch"
}
]
}

@ -0,0 +1,71 @@
<!-- https://github.com/eugenkiss/7guis/wiki#flight-booker -->
<select bind:value='isReturn'>
<option value='{false}'>one-way flight</option>
<option value='{true}'>return flight</option>
</select>
<input type='date' bind:value='start'>
<input type='date' bind:value='end' disabled='{!isReturn}'>
<button
on:click='bookFlight()'
disabled='{ isReturn && ( startDate >= endDate ) }'
>book</button>
<style>
select, input, button {
display: block;
margin: 0.5em 0;
font-size: inherit;
}
</style>
<script>
export default {
data() {
const tomorrow = new Date(Date.now() + 86400000);
const tomorrowAsString = [
tomorrow.getFullYear(),
pad(tomorrow.getMonth() + 1, 2),
pad(tomorrow.getDate(), 2)
].join('-');
return {
start: tomorrowAsString,
end: tomorrowAsString,
type: 'oneway'
};
},
computed: {
startDate: ({ start }) => convertToDate(start),
endDate: ({ end }) => convertToDate(end)
},
methods: {
bookFlight() {
const { startDate, endDate, isReturn } = this.get();
const type = isReturn ? 'return' : 'one-way';
let message = `You have booked a ${type} flight, leaving ${startDate.toDateString()}`;
if (type === 'return') {
message += ` and returning ${endDate.toDateString()}`;
}
alert(message);
}
}
};
function convertToDate(str) {
var split = str.split('-');
return new Date(+split[0], +split[1] - 1, +split[2]);
}
function pad(x, len) {
x = String(x);
while (x.length < len) x = `0${x}`;
return x;
}
</script>

@ -0,0 +1,26 @@
<!-- https://github.com/eugenkiss/7guis/wiki#temperature-converter -->
<input bind:value='celsius' type='number'> °c =
<input bind:value='fahrenheit' type='number'> °f
<style>
input {
width: 5em;
}
</style>
<script>
export default {
onstate: function ({ changed, current }) {
if (changed.celsius) {
this.set({
fahrenheit: +(32 + (9 / 5 * current.celsius)).toFixed(1)
});
}
if (changed.fahrenheit) {
this.set({
celsius: +(5 / 9 * (current.fahrenheit - 32)).toFixed(1)
});
}
}
}
</script>

@ -0,0 +1,53 @@
<!-- https://github.com/eugenkiss/7guis/wiki#timer -->
<label>
elapsed time:
<progress value='{elapsed / duration}'></progress>
</label>
<div>{ ( elapsed / 1000 ).toFixed( 1 ) }s</div>
<label>
duration:
<input type='range' bind:value='duration' min='1' max='20000'>
</label>
<button on:click='reset()'>reset</button>
<script>
export default {
data() {
return { elapsed: 0, duration: 5000 };
},
oncreate() {
this.reset();
const update = () => {
this.frame = requestAnimationFrame(update);
const { start, duration } = this.get();
const elapsed = window.performance.now() - start;
if (elapsed > duration) return;
this.set({ elapsed });
};
update();
},
ondestroy() {
if (this.frame) {
cancelAnimationFrame(this.frame);
}
},
methods: {
reset() {
this.set({
start: window.performance.now()
});
}
}
};
</script>

@ -0,0 +1,26 @@
<button on:click='findAnswer()'>find the answer</button>
{#if promise}
{#await promise}
<p>wait for it...</p>
{:then answer}
<p>the answer is {answer}!</p>
{:catch error}
<p>well that's odd</p>
{/await}
{/if}
<script>
export default {
methods: {
findAnswer() {
this.set({
promise: new Promise(fulfil => {
const delay = 1000 + Math.random() * 3000;
setTimeout(() => fulfil(42), delay);
})
});
}
}
};
</script>

@ -0,0 +1,132 @@
<svelte:window on:resize='resize()'/>
<div class='chart'>
<h2>US birthrate by year</h2>
<svg ref:svg>
<!-- y axis -->
<g class='axis y-axis' transform='translate(0,{padding.top})'>
{#each yTicks as tick}
<g class='tick tick-{tick}' transform='translate(0, {yScale(tick) - padding.bottom})'>
<line x2='100%'></line>
<text y='-4'>{tick} {tick === 20 ? ' per 1,000 population' : ''}</text>
</g>
{/each}
</g>
<!-- x axis -->
<g class='axis x-axis'>
{#each points as point, i}
<g class='tick tick-{tick}' transform='translate({xScale(i)},{height})'>
<text x='{barWidth/2}' y='-4'>{width > 380 ? point.year : formatMobile(point.year)}</text>
</g>
{/each}
</g>
<g class='bars'>
{#each points as point, i}
<rect
x='{xScale(i) + 2}'
y='{yScale(point.birthrate)}'
width='{ barWidth - 4 }'
height='{ height - padding.bottom - yScale(point.birthrate) }'
></rect>
{/each}
</g>
</svg>
</div>
<style>
.chart {
width: 100%;
max-width: 500px;
margin: 0 auto;
}
svg {
position: relative;
width: 100%;
height: 200px;
}
.tick {
font-family: Helvetica, Arial;
font-size: .725em;
font-weight: 200;
}
.tick line {
stroke: #e2e2e2;
stroke-dasharray: 2;
}
.tick text {
fill: #ccc;
text-anchor: start;
}
.tick.tick-0 line {
stroke-dasharray: 0;
}
.x-axis .tick text {
text-anchor: middle;
}
.bars rect {
fill: #a11;
stroke: none;
opacity: 0.65;
}
</style>
<script>
import { scaleLinear } from 'd3-scale';
var xScale = scaleLinear();
var yScale = scaleLinear();
export default {
data: function () {
return {
padding: { top: 20, right: 15, bottom: 20, left: 25 },
height: 200,
width: 500,
xTicks: [1990, 1995, 2000, 2005, 2010, 2015],
yTicks: [0, 5, 10, 15, 20]
};
},
helpers: {
formatMobile: function (tick) {
return "'" + tick % 100;
}
},
computed: {
barWidth: function ({ xTicks, width, padding }) {
var innerWidth = width - (padding.left + padding.right);
return innerWidth / xTicks.length;
},
xScale: function ({ padding, width, xTicks }) {
return xScale
.domain([0, xTicks.length])
.range([padding.left, width - padding.right]);
},
yScale: function ({ padding, height, yTicks }) {
return yScale
.domain([0, Math.max.apply(null, yTicks)])
.range([height - padding.bottom, padding.top]);
}
},
oncreate() {
this.resize();
},
methods: {
resize: function () {
var bcr = this.refs.svg.getBoundingClientRect();
this.set({
width: bcr.right - bcr.left,
height: bcr.bottom - bcr.top
});
}
}
};
</script>

@ -0,0 +1,28 @@
{
"points": [
{
"year": 1990,
"birthrate": 16.7
},
{
"year": 1995,
"birthrate": 14.6
},
{
"year": 2000,
"birthrate": 14.4
},
{
"year": 2005,
"birthrate": 14
},
{
"year": 2010,
"birthrate": 13
},
{
"year": 2015,
"birthrate": 12.4
}
]
}

@ -0,0 +1,16 @@
<label>
<input type='checkbox' bind:group='selected' value='red'>
red
</label>
<label>
<input type='checkbox' bind:group='selected' value='green'>
green
</label>
<label>
<input type='checkbox' bind:group='selected' value='blue'>
blue
</label>
<p>{selected.join(', ') || 'nothing'} selected</p>

@ -0,0 +1,17 @@
{#each todos as todo}
<div class='todo {todo.done ? "done": ""}'>
<input type='checkbox' bind:checked='todo.done'>
<input type='text' bind:value='todo.description'>
</div>
{/each}
<style>
input[type="text"] {
width: 20em;
max-width: calc(100% - 2em);
}
.done {
opacity: 0.6;
}
</style>

@ -0,0 +1,16 @@
{
"todos": [
{
"description": "Buy some milk",
"done": true
},
{
"description": "Do the laundry",
"done": true
},
{
"description": "Find life's true purpose",
"done": false
}
]
}

@ -0,0 +1,12 @@
<!-- number and range inputs are bound to numeric values -->
<input bind:value='a' type='number' min='0' max='10'>
<input bind:value='b' type='range' min='0' max='10'>
<p>{a} * {b} = {a * b}</p>
<style>
input {
display: block;
width: 10em
}
</style>

@ -0,0 +1,16 @@
<label>
<input type='radio' bind:group='selected' value='red'>
red
</label>
<label>
<input type='radio' bind:group='selected' value='green'>
green
</label>
<label>
<input type='radio' bind:group='selected' value='blue'>
blue
</label>
<p style='color: {selected};'>selected {selected}</p>

@ -0,0 +1,2 @@
<input bind:value='name' placeholder='enter your name'>
<p>Hello {name || 'stranger'}!</p>

@ -0,0 +1,104 @@
<svelte:window on:click='seek(event)' on:mousemove='seek(event)'/>
<audio bind:currentTime=t bind:duration=d bind:paused>
<source type='audio/mp3' src='https://deepnote.surge.sh/deepnote.mp3'>
</audio>
<p>THX Deep Note</p>
<div class='status' on:click='event.stopPropagation()'>
<img alt='play/pause button' on:click='set({ paused: !paused })' src='{icon}/333333'>
<span class='elapsed'>{format(t)}</span>
<span class='duration'>{format(d)}</span>
</div>
<div class='progress' style='width: {d ? 100 * t/d : 0}%; background: {bg};'>
<p>THX Deep Note</p>
<div class='status' on:click='event.stopPropagation()'>
<img alt='play/pause button' src='{icon}/ffffff'>
<span class='elapsed'>{format(t)}</span>
<span class='duration'>{format(d)}</span>
</div>
</div>
<style>
.progress {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
color: white;
overflow: hidden;
pointer-events: none;
}
p {
position: absolute;
left: 1em;
top: 1em;
width: 20em;
}
.status {
position: absolute;
bottom: 1em;
left: 1em;
width: calc(100vw - 2em);
}
img {
position: absolute;
left: 0;
bottom: 2em;
width: 3em;
cursor: pointer;
}
.elapsed { float: left; }
.duration { float: right; }
</style>
<script>
function pad(num) {
return num < 10 ? '0' + num : num;
}
export default {
data() {
return { paused: true, t: 0 };
},
computed: {
icon: ({ paused }) => {
return `https://icon.now.sh/${paused ? 'play' : 'pause'}_circle_filled`;
},
bg: ({ t, d }) => {
var p = d ? t / d : 0;
var h = 90 + 90 * p;
var l = 10 + p * 30;
return `hsl(${h},50%,${l}%)`;
}
},
helpers: {
format: time => {
if (isNaN(time)) return '--:--.-';
var minutes = Math.floor(time / 60);
var seconds = (time % 60).toFixed(1);
return minutes + ':' + pad(seconds)
}
},
methods: {
seek(event) {
if (event.buttons === 1) {
event.preventDefault();
var p = event.clientX / window.innerWidth;
this.set({ t: p * this.get().d });
}
}
}
}
</script>

@ -0,0 +1,19 @@
<textarea bind:value='markdown' resize='none'></textarea>
<div class='output'>{@html marked(markdown)}</div>
<style>
textarea {
width: 100%;
height: 50%;
}
</style>
<script>
import marked from 'marked';
export default {
helpers: {
marked
}
};
</script>

@ -0,0 +1,3 @@
{
"markdown": "# Markdown editor\n\nTODOs:\n\n* make a Svelte app\n* think of a third item for this list"
}

@ -0,0 +1,7 @@
<h1>Cats of YouTube</h1>
<ul>
{#each cats as cat}
<li><a target='_blank' href='{cat.video}'>{cat.name}</a></li>
{/each}
</ul>

@ -0,0 +1,16 @@
{
"cats": [
{
"name": "Keyboard Cat",
"video": "https://www.youtube.com/watch?v=J---aiyznGQ"
},
{
"name": "Maru",
"video": "https://www.youtube.com/watch?v=z_AbfPXTKms"
},
{
"name": "Henri The Existential Cat",
"video": "https://www.youtube.com/watch?v=OUtn3pvWmpg"
}
]
}

@ -0,0 +1,66 @@
<svelte:window on:hashchange='hashchange()'/>
<main>
{#if item}
<Item {item}/>
{:elseif page}
<List {page}/>
{/if}
</main>
<style>
main {
position: relative;
max-width: 800px;
margin: 0 auto;
min-height: 101vh;
padding: 1em;
}
main :global(.meta) {
color: #999;
font-size: 12px;
margin: 0 0 1em 0;
}
main :global(a) {
color: rgb(0,0,150);
}
</style>
<script>
import List from './List.html';
import Item from './Item.html';
export default {
components: { List, Item },
oncreate() {
this.hashchange();
},
methods: {
async hashchange() {
// the poor man's router!
const path = window.location.hash.slice(1);
if (path.startsWith('/item')) {
const id = path.slice(6);
const item = await fetch(`https://node-hnapi.herokuapp.com/item/${id}`).then(r => r.json());
this.set({ item });
window.scrollTo(0,0);
} else if (path.startsWith('/top')) {
const page = +path.slice(5);
this.set({
item: null,
page
});
} else {
window.location.hash = '/top/1';
}
}
}
};
</script>

@ -0,0 +1,28 @@
<article>
<p class='meta'>{comment.user} {comment.time_ago}</p>
{@html comment.content}
<div class='replies'>
{#each comment.comments as child}
<svelte:self comment='{child}'/>
{/each}
</div>
</article>
<style>
article {
border-top: 1px solid #eee;
margin: 1em 0 0 0;
padding: 1em 0 0 0;
font-size: 14px;
}
.meta {
color: #999;
}
.replies {
padding: 0 0 0 1em;
}
</style>

@ -0,0 +1,47 @@
<a href='#/top/1' on:click='back(event)'>&laquo; back</a>
<article>
<a href='{item.url}'>
<h1>{item.title}</h1>
<small>{item.domain}</small>
</a>
<p class='meta'>submitted by {item.user} {item.time_ago}
</article>
<div class='comments'>
{#each item.comments as comment}
<Comment {comment}/>
{/each}
</div>
<style>
article {
margin: 0 0 1em 0;
}
a {
display: block;
margin: 0 0 1em 0;
}
h1 {
font-size: 1.4em;
margin: 0;
}
</style>
<script>
import Comment from './Comment.html';
export default {
components: { Comment },
methods: {
back(event) {
event.preventDefault();
window.history.back();
}
}
};
</script>

@ -0,0 +1,52 @@
{#if items}
{#each items as item, i}
<Summary {item} {i} {offset}/>
{/each}
<a href='#/top/{page + 1}'>page {page + 1}</a>
{:else}
<p class='loading'>loading...</p>
{/if}
<style>
a {
padding: 2em;
display: block;
}
.loading {
opacity: 0;
animation: 0.4s 0.8s forwards fade-in;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
<script>
import Summary from './Summary.html';
const PAGE_SIZE = 20;
export default {
async onstate({ changed, current }) {
if (changed.page) {
const { page } = current;
const items = await fetch(`https://node-hnapi.herokuapp.com/news?page=${page}`).then(r => r.json());
this.set({
items,
offset: PAGE_SIZE * (page - 1)
});
window.scrollTo(0,0);
}
},
components: {
Summary
}
};
</script>

@ -0,0 +1,38 @@
<article>
<span>{i + offset + 1}</span>
<h2><a target='_blank' href='{item.url}'>{item.title}</a></h2>
<p class='meta'><a href='#/item/{item.id}'>{comment_text}</a> by {item.user} {item.time_ago}</p>
</article>
<style>
article {
position: relative;
padding: 0 0 0 2em;
border-bottom: 1px solid #eee;
}
h2 {
font-size: 1em;
margin: 0.5em 0;
}
span {
position: absolute;
left: 0;
}
a {
color: #333;
}
</style>
<script>
export default {
computed: {
comment_text({ item }) {
const c = item.comments_count;
return `${c} ${c === 1 ? 'comment' : 'comments'}`;
}
}
};
</script>

@ -0,0 +1,14 @@
<h1>Hello {name}!</h1>
<!--
This is a Svelte component. Click the toggle
below right to see the generated code.
You can interact with this component via your
browser's console - try running the following:
app.set({ name: 'everybody' });
You can also update the data via the JSON
editor on this page.
-->

@ -0,0 +1,5 @@
{#if foo}
<p>foo!</p>
{:else}
<p>not foo!</p>
{/if}

@ -0,0 +1,48 @@
<h2>Immutable</h2>
{#each todos as todo}
<label on:click="toggle(todo.id)">
<span>{todo.done ? "😎": "☹️"}</span>
<ImmutableTodo {todo}/>
</label>
{/each}
<h2>Mutable</h2>
{#each todos as todo}
<label on:click="toggle(todo.id)">
<span>{todo.done ? "😎": "☹️"}</span>
<MutableTodo {todo}/>
</label>
{/each}
<script>
import ImmutableTodo from './ImmutableTodo.html';
import MutableTodo from './MutableTodo.html';
export default {
immutable: true,
methods: {
toggle(id) {
const { todos } = this.get();
this.set({
todos: todos.map(todo => {
if (todo.id === id) {
// return a new object
return {
id,
done: !todo.done,
text: todo.text
};
}
// return the same object
return todo;
})
});
}
},
components: { ImmutableTodo, MutableTodo }
}
</script>

@ -0,0 +1,17 @@
<!-- the text will flash red whenever
the `todo` object changes -->
<span ref:span>{todo.text}</span>
<script>
export default {
// try commenting this out
immutable: true,
onupdate({ changed, current, previous }) {
this.refs.span.style.color = 'red';
setTimeout(() => {
this.refs.span.style.color = 'black';
}, 400);
}
};
</script>

@ -0,0 +1,14 @@
<span ref:span>{todo.text}</span>
<script>
export default {
immutable: false,
onupdate({ changed, current, previous }) {
this.refs.span.style.color = 'red';
setTimeout(() => {
this.refs.span.style.color = 'black';
}, 400);
}
};
</script>

@ -0,0 +1,7 @@
{
todos: [
{ id: 1, done: true, text: "wash the car" },
{ id: 2, done: false, text: "take the dog for a walk" },
{ id: 3, done: false, text: "mow the lawn" }
]
}

@ -0,0 +1,153 @@
<svelte:window on:resize='resize()'/>
<div class='chart'>
<h2>Arctic sea ice minimum</h2>
<svg ref:svg>
<!-- y axis -->
<g class='axis y-axis' transform='translate(0, {padding.top})'>
{#each yTicks as tick}
<g class='tick tick-{tick}' transform='translate(0, {yScale(tick) - padding.bottom})'>
<line x2='100%'></line>
<text y='-4'>{tick} {tick === 8 ? ' million sq km' : ''}</text>
</g>
{/each}
</g>
<!-- x axis -->
<g class='axis x-axis'>
{#each xTicks as tick}
<g class='tick tick-{ tick }' transform='translate({xScale(tick)},{height})'>
<line y1='-{height}' y2='-{padding.bottom}' x1='0' x2='0'></line>
<text y='-2'>{width > 380 ? tick : formatMobile(tick)}</text>
</g>
{/each}
</g>
<!-- data -->
<path class='path-area' d='{area}'></path>
<path class='path-line' d='{path}'></path>
</svg>
<p>Average September extent. Source: <a href='https://climate.nasa.gov/vital-signs/arctic-sea-ice/'>NSIDC/NASA</a>
</div>
<style>
.chart {
width: 100%;
max-width: 500px;
margin: 0 auto;
}
svg {
position: relative;
width: 100%;
height: 200px;
}
.tick {
font-size: .725em;
font-weight: 200;
}
.tick line {
stroke: #aaa;
stroke-dasharray: 2;
}
.tick text {
fill: #666;
text-anchor: start;
}
.tick.tick-0 line {
stroke-dasharray: 0;
}
.x-axis .tick text {
text-anchor: middle;
}
.path-line {
fill: none;
stroke: rgb(0,100,100);
stroke-linejoin: round;
stroke-linecap: round;
stroke-width: 2;
}
.path-area {
fill: rgba(0,100,100,0.2);
}
</style>
<script>
import { scaleLinear } from 'd3-scale';
const xScale = scaleLinear();
const yScale = scaleLinear();
export default {
data() {
return {
padding: { top: 20, right: 15, bottom: 20, left: 25 },
height: 200,
width: 500,
xTicks: [1980, 1990, 2000, 2010],
yTicks: [0, 2, 4, 6, 8],
formatMobile(tick) {
return "'" + tick % 100;
}
};
},
computed: {
minX: ({ points }) => {
return points[0].x;
},
maxX: ({ points }) => {
return points[points.length - 1].x;
},
xScale: ({ padding, width, minX, maxX }) => {
return xScale
.domain([minX, maxX])
.range([padding.left, width - padding.right]);
},
yScale: ({ padding, height, yTicks }) => {
return yScale
.domain([Math.min.apply(null, yTicks), Math.max.apply(null, yTicks)])
.range([height - padding.bottom, padding.top]);
},
path: ({ points, xScale, yScale }) => {
return 'M' + points
.map(function (point, i) {
return xScale(point.x) + ',' + yScale(point.y);
})
.join('L');
},
area: ({ points, xScale, yScale, minX, maxX, path }) => {
return path + (
'L' + xScale(maxX) + ',' + yScale(0) +
'L' + xScale(minX) + ',' + yScale(0) +
'Z'
);
}
},
oncreate() {
this.resize();
},
methods: {
resize: function () {
const { width, height } = this.refs.svg.getBoundingClientRect();
this.set({ width, height });
}
}
};
</script>

@ -0,0 +1,156 @@
{
"points": [
{
"x": 1979,
"y": 7.19
},
{
"x": 1980,
"y": 7.83
},
{
"x": 1981,
"y": 7.24
},
{
"x": 1982,
"y": 7.44
},
{
"x": 1983,
"y": 7.51
},
{
"x": 1984,
"y": 7.1
},
{
"x": 1985,
"y": 6.91
},
{
"x": 1986,
"y": 7.53
},
{
"x": 1987,
"y": 7.47
},
{
"x": 1988,
"y": 7.48
},
{
"x": 1989,
"y": 7.03
},
{
"x": 1990,
"y": 6.23
},
{
"x": 1991,
"y": 6.54
},
{
"x": 1992,
"y": 7.54
},
{
"x": 1993,
"y": 6.5
},
{
"x": 1994,
"y": 7.18
},
{
"x": 1995,
"y": 6.12
},
{
"x": 1996,
"y": 7.87
},
{
"x": 1997,
"y": 6.73
},
{
"x": 1998,
"y": 6.55
},
{
"x": 1999,
"y": 6.23
},
{
"x": 2000,
"y": 6.31
},
{
"x": 2001,
"y": 6.74
},
{
"x": 2002,
"y": 5.95
},
{
"x": 2003,
"y": 6.13
},
{
"x": 2004,
"y": 6.04
},
{
"x": 2005,
"y": 5.56
},
{
"x": 2006,
"y": 5.91
},
{
"x": 2007,
"y": 4.29
},
{
"x": 2008,
"y": 4.72
},
{
"x": 2009,
"y": 5.38
},
{
"x": 2010,
"y": 4.92
},
{
"x": 2011,
"y": 4.61
},
{
"x": 2012,
"y": 3.62
},
{
"x": 2013,
"y": 5.35
},
{
"x": 2014,
"y": 5.28
},
{
"x": 2015,
"y": 4.63
},
{
"x": 2016,
"y": 4.72
}
]
}

@ -0,0 +1,175 @@
[
{
"name": "Basics",
"examples": [
{
"slug": "hello-world",
"title": "Hello World!"
},
{
"slug": "if-blocks",
"title": "If blocks"
},
{
"slug": "each-blocks",
"title": "Each blocks"
},
{
"slug": "scoped-styles",
"title": "Scoped styles"
}
]
},
{
"name": "Two-way bindings",
"examples": [
{
"slug": "binding-input-text",
"title": "Text input"
},
{
"slug": "binding-input-numeric",
"title": "Numeric input"
},
{
"slug": "binding-textarea",
"title": "Textarea"
},
{
"slug": "binding-input-checkbox",
"title": "Checkbox input"
},
{
"slug": "binding-input-checkbox-group",
"title": "Checkbox input (grouped)"
},
{
"slug": "binding-input-radio",
"title": "Radio input"
},
{
"slug": "binding-media-elements",
"title": "Media elements"
}
]
},
{
"name": "Nested components",
"examples": [
{
"slug": "nested-components",
"title": "Nested components"
},
{
"slug": "modal-with-slot",
"title": "Modal with <slot>"
},
{
"slug": "self-references",
"title": "Self-references"
}
]
},
{
"name": "SVG and dataviz",
"examples": [
{
"slug": "svg-clock",
"title": "SVG Clock"
},
{
"slug": "line-chart",
"title": "Line/area chart"
},
{
"slug": "bar-chart",
"title": "Bar chart"
},
{
"slug": "scatterplot",
"title": "Scatterplot"
}
]
},
{
"name": "Transitions",
"examples": [
{
"slug": "transitions-fade",
"title": "Simple fade"
},
{
"slug": "transitions-fly",
"title": "Parameterised"
},
{
"slug": "transitions-in-out",
"title": "In and out"
},
{
"slug": "transitions-custom",
"title": "Custom CSS"
}
]
},
{
"name": "Async data",
"examples": [
{
"slug": "await-block",
"title": "Await block"
}
]
},
{
"name": "7guis",
"examples": [
{
"slug": "7guis-counter",
"title": "Counter"
},
{
"slug": "7guis-temperature",
"title": "Temperature converter"
},
{
"slug": "7guis-flight-booker",
"title": "Flight booker"
},
{
"slug": "7guis-timer",
"title": "Timer"
},
{
"slug": "7guis-crud",
"title": "CRUD"
},
{
"slug": "7guis-circles",
"title": "Circles"
}
]
},
{
"name": "<:Window>",
"examples": [
{
"slug": "parallax",
"title": "Parallax"
}
]
},
{
"name": "Miscellaneous",
"examples": [
{
"slug": "hacker-news",
"title": "Hacker News"
},
{
"slug": "immutable",
"title": "Immutable data"
}
]
}
]

@ -0,0 +1,33 @@
{#if showModal}
<Modal on:close='set({ showModal: false })'>
<h2 slot='header'>
modal
<small><em>adjective</em> mod·al \ˈmō-dəl\</small>
</h2>
<ol class="definition-list">
<li>of or relating to modality in logic</li>
<li>containing provisions as to the mode of procedure or the manner of taking effect —used of a contract or legacy</li>
<li>of or relating to a musical mode</li>
<li>of or relating to structure as opposed to substance</li>
<li>of, relating to, or constituting a grammatical form or category characteristically indicating predication</li>
<li>of or relating to a statistical mode</li>
</ol>
<a href='https://www.merriam-webster.com/dictionary/modal'>merriam-webster.com</a>
</Modal>
{:else}
<button on:click='set({ showModal: true })'>
show modal
</button>
{/if}
<script>
import Modal from './Modal.html';
export default {
components: {
Modal
}
};
</script>

@ -0,0 +1,39 @@
<div class='modal-background' on:click='fire("close")'></div>
<div class='modal'>
<slot name='header'></slot>
<hr>
<slot></slot>
<hr>
<button on:click='fire("close")'>close modal</button>
</div>
<style>
.modal-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.3);
}
.modal {
position: absolute;
left: 50%;
top: 50%;
width: calc(100vw - 4em);
max-width: 32em;
max-height: calc(100vh - 4em);
overflow: auto;
transform: translate(-50%,-50%);
padding: 1em;
border-radius: 0.2em;
background: white;
}
button {
display: block;
}
</style>

@ -0,0 +1,12 @@
<p>This is a top-level element.</p>
<Nested/>
<script>
import Nested from './Nested.html';
export default {
components: {
Nested
}
};
</script>

@ -0,0 +1 @@
<p>And this is a nested component.</p>

@ -0,0 +1,72 @@
<!-- this binds `sy` to the current value of `window.scrollY` -->
<svelte:window bind:scrollY='sy'/>
<!-- try changing the values that `sy` is multiplied by -
values closer to 0 appear further away -->
<div class='parallax-container'>
<img style='transform: translate(0,{-sy * 0.2}px)' src='http://www.firewatchgame.com/images/parallax/parallax0.png'>
<img style='transform: translate(0,{-sy * 0.3}px)' src='http://www.firewatchgame.com/images/parallax/parallax1.png'>
<img style='transform: translate(0,{-sy * 0.4}px)' src='http://www.firewatchgame.com/images/parallax/parallax3.png'>
<img style='transform: translate(0,{-sy * 0.5}px)' src='http://www.firewatchgame.com/images/parallax/parallax5.png'>
<img style='transform: translate(0,{-sy * 0.6}px)' src='http://www.firewatchgame.com/images/parallax/parallax7.png'>
</div>
<div class='text'>
<small style='
transform: translate(0,{-sy * 1.5}px);
opacity: {1 - Math.max( 0, sy / 80 )}
'>(scroll down)</small>
<span>parallax has never been this easy</span>
</div>
<style>
.parallax-container {
position: fixed;
width: 2400px;
height: 712px;
left: 50%;
transform: translate(-50%,0);
}
.parallax-container img {
position: absolute;
top: 0;
left: 0;
width: 100%;
will-change: transform;
}
.text {
position: relative;
width: 100%;
min-height: 100vh;
color: white;
text-align: center;
padding: 50vh 0.5em 0.5em 0.5em;
box-sizing: border-box;
}
.text::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: linear-gradient(to bottom, rgba(45,10,13,0) 60vh,rgba(45,10,13,1) 712px);
}
small {
display: block;
font-size: 4vw;
will-change: transform, opacity;
}
.text span {
font-size: 20vw;
position: relative;
z-index: 2;
}
:global(body) { margin: 0; padding: 0; }
</style>

@ -0,0 +1,29 @@
<div class='chart'>
<h2>Anscombe's quartet</h2>
<Scatterplot points='{a}'/>
<Scatterplot points='{b}'/>
<Scatterplot points='{c}'/>
<Scatterplot points='{d}'/>
</div>
<style>
.chart {
width: 100%;
max-width: 640px;
height: calc(100% - 4em);
min-height: 280px;
max-height: 480px;
margin: 0 auto;
}
</style>
<script>
import Scatterplot from './Scatterplot.html';
export default {
components: {
Scatterplot
}
};
</script>

@ -0,0 +1,116 @@
<svelte:window on:resize='resize()'/>
<svg ref:svg>
<!-- y axis -->
<g class='axis y-axis'>
{#each yTicks as tick}
<g class='tick tick-{tick}' transform='translate(0, {yScale(tick)})'>
<line x1='{padding.left}' x2='{xScale(22)}'/>
<text x='{padding.left - 8}' y='+4'>{tick}</text>
</g>
{/each}
</g>
<!-- x axis -->
<g class='axis x-axis'>
{#each xTicks as tick}
<g class='tick' transform='translate({xScale(tick)},0)'>
<line y1='{yScale(0)}' y2='{yScale(13)}'/>
<text y='{height - padding.bottom + 16}'>{tick}</text>
</g>
{/each}
</g>
<!-- data -->
{#each points as point}
<circle cx='{xScale(point.x)}' cy='{yScale(point.y)}' r='5'/>
{/each}
</svg>
<style>
svg {
width: 50%;
height: 50%;
float: left;
}
circle {
fill: orange;
fill-opacity: 0.6;
stroke: rgba(0,0,0,0.5);
}
.tick line {
stroke: #ddd;
stroke-dasharray: 2;
}
text {
font-size: 12px;
fill: #999;
}
.x-axis text {
text-anchor: middle;
}
.y-axis text {
text-anchor: end;
}
</style>
<script>
import { scaleLinear } from 'd3-scale';
const xScale = scaleLinear();
const yScale = scaleLinear();
export default {
data() {
return {
padding: { top: 20, right: 40, bottom: 40, left: 25 },
height: 200,
width: 500,
xTicks: [0, 4, 8, 12, 16, 20],
yTicks: [0, 2, 4, 6, 8, 10, 12]
};
},
computed: {
xTicks: ({ width }) => {
return width > 180 ?
[0, 4, 8, 12, 16, 20] :
[0, 10, 20];
},
yTicks: ({ height }) => {
return height > 180 ?
[0, 2, 4, 6, 8, 10, 12] :
[0, 4, 8, 12];
},
xScale: ({ padding, width }) => {
return xScale
.domain([0, 20])
.range([padding.left, width - padding.right]);
},
yScale: ({ padding, height }) => {
return yScale
.domain([0, 12])
.range([height - padding.bottom, padding.top]);
}
},
oncreate() {
this.resize();
},
methods: {
resize() {
const { width, height } = this.refs.svg.getBoundingClientRect();
this.set({ width, height });
}
}
};
</script>

@ -0,0 +1,186 @@
{
"a": [
{
"x": 10,
"y": 8.04
},
{
"x": 8,
"y": 6.95
},
{
"x": 13,
"y": 7.58
},
{
"x": 9,
"y": 8.81
},
{
"x": 11,
"y": 8.33
},
{
"x": 14,
"y": 9.96
},
{
"x": 6,
"y": 7.24
},
{
"x": 4,
"y": 4.26
},
{
"x": 12,
"y": 10.84
},
{
"x": 7,
"y": 4.82
},
{
"x": 5,
"y": 5.68
}
],
"b": [
{
"x": 10,
"y": 9.14
},
{
"x": 8,
"y": 8.14
},
{
"x": 13,
"y": 8.74
},
{
"x": 9,
"y": 8.77
},
{
"x": 11,
"y": 9.26
},
{
"x": 14,
"y": 8.1
},
{
"x": 6,
"y": 6.13
},
{
"x": 4,
"y": 3.1
},
{
"x": 12,
"y": 9.13
},
{
"x": 7,
"y": 7.26
},
{
"x": 5,
"y": 4.74
}
],
"c": [
{
"x": 10,
"y": 7.46
},
{
"x": 8,
"y": 6.77
},
{
"x": 13,
"y": 12.74
},
{
"x": 9,
"y": 7.11
},
{
"x": 11,
"y": 7.81
},
{
"x": 14,
"y": 8.84
},
{
"x": 6,
"y": 6.08
},
{
"x": 4,
"y": 5.39
},
{
"x": 12,
"y": 8.15
},
{
"x": 7,
"y": 6.42
},
{
"x": 5,
"y": 5.73
}
],
"d": [
{
"x": 8,
"y": 6.58
},
{
"x": 8,
"y": 5.76
},
{
"x": 8,
"y": 7.71
},
{
"x": 8,
"y": 8.84
},
{
"x": 8,
"y": 8.47
},
{
"x": 8,
"y": 7.04
},
{
"x": 8,
"y": 5.25
},
{
"x": 19,
"y": 12.5
},
{
"x": 8,
"y": 5.56
},
{
"x": 8,
"y": 7.91
},
{
"x": 8,
"y": 6.89
}
]
}

@ -0,0 +1,11 @@
<div class='foo'>
Big red Comic Sans
</div>
<style>
.foo {
color: red;
font-size: 2em;
font-family: 'Comic Sans MS';
}
</style>

@ -0,0 +1,9 @@
<ul>
<li>{node.name}
{#if node.children}
{#each node.children as child}
<svelte:self node='{child}'/>
{/each}
{/if}
</li>
</ul>

@ -0,0 +1,32 @@
{
"node": {
"name": "Fruit",
"children": [
{
"name": "Red",
"children": [
{
"name": "Cherry"
},
{
"name": "Strawberry"
}
]
},
{
"name": "Green",
"children": [
{
"name": "Apple"
},
{
"name": "Pear"
},
{
"name": "Lime"
}
]
}
]
}
}

@ -0,0 +1,101 @@
<svg viewBox='-50 -50 100 100'>
<circle class='clock-face' r='48'/>
<!-- markers -->
{#each [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55] as minute}
<line
class='major'
y1='35'
y2='45'
transform='rotate({30 * minute})'
/>
{#each [1, 2, 3, 4] as offset}
<line
class='minor'
y1='42'
y2='45'
transform='rotate({6 * (minute + offset)})'
/>
{/each}
{/each}
<!-- hour hand -->
<line
class='hour'
y1='2'
y2='-20'
transform='rotate({30 * hours + minutes / 2})'
/>
<!-- minute hand -->
<line
class='minute'
y1='4'
y2='-30'
transform='rotate({6 * minutes + seconds / 10})'
/>
<!-- second hand -->
<g transform='rotate({6 * seconds})'>
<line class='second' y1='10' y2='-38'/>
<line class='second-counterweight' y1='10' y2='2'/>
</g>
</svg>
<style>
svg {
width: 100%;
height: 100%;
}
.clock-face {
stroke: #333;
fill: white;
}
.minor {
stroke: #999;
stroke-width: 0.5;
}
.major {
stroke: #333;
stroke-width: 1;
}
.hour {
stroke: #333;
}
.minute {
stroke: #666;
}
.second, .second-counterweight {
stroke: rgb(180,0,0);
}
.second-counterweight {
stroke-width: 3;
}
</style>
<script>
export default {
data() {
return {
time: new Date()
};
},
computed: {
hours: ({ time }) => time.getHours(),
minutes: ({ time }) => time.getMinutes(),
seconds: ({ time }) => time.getSeconds()
},
oncreate() {
this.interval = setInterval(() => {
this.set({ time: new Date() });
}, 1000);
},
ondestroy() {
clearInterval(this.interval);
}
};
</script>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1,50 @@
<input type='checkbox' bind:checked=visible> visible
{#if visible}
<div class='centered' in:wheee='{duration: 8000}' out:fade>
<span>wheeee!!!!!</span>
</div>
{/if}
<style>
.centered {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
span {
position: absolute;
transform: translate(-50%,-50%);
font-size: 4em;
}
</style>
<script>
import * as eases from 'eases-jsnext';
import { fade } from 'svelte-transitions';
export default {
transitions: {
wheee: (node, params) => {
return {
duration: params.duration,
css: t => {
const eased = eases.elasticOut(t);
return `
transform: scale(${eased}) rotate(${eased * 1080}deg);
color: hsl(
${~~(t * 360)},
${Math.min(100, 1000 - 1000 * t)}%,
${Math.min(50, 500 - 500 * t)}%
);`
}
};
},
fade
}
};
</script>

@ -0,0 +1,13 @@
<input type='checkbox' bind:checked=visible> visible
{#if visible}
<p transition:fade>fades in and out</p>
{/if}
<script>
import { fade } from 'svelte-transitions';
export default {
transitions: { fade }
};
</script>

@ -0,0 +1,13 @@
<input type='checkbox' bind:checked=visible> visible
{#if visible}
<p transition:fly='{y: 200, duration: 1000}'>flies 200 pixels up, slowly</p>
{/if}
<script>
import { fly } from 'svelte-transitions';
export default {
transitions: { fly }
};
</script>

@ -0,0 +1,13 @@
<input type='checkbox' bind:checked=visible> visible
{#if visible}
<p in:fly='{y: 50}' out:fade>flies up, fades out</p>
{/if}
<script>
import { fade, fly } from 'svelte-transitions';
export default {
transitions: { fade, fly }
};
</script>

@ -0,0 +1,113 @@
---
title: Introduction
---
### What is Svelte?
Svelte is a tool for building fast web applications.
It is similar to JavaScript frameworks such as React, Angular, Vue, and Ractive, which all share a goal of making it easy to build slick interactive user interfaces.
But there's a crucial difference: Svelte converts your app into ideal JavaScript at _build time_, rather than interpreting your application code at _run time_. This means you don't pay the performance cost of the framework's abstractions, and you don't incur a penalty when your app first loads.
You can build your entire app with Svelte, or you can add it incrementally to an existing codebase. You can also ship components as standalone packages that work anywhere, without the overhead of a dependency on a conventional framework.
[Read the introductory blog post](/blog/frameworks-without-the-framework) to learn more about Svelte's goals and philosophy.
### Understanding Svelte components
In Svelte, an application is composed from one or more _components_. A component is a reusable self-contained block of code that encapsulates markup, styles and behaviours that belong together.
Like Ractive and Vue, Svelte promotes the concept of _single-file components_: a component is just an `.html` file. Here's a simple example:
```html
<!--{ title: 'Hello world!' }-->
<h1>Hello {name}!</h1>
```
```json
/* { hidden: true } */
{
"name": "world"
}
```
> Wherever you see <svg class="icon" style="color:var(--text)"><use xlink:href='#maximize-2' /></svg> links, click through for an interactive example
Svelte turns this into a JavaScript module that you can import into your app:
```js
/* { filename: 'main.js' } */
import App from './App.html';
const app = new App({
target: document.querySelector('main'),
data: { name: 'world' },
});
// change the data associated with the template
app.set({ name: 'everybody' });
// detach the component and clean everything up
app.destroy();
```
Congratulations, you've just learned about half of Svelte's API!
### Getting started
Normally, this is the part where the instructions might tell you to add the framework to your page as a `<script>` tag. But because Svelte runs at build time, it works a little bit differently.
The best way to use Svelte is to integrate it into your build system  there are plugins for Rollup, Browserify, Gulp and others, with more on the way. See [here](https://github.com/sveltejs/svelte/#svelte) for an up-to-date list.
> You will need to have [Node.js](https://nodejs.org/en/) installed, and have some familiarity with the command line
#### Getting started using the REPL
Going to the [REPL](/repl) and pressing the _download_ button on any of the examples will give you a .zip file containing everything you need to run that example locally. Just unzip it, `cd` to the directory, and run `npm install` and `npm run dev`. See [this blog post](/blog/the-easiest-way-to-get-started) for more information.
#### Getting started using degit
[degit](https://github.com/Rich-Harris/degit) is a tool for creating projects from templates stored in git repos. Install it globally...
```bash
npm install -g degit
```
...then you can use it to spin up a new project:
```bash
degit sveltejs/template my-new-project
cd my-new-project
npm install
npm run dev
```
You can use any git repo you like — these are the 'official' templates:
- [sveltejs/template](https://github.com/sveltejs/template) — this is what you get by downloading from the REPL
- [sveltejs/template-webpack](https://github.com/sveltejs/template-webpack) — similar, but uses [webpack](https://webpack.js.org/) instead of [Rollup](https://rollupjs.org/guide/en)
#### Getting started using the CLI
Svelte also provides a Command Line Interface, but it's not recommended for production use. The CLI will compile your components to standalone JavaScript files, but won't automatically recompile them when they change, and won't deduplicate code shared between your components. Use one of the above methods instead.
If you've installed `svelte` globally, you can use `svelte --help` for a complete list of options. Some examples of the more common operations are:
```bash
# Generate a JavaScript module from MyComponent.html
svelte compile MyComponent.html > MyComponent.js
svelte compile -i MyComponent.html -o MyComponent.js
# Generate a UMD module from MyComponent.html,
# inferring its name from the filename ('MyComponent')
svelte compile -f umd MyComponent.html > MyComponent.js
# Generate a UMD module, specifying the name
svelte compile -f umd -n CustomName MyComponent.html > MyComponent.js
# Compile all .html files in a directory
svelte compile -i src/components -o build/components
```
> You can also use [npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) to use the CLI without installing Svelte globally — just prefix your command with `npx`: `npx svelte compile ...`

@ -0,0 +1,141 @@
---
title: Component API
---
As we saw above, you create a component instance with the `new` keyword:
```js
/* { filename: 'main.js' } */
import MyComponent from './MyComponent.html';
const component = new MyComponent({
// `target` is the only required option the element
// to render the component to
target: document.querySelector('main'),
// `data` is optional. A component can also have
// default data we'll learn about that later.
data: {
questions: [
'life',
'the universe',
'everything'
],
answer: 42
}
});
```
Every Svelte component instance has a small number of methods you can use to control it, in addition to any [custom methods](guide#custom-methods) you add.
### component.set(state)
This updates the component's state with the new values provided and causes the DOM to update. `state` must be a plain old JavaScript object (POJO). Any properties *not* included in `state` will remain as they were.
```js
component.set({
questions: [
'why is the sky blue?',
'how do planes fly?',
'where do babies come from?'
],
answer: 'ask your mother'
});
```
### component.get()
Returns the component's current state:
```js
const { questions, answer } = component.get();
console.log(answer); // 'ask your mother'
```
This will also retrieve the value of [computed properties](guide#computed-properties).
> Previous versions of Svelte allowed you to specify a key to retrieve a specific value — this was removed in version 2.
### component.on(eventName, callback)
Allows you to respond to *events*:
```js
const listener = component.on('thingHappened', event => {
console.log(`A thing happened: ${event.thing}`);
});
// some time later...
listener.cancel();
```
Each component has three built-in events, corresponding to their [lifecycle hooks](guide#lifecycle-hooks):
```js
component.on('state', ({ changed, current, previous }) => {
console.log('state changed', current);
});
component.on('update', ({ changed, current, previous }) => {
console.log('DOM updated after state change', current);
});
component.on('destroy', () => {
console.log('this component is being destroyed');
});
```
### component.fire(eventName, event)
The companion to `component.on(...)`:
```js
component.fire('thingHappened', {
thing: 'this event was fired'
});
```
At first glance `component.on(...)` and `component.fire(...)` aren't particularly useful, but it'll become more so when we learn about [nested components](guide#nested-components) and [component events](guide#component-events).
### component.destroy()
Removes the component from the DOM and removes any event listeners that were created. This will also fire a `destroy` event:
```js
component.on('destroy', () => {
alert('goodbye!'); // please don't do this
});
component.destroy();
```
### component.options
The options used to instantiate the component are available in `component.options`.
```html
<!-- { title: 'component.options' } -->
Check the console.
<script>
export default {
oncreate() {
console.log(this.options);
}
};
</script>
```
This gives you access to standard options like `target` and `data`, but can also be used to access any other custom options you may choose to implement for your component.
### component.root
In [nested components](guide#nested-components), each component has a `root` property pointing to the top-level root component that is, the one instantiated with `new MyComponent({...})`.
> Earlier versions of Svelte had a `component.observe(...)` method. This was removed in version 2, in favour of the `onstate` [lifecycle hook](guide#lifecycle-hooks), but is still available via [svelte-extras](https://github.com/sveltejs/svelte-extras).

@ -0,0 +1,311 @@
---
title: Template syntax
---
Rather than reinventing the wheel, Svelte templates are built on foundations that have stood the test of time: HTML, CSS and JavaScript. There's very little extra stuff to learn.
> Svelte version 1 had a slightly different template syntax. You can upgrade older components automatically using [svelte-upgrade](https://github.com/sveltejs/svelte-upgrade).
### Tags
Tags allow you to bind data to your template. Whenever your data changes (for example after `component.set(...)`), the DOM updates automatically. You can use any JavaScript expression in templates, and it will also automatically update:
```html
<!-- { title: 'Template tags' } -->
<p>{a} + {b} = {a + b}</p>
```
```json
/* { hidden: true } */
{
"a": 1,
"b": 2
}
```
You can also use tags in attributes:
```html
<!-- { title: 'Tags in attributes' } -->
<h1 style="color: {color};">{color}</h1>
<p hidden={hideParagraph}>You can hide this paragraph.</p>
```
```json
/* { hidden: true } */
{
color: "steelblue",
hideParagraph: false
}
```
[Boolean attributes](https://www.w3.org/TR/html5/infrastructure.html#sec-boolean-attributes) like `hidden` will be omitted if the tag expression evaluates to false.
### HTML
Ordinary tags render expressions as plain text. If you need your expression interpreted as HTML, wrap it in a special `@html` tag:
```html
<!-- { title: 'Triple tags' } -->
<p>This HTML: {content}</p>
<p>Renders as: {@html content}</p>
```
```json
/* { hidden: true } */
{
content: "Some <b>bold</b> text."
}
```
As with regular tags, you can use any JavaScript expression in HTML tags, and it will automatically update the document when your data changes.
> HTML is **not** sanitized before it is rendered! If you are displaying user input, you are responsible for first sanitizing it. Not doing so potentially opens you up to XSS attacks.
### If blocks
Control whether or not part of your template is rendered by wrapping it in an if block.
```html
<!-- { repl: false } -->
{#if user.loggedIn}
<a href="/logout">log out</a>
{/if}
{#if !user.loggedIn}
<a href="/login">log in</a>
{/if}
```
You can combine the two blocks above with `{:else}`:
```html
<!-- { repl: false } -->
{#if user.loggedIn}
<a href="/logout">log out</a>
{:else}
<a href="/login">log in</a>
{/if}
```
You can also use `{:elseif ...}`:
```html
<!--{ title: 'If, else and elseif' }-->
{#if x > 10}
<p>{x} is greater than 10</p>
{:elseif 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
```
```json
/* { hidden: true } */
{
x: 7
}
```
### Each blocks
Iterate over lists of data:
```html
<!--{ title: 'Each blocks' }-->
<h1>Cats of YouTube</h1>
<ul>
{#each cats as cat}
<li><a target="_blank" href={cat.video}>{cat.name}</a></li>
{:else}
<li>No cats :(</li>
{/each}
</ul>
```
```json
/* { hidden: true } */
{
cats: [
{
name: "Keyboard Cat",
video: "https://www.youtube.com/watch?v=J---aiyznGQ"
},
{
name: "Maru",
video: "https://www.youtube.com/watch?v=z_AbfPXTKms"
},
{
name: "Henri The Existential Cat",
video: "https://www.youtube.com/watch?v=OUtn3pvWmpg"
}
]
}
```
Else is triggered when the list is empty.
You can access the index of the current element with *expression* as *name*, *index*:
```html
<!--{ title: 'Each block indexes' }-->
<div class="grid">
{#each rows as row, y}
<div class="row">
{#each columns as column, x}
<code class="cell">
{x + 1},{y + 1}:
<strong>{row[column]}</strong>
</code>
{/each}
</div>
{/each}
</div>
```
```json
/* { hidden: true } */
{
columns: ["foo", "bar", "baz"],
rows: [
{ foo: "a", bar: "b", baz: "c" },
{ foo: "d", bar: "e", baz: "f" },
{ foo: "g", bar: "h", baz: "i" }
]
}
```
> By default, if the list `a, b, c` becomes `a, c`, Svelte will *remove* the third block and *change* the second from `b` to `c`, rather than removing `b`. If that's not what you want, use a [keyed each block](guide#keyed-each-blocks).
You can use destructuring patterns on the elements of the array:
```html
<!--{ title: 'Each block destructuring' }-->
<h1>It's the cats of YouTube again</h1>
<ul>
{#each cats as {name, video} }
<li><a target="_blank" href={video}>{name}</a></li>
{/each}
</ul>
```
```json
/* { hidden: true } */
{
cats: [
{
name: "Keyboard Cat",
video: "https://www.youtube.com/watch?v=J---aiyznGQ"
},
{
name: "Maru",
video: "https://www.youtube.com/watch?v=z_AbfPXTKms"
},
{
name: "Henri The Existential Cat",
video: "https://www.youtube.com/watch?v=OUtn3pvWmpg"
}
]
}
```
If you want to iterate over an object you can use `Object.entries(object)` which returns the object's properties as `[key, value]` pairs:
```html
<!--{ title: 'Iterating over objects' }-->
<h1>Cats and Dogs</h1>
{#each Object.entries(animals) as [animal, names]}
<p>{animal}: {names.join(" and ")}</p>
{/each}
```
```json
/* { hidden: true } */
{
animals: {
Cats: ["Buzz", "Stella"],
Dogs: ["Hector", "Victoria"]
}
}
```
### Await blocks
You can represent the three states of a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — pending, fulfilled and rejected — with an `await` block:
```html
<!--{ title: 'Await blocks' }-->
{#await promise}
<p>wait for it...</p>
{:then answer}
<p>the answer is {answer}!</p>
{:catch error}
<p>well that's odd</p>
{/await}
<script>
export default {
data() {
return {
promise: new Promise(fulfil => {
setTimeout(() => fulfil(42), 3000);
})
};
}
};
</script>
```
If the expression in `{#await expression}` *isn't* a promise, Svelte skips ahead to the `then` section.
### Directives
Directives allow you to add special instructions for adding [event handlers](guide#event-handlers), [bindings](guide#bindings), [referencing elements](guide#refs) and so on. We'll cover each of those in later stages of this guide for now, all you need to know is that directives can be identified by the `:` character:
```html
<!--{ title: 'Element directives' }-->
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>
```
```json
/* { hidden: true } */
{
count: 0
}
```
> Technically, the `:` character is used to denote namespaced attributes in HTML. These will *not* be treated as directives, if encountered.
### Debug tags
To inspect data as it changes and flows through your app, use a `{@debug ...}` tag:
```html
<!--{ title: 'Debug tags' }-->
<input bind:value=name>
{@debug name}
<h1>Hello {name}!</h1>
```
```json
/* { hidden: true } */
{
name: 'world'
}
```
This will log the value of `name` whenever it changes. If your devtools are open, changing `name` will pause execution and open the debugger.
You can debug multiple values simultaneously (`{@debug foo, bar, baz}`), or use `{@debug}` to pause execution whenever the surrounding markup is updated.
> Debug tags only have an effect when compiling with the `dev: true` compiler option.

@ -0,0 +1,142 @@
---
title: Scoped styles
---
One of Svelte's key tenets is that components should be self-contained and reusable in different contexts. Because of that, it has a mechanism for *scoping* your CSS, so that you don't accidentally clobber other selectors on the page.
### Adding styles
Your component template can have a `<style>` tag, like so:
```html
<!--{ title: 'Scoped styles' }-->
<div class="foo">
Big red Comic Sans
</div>
<style>
.foo {
color: red;
font-size: 2em;
font-family: 'Comic Sans MS';
}
</style>
```
### How it works
Open the example above in the REPL and inspect the element to see what has happened Svelte has added a `svelte-[uniqueid]` class to the element, and transformed the CSS selector accordingly. Since no other element on the page can share that selector, anything else on the page with `class="foo"` will be unaffected by our styles.
This is vastly simpler than achieving the same effect via [Shadow DOM](http://caniuse.com/#search=shadow%20dom) and works everywhere without polyfills.
> Svelte will add a `<style>` tag to the page containing your scoped styles. Dynamically adding styles may be impossible if your site has a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). If that's the case, you can use scoped styles by [server-rendering your CSS](guide#rendering-css) and using the `css: false` compiler option (or `--no-css` with the CLI).
### Cascading rules
Styles will *only* apply to the current component, unless you opt in to cascading with the `:global(...)` modifier:
<!-- TODO `cascade: false` in the REPL -->
```html
<!-- { repl: false } -->
<div>
<Widget/>
</div>
<style>
p {
/* this block will be disregarded, since
there are no <p> elements here */
color: red;
}
div :global(p) {
/* this block will be applied to any <p> elements
inside the <div>, i.e. in <Widget> */
font-weight: bold;
}
</style>
<script>
import Widget from './Widget.html';
export default {
components: { Widget }
};
</script>
```
> Scoped styles are *not* dynamic  they are shared between all instances of a component. In other words you can't use `{tags}` inside your CSS.
### Unused style removal
Svelte will identify and remove styles that are not being used in your app. It will also emit a warning so that you can remove them from the source.
For rules *not* to be removed, they must apply to the component's markup. As far as Svelte is concerned `.active` is unused in the following code and should be removed:
```html
<!-- { repl: false } -->
<div>
<p ref:paragraph>this text is not bold</p>
</div>
<style>
.active {
color: bold;
}
</style>
<script>
export default {
oncreate() {
const { active } = this.get();
if (active) this.refs.paragraph.classList.add('active');
}
};
</script>
```
Instead of manually manipulating the DOM, you should always use the `class` attribute (or the [class directive](https://svelte.technology/guide#classes)):
```html
<!-- { repl: false } -->
<div>
<p class="{active ? 'active' : ''}">this text is bold</p>
</div>
```
If that's impossible for some reason, you can use `:global(...)`:
```html
<!-- { repl: false } -->
<style>
div :global(.active) {
color: bold;
}
</style>
```
The same applies to the contents of `{@html ...}` tags.
### Special selectors
If you have a [ref](guide#refs) on an element, you can use it as a CSS selector. The `ref:*` selector has the same specificity as a class or attribute selector.
```html
<!--{ title: 'Styling with refs' }-->
<div ref:foo>
yeah!
</div>
<style>
ref:foo {
color: magenta;
font-size: 5em;
}
</style>
```

@ -0,0 +1,881 @@
---
title: Behaviours
---
As well as scoped styles and a template, components can encapsulate *behaviours*. For that, we add a `<script>` element and export an object:
```html
<!-- { title: 'Behaviours' } -->
<div>
<!-- template goes here -->
</div>
<script>
export default {
// behaviours go here
};
</script>
```
### Default data
Often, it makes sense for a component to have default data. This should be expressed as a function that returns a plain JavaScript object:
```html
<!-- { title: 'Default data' } -->
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>
<script>
export default {
data() {
return {
count: 0
};
}
};
</script>
```
Data supplied at instantiation takes priority over defaults. In other words, if we instantiated the component above like so...
```js
const counter = new Counter({
data: {
count: 99
}
});
```
...then `{count}`, or `counter.get().count`, would initially be 99 rather than 0.
### Computed properties
Often, your program will use values that depend on other values for example, you might have a filtered list, which depends on both the list *and* the filter. Normally in JavaScript you'd have to add logic to update the dependent property when *any* of the dependencies change. This is a frequent source of bugs, and it gets worse as your application grows.
Svelte allows you to express these dependencies in computed properties, which are recalculated whenever those dependencies change:
```html
<!-- { title: 'Computed properties' } -->
<p>
The time is
<strong>{hours}:{minutes}:{seconds}</strong>
</p>
<script>
export default {
data() {
return {
time: new Date()
};
},
computed: {
hours: ({ time }) => time.getHours(),
minutes: ({ time }) => time.getMinutes(),
seconds: ({ time }) => time.getSeconds()
}
};
</script>
```
Each function is passed the component's current state object. Because we're using destructuring syntax, the compiler knows that `hours`, `minutes` and `seconds` only need to re-run when `time` changes, and not when any other values change. There's no costly dependency tracking involved the dependency graph is resolved at compile time.
> `computed` must be an object literal, and the properties must be function expressions or arrow function expressions. Any external functions used in computed must be wrapped _here_:
```js
import externalFunc from '_external_file';
export default {
computed: {
externalFunc: ({ dep1, dep2 }) => externalFunc(dep1, dep2);
}
}
```
Computed properties can of course return functions. For example, we could dynamically generate a filter function for a list of items:
```html
<!-- { title: 'Filtering' } -->
<input bind:value=search>
{#each items.filter(predicate) as word}
<p><strong>{word.slice(0, search.length)}</strong>{word.slice(search.length)}</p>
{:else}
<p>no matches!</p>
{/each}
<script>
export default {
computed: {
predicate: ({ search }) => {
search = search.toLowerCase();
return word => word.startsWith(search);
}
}
};
</script>
```
```json
/* { hidden: true } */
{
search: "",
items: [
"about",
"above",
"abuse",
"actor",
"acute",
"admit",
"adopt",
"adult",
"after",
"again",
"agent",
"agree",
"ahead",
"alarm",
"album",
"alert",
"alike",
"alive",
"allow",
"alone",
"along",
"alter",
"among",
"anger",
"Angle",
"angry",
"apart",
"apple",
"apply",
"arena",
"argue",
"arise",
"array",
"aside",
"asset",
"audio",
"audit",
"avoid",
"award",
"aware",
"badly",
"baker",
"bases",
"basic",
"basis",
"beach",
"began",
"begin",
"begun",
"being",
"below",
"bench",
"billy",
"birth",
"black",
"blame",
"blind",
"block",
"blood",
"board",
"boost",
"booth",
"bound",
"brain",
"brand",
"bread",
"break",
"breed",
"brief",
"bring",
"broad",
"broke",
"brown",
"build",
"built",
"buyer",
"cable",
"calif",
"carry",
"catch",
"cause",
"chain",
"chair",
"chart",
"chase",
"cheap",
"check",
"chest",
"chief",
"child",
"china",
"chose",
"civil",
"claim",
"class",
"clean",
"clear",
"click",
"clock",
"close",
"coach",
"coast",
"could",
"count",
"court",
"cover",
"craft",
"crash",
"cream",
"crime",
"cross",
"crowd",
"crown",
"curve",
"cycle",
"daily",
"dance",
"dated",
"dealt",
"death",
"debut",
"delay",
"depth",
"doing",
"doubt",
"dozen",
"draft",
"drama",
"drawn",
"dream",
"dress",
"drill",
"drink",
"drive",
"drove",
"dying",
"eager",
"early",
"earth",
"eight",
"elite",
"empty",
"enemy",
"enjoy",
"enter",
"entry",
"equal",
"error",
"event",
"every",
"exact",
"exist",
"extra",
"faith",
"false",
"fault",
"fiber",
"field",
"fifth",
"fifty",
"fight",
"final",
"first",
"fixed",
"flash",
"fleet",
"floor",
"fluid",
"focus",
"force",
"forth",
"forty",
"forum",
"found",
"frame",
"frank",
"fraud",
"fresh",
"front",
"fruit",
"fully",
"funny",
"giant",
"given",
"glass",
"globe",
"going",
"grace",
"grade",
"grand",
"grant",
"grass",
"great",
"green",
"gross",
"group",
"grown",
"guard",
"guess",
"guest",
"guide",
"happy",
"harry",
"heart",
"heavy",
"hence",
"henry",
"horse",
"hotel",
"house",
"human",
"ideal",
"image",
"index",
"inner",
"input",
"issue",
"japan",
"jimmy",
"joint",
"jones",
"judge",
"known",
"label",
"large",
"laser",
"later",
"laugh",
"layer",
"learn",
"lease",
"least",
"leave",
"legal",
"level",
"lewis",
"light",
"limit",
"links",
"lives",
"local",
"logic",
"loose",
"lower",
"lucky",
"lunch",
"lying",
"magic",
"major",
"maker",
"march",
"maria",
"match",
"maybe",
"mayor",
"meant",
"media",
"metal",
"might",
"minor",
"minus",
"mixed",
"model",
"money",
"month",
"moral",
"motor",
"mount",
"mouse",
"mouth",
"movie",
"music",
"needs",
"never",
"newly",
"night",
"noise",
"north",
"noted",
"novel",
"nurse",
"occur",
"ocean",
"offer",
"often",
"order",
"other",
"ought",
"paint",
"panel",
"paper",
"party",
"peace",
"peter",
"phase",
"phone",
"photo",
"piece",
"pilot",
"pitch",
"place",
"plain",
"plane",
"plant",
"plate",
"point",
"pound",
"power",
"press",
"price",
"pride",
"prime",
"print",
"prior",
"prize",
"proof",
"proud",
"prove",
"queen",
"quick",
"quiet",
"quite",
"radio",
"raise",
"range",
"rapid",
"ratio",
"reach",
"ready",
"refer",
"right",
"rival",
"river",
"robin",
"roger",
"roman",
"rough",
"round",
"route",
"royal",
"rural",
"scale",
"scene",
"scope",
"score",
"sense",
"serve",
"seven",
"shall",
"shape",
"share",
"sharp",
"sheet",
"shelf",
"shell",
"shift",
"shirt",
"shock",
"shoot",
"short",
"shown",
"sight",
"since",
"sixth",
"sixty",
"sized",
"skill",
"sleep",
"slide",
"small",
"smart",
"smile",
"smith",
"smoke",
"solid",
"solve",
"sorry",
"sound",
"south",
"space",
"spare",
"speak",
"speed",
"spend",
"spent",
"split",
"spoke",
"sport",
"staff",
"stage",
"stake",
"stand",
"start",
"state",
"steam",
"steel",
"stick",
"still",
"stock",
"stone",
"stood",
"store",
"storm",
"story",
"strip",
"stuck",
"study",
"stuff",
"style",
"sugar",
"suite",
"super",
"sweet",
"table",
"taken",
"taste",
"taxes",
"teach",
"teeth",
"terry",
"texas",
"thank",
"theft",
"their",
"theme",
"there",
"these",
"thick",
"thing",
"think",
"third",
"those",
"three",
"threw",
"throw",
"tight",
"times",
"tired",
"title",
"today",
"topic",
"total",
"touch",
"tough",
"tower",
"track",
"trade",
"train",
"treat",
"trend",
"trial",
"tried",
"tries",
"truck",
"truly",
"trust",
"truth",
"twice",
"under",
"undue",
"union",
"unity",
"until",
"upper",
"upset",
"urban",
"usage",
"usual",
"valid",
"value",
"video",
"virus",
"visit",
"vital",
"voice",
"waste",
"watch",
"water",
"wheel",
"where",
"which",
"while",
"white",
"whole",
"whose",
"woman",
"women",
"world",
"worry",
"worse",
"worst",
"worth",
"would",
"wound",
"write",
"wrong",
"wrote",
"yield",
"young",
"youth"
]
}
```
### Lifecycle hooks
There are four 'hooks' provided by Svelte for adding control logic — `oncreate`, `ondestroy`, `onstate` and `onupdate`:
```html
<!-- { title: 'Lifecycle hooks' } -->
<p>
The time is
<strong>{hours}:{minutes}:{seconds}</strong>
</p>
<script>
export default {
onstate({ changed, current, previous }) {
// this fires before oncreate, and on every state change.
// the first time it runs, `previous` is undefined
if (changed.time) {
console.log(`time changed: ${previous && previous.time} -> ${current.time}`);
}
},
oncreate() {
// this fires when the component has been
// rendered to the DOM
console.log('in oncreate');
this.interval = setInterval(() => {
this.set({ time: new Date() });
}, 1000);
},
onupdate({ changed, current, previous }) {
// this fires after oncreate, and after every state change
// once the DOM is synchronised with the data
console.log(`The DOM has been updated`);
},
ondestroy() {
// this fires when the component is
// removed from the DOM
console.log('in ondestroy');
clearInterval(this.interval);
},
data() {
return {
time: new Date()
};
},
computed: {
hours: ({ time }) => time.getHours(),
minutes: ({ time }) => time.getMinutes(),
seconds: ({ time }) => time.getSeconds()
}
};
</script>
```
> You can add event listeners corresponding to `onstate`, `onupdate` and `ondestroy` programmatically — see [component.on](guide#component-on-eventname-callback-)
### Helpers
Helpers are simple functions that are used in your template. In the example above, we want to ensure that `minutes` and `seconds` are preceded with a `0` if they only have one digit, so we add a `leftPad` helper:
```html
<!-- { title: 'Helpers' } -->
<p>
The time is
<strong>{hours}:{leftPad(minutes, 2, '0')}:{leftPad(seconds, 2, '0')}</strong>
</p>
<script>
import leftPad from 'left-pad';
export default {
helpers: {
leftPad
},
oncreate() {
this.interval = setInterval(() => {
this.set({ time: new Date() });
}, 1000);
},
ondestroy() {
clearInterval(this.interval);
},
data() {
return {
time: new Date()
};
},
computed: {
hours: ({ time }) => time.getHours(),
minutes: ({ time }) => time.getMinutes(),
seconds: ({ time }) => time.getSeconds()
}
};
</script>
```
Of course, you could use `leftPad` inside the computed properties instead of in the template. There's no hard and fast rule about when you should use expressions with helpers versus when you should use computed properties  do whatever makes your component easier for the next developer to understand.
> Helper functions should be *pure* in other words, they should not have side-effects, and their returned value should only depend on their arguments.
### Custom methods
In addition to the [built-in methods](guide#component-api), you can add methods of your own:
```html
<!-- { title: 'Custom methods' } -->
<p>Try calling <code>app.say('hello!')</code> from the console</p>
<script>
export default {
methods: {
say(message) {
alert(message); // again, please don't do this
}
}
};
</script>
```
These become part of the component's API:
```js
import MyComponent from './MyComponent.html';
var component = new MyComponent({
target: document.querySelector('main')
});
component.say('👋');
```
Methods (whether built-in or custom) can also be called inside [event handlers](guide#event-handlers):
```html
<!-- { repl: false } -->
<button on:click="say('hello')">say hello!</button>
```
### Custom event handlers
Soon, we'll learn about [event handlers](guide#event-handlers) if you want, skip ahead to that section first then come back here!
Most of the time you can make do with the standard DOM events (the sort you'd add via `element.addEventListener`, such as `click`) but sometimes you might need custom events to handle gestures, for example.
Custom events are just functions that take a node and a callback as their argument, and return an object with a `destroy` method that gets called when the element is removed from the page:
```html
<!-- { title: 'Custom events' } -->
<button on:longpress="set({ done: true })">click and hold</button>
{#if done}
<p>clicked and held</p>
{/if}
<script>
export default {
events: {
longpress(node, callback) {
function onmousedown(event) {
const timeout = setTimeout(() => callback(event), 1000);
function cancel() {
clearTimeout(timeout);
node.removeEventListener('mouseup', cancel, false);
}
node.addEventListener('mouseup', cancel, false);
}
node.addEventListener('mousedown', onmousedown, false);
return {
destroy() {
node.removeEventListener('mousedown', onmousedown, false);
}
};
}
}
};
</script>
```
### Namespaces
Components are assumed to be in the HTML namespace. If your component is designed to be used inside an `<svg>` element, you need to specify the namespace:
```html
<!--{ title: 'SVG' }-->
<svg viewBox="0 0 1000 1000" style="width: 100%; height: 100%;">
<SmileyFace x=70 y=280 size=100 fill="#f4d9c7"/>
<SmileyFace x=800 y=250 size=150 fill="#40250f"/>
<SmileyFace x=150 y=700 size=110 fill="#d2aa7a"/>
<SmileyFace x=875 y=730 size=130 fill="#824e2e"/>
<SmileyFace x=450 y=500 size=240 fill="#d2b198"/>
</svg>
<script>
import SmileyFace from './SmileyFace.html';
export default {
components: { SmileyFace }
};
</script>
```
```html
<!--{ filename: 'SmileyFace.html' }-->
<!-- CC-BY-SA — https://commons.wikimedia.org/wiki/File:718smiley.svg -->
<g transform="translate({x},{y}) scale({size / 366.5})">
<circle r=366.5/>
<circle r=336.5 fill={fill}/>
<path d="m-41.5 298.5c-121-21-194-115-212-233v-8l-25-1-1-18h481c6 13 10 27 13 41 13 94-38 146-114 193-45 23-93 29-142 26z"/>
<path d="m5.5 280.5c52-6 98-28 138-62 28-25 46-56 51-87 4-20 1-57-5-70l-423-1c-2 56 39 118 74 157 31 34 72 54 116 63 11 2 38 2 49 0z" fill="#871945"/>
<path d="m-290.5 -24.5c-13-26-13-57-9-85 6-27 18-52 35-68 21-20 50-23 77-18 15 4 28 12 39 23 18 17 30 40 36 67 4 20 4 41 0 60l-6 21z"/>
<path d="m-132.5 -43.5c5-6 6-40 2-58-3-16-4-16-10-10-14 14-38 14-52 0-15-18-12-41 6-55 3-3 5-5 5-6-1-4-22-8-34-7-42 4-57.6 40-66.2 77-3 17-1 53 4 59h145.2z" fill="#fff"/>
<path d="m11.5 -23.5c-2-3-6-20-7-29-5-28-1-57 11-83 15-30 41-52 72-60 29-7 57 0 82 15 26 17 45 49 50 82 2 12 2 33 0 45-1 10-5 26-8 30z"/>
<path d="m198.5 -42.5c4-5 5-34 4-50-2-14-6-24-8-24-1 0-3 2-6 5-17 17-47 13-58-9-7-16-4-31 8-43 4-4 7-8 7-9 0 0-4-2-8-3-51-17-105 20-115 80-3 15 0 43 3 53z" fill="#fff"/>
<path d="m137.5 223.5s-46 40-105 53c-66 15-114-7-114-7s14-76 93-95c76-18 126 49 126 49z" fill="#f9bedd"/>
</g>
<script>
export default {
// you can either use the shorthand 'svg', or the full
// namespace: 'http://www.w3.org/2000/svg'. (I know
// which one I prefer.)
namespace: 'svg',
data() {
return {
x: 100,
y: 100,
size: 100
};
}
};
</script>
```

@ -0,0 +1,224 @@
---
title: Nested components
---
As well as containing elements (and `if` blocks and `each` blocks), Svelte components can contain *other* Svelte components.
```html
<!-- { title: 'Nested components' } -->
<div class='widget-container'>
<Widget/>
</div>
<script>
import Widget from './Widget.html';
export default {
components: {
Widget
}
};
</script>
```
```html
<!--{ filename: 'Widget.html' }-->
<p>I am a nested component</p>
```
That's similar to doing this...
```js
import Widget from './Widget.html';
const widget = new Widget({
target: document.querySelector('.widget-container')
});
```
...except that Svelte takes care of destroying the child component when the parent is destroyed, and keeps the two components in sync with *props*.
> Component names must be capitalised, following the widely-used JavaScript convention of capitalising constructor names. It's also an easy way to distinguish components from elements in your template.
### Props
Props, short for 'properties', are the means by which you pass data down from a parent to a child component — in other words, they're just like attributes on an element:
```html
<!--{ title: 'Props' }-->
<div class='widget-container'>
<Widget foo bar="static" baz={dynamic}/>
</div>
<script>
import Widget from './Widget.html';
export default {
components: {
Widget
}
};
</script>
```
```html
<!--{ filename: 'Widget.html' }-->
<p>foo: {foo}</p>
<p>bar: {bar}</p>
<p>baz: {baz}</p>
```
```json
/* { hidden: true } */
{
dynamic: 'try changing this text'
}
```
As with element attributes, prop values can contain any valid JavaScript expression.
Often, the name of the property will be the same as the value, in which case we can use a shorthand:
```html
<!-- { repl: false } -->
<!-- these are equivalent -->
<Widget foo={foo}/>
<Widget {foo}/>
```
> Note that props are *one-way* — to get data from a child component into a parent component, use [bindings](guide#bindings).
### Composing with `<slot>`
A component can contain a `<slot></slot>` element, which allows the parent component to inject content:
```html
<!-- { title: 'Using <slot>' } -->
<Box>
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</Box>
<script>
import Box from './Box.html';
export default {
components: { Box }
};
</script>
```
```html
<!--{ filename: 'Box.html' }-->
<div class="box">
<slot><!-- content is injected here --></slot>
</div>
<style>
.box {
border: 2px solid black;
padding: 0.5em;
}
</style>
```
The `<slot>` element can contain 'fallback content', which will be used if no children are provided for the component:
```html
<!-- { title: 'Default slot content' } -->
<Box></Box>
<script>
import Box from './Box.html';
export default {
components: { Box }
};
</script>
```
```html
<!--{ filename: 'Box.html' }-->
<div class="box">
<slot>
<p class="fallback">the box is empty!</p>
</slot>
</div>
<style>
.box {
border: 2px solid black;
padding: 0.5em;
}
.fallback {
color: #999;
}
</style>
```
You can also have *named* slots. Any elements with a corresponding `slot` attribute will fill these slots:
```html
<!-- { title: 'Named slots' } -->
<ContactCard>
<span slot="name">P. Sherman</span>
<span slot="address">42 Wallaby Way, Sydney</span>
</ContactCard>
<script>
import ContactCard from './ContactCard.html';
export default {
components: { ContactCard }
};
</script>
```
```html
<!--{ filename: 'ContactCard.html' }-->
<div class="contact-card">
<h2><slot name="name"></slot></h2>
<slot name="address">Unknown address</slot>
<br>
<slot name="email">Unknown email</slot>
</div>
<style>
.contact-card {
border: 2px solid black;
padding: 0.5em;
}
</style>
```
### Shorthand imports
As an alternative to using an `import` declaration...
```html
<!-- { repl: false } -->
<script>
import Widget from './Widget.html';
export default {
components: { Widget }
};
</script>
```
...you can write this:
```html
<!-- { repl: false } -->
<script>
export default {
components: {
Widget: './Widget.html'
}
};
</script>
```

@ -0,0 +1,183 @@
---
title: Special elements
---
Svelte includes a handful of built-in elements with special behaviour.
### `<svelte:self>`
Sometimes, a component needs to embed itself recursively — for example if you have a tree-like data structure. In Svelte, that's accomplished with the `<svelte:self>` tag:
```html
<!-- { title: '<svelte:self> tags' } -->
{#if countdown > 0}
<p>{countdown}</p>
<svelte:self countdown="{countdown - 1}"/>
{:else}
<p>liftoff!</p>
{/if}
```
```json
/* { hidden: true } */
{
countdown: 5
}
```
### `<svelte:component>`
If you don't know what kind of component to render until the app runs — in other words, it's driven by state — you can use `<svelte:component>`:
```html
<!-- { title: '<svelte:component> tags' } -->
<input type=checkbox bind:checked=foo> foo
<svelte:component this="{foo ? Red : Blue}" name="thing"/>
<script>
import Red from './Red.html';
import Blue from './Blue.html';
export default {
data() {
return { Red, Blue }
}
};
</script>
```
```html
<!--{ hidden: true, filename: 'Red.html' }-->
<p style="color: red">Red {name}</p>
```
```html
<!--{ hidden: true, filename: 'Blue.html' }-->
<p style="color: blue">Blue {name}</p>
```
> Note that `Red` and `Blue` are items in `data`, *not* `components`, unlike if we were doing `<Red>` or `<Blue>`.
The expression inside the `this="{...}"` can be any valid JavaScript expression. For example, it could be a [computed property](guide#computed-properties):
```html
<!-- { title: '<svelte:component> with computed' } -->
<label><input type=radio bind:group=size value=small> small</label>
<label><input type=radio bind:group=size value=medium> medium</label>
<label><input type=radio bind:group=size value=large> large</label>
<svelte:component this={Size}/>
<script>
import Small from './Small.html';
import Medium from './Medium.html';
import Large from './Large.html';
export default {
computed: {
Size: ({size}) => {
if (size === 'small') return Small;
if (size === 'medium') return Medium;
return Large;
}
}
};
</script>
```
```html
<!--{ filename: 'Small.html' }-->
<p style="font-size: 12px">small</p>
```
```html
<!--{ filename: 'Medium.html' }-->
<p style="font-size: 18px">medium</p>
```
```html
<!--{ filename: 'Large.html' }-->
<p style="font-size: 32px">LARGE</p>
```
```json
/* { hidden: true } */
{
size: "medium"
}
```
### `<svelte:window>`
The `<svelte:window>` tag gives you a convenient way to declaratively add event listeners to `window`. Event listeners are automatically removed when the component is destroyed.
```html
<!-- { title: '<svelte:window> tags' } -->
<svelte:window on:keydown="set({ key: event.key, keyCode: event.keyCode })"/>
{#if key}
<p><kbd>{key === ' ' ? 'Space' : key}</kbd> (code {keyCode})</p>
{:else}
<p>click in this window and press any key</p>
{/if}
<style>
kbd {
background-color: #eee;
border: 2px solid #f4f4f4;
border-right-color: #ddd;
border-bottom-color: #ddd;
font-size: 2em;
margin: 0 0.5em 0 0;
padding: 0.5em 0.8em;
font-family: Inconsolata;
}
</style>
```
You can also bind to certain values — so far `innerWidth`, `outerWidth`, `innerHeight`, `outerHeight`, `scrollX`, `scrollY` and `online`:
```html
<!-- { title: '<svelte:window> bindings' } -->
<svelte:window bind:scrollY=y/>
<div class="background"></div>
<p class="fixed">user has scrolled {y} pixels</p>
<style>
.background {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 9999px;
background: linear-gradient(to bottom, #7db9e8 0%,#0a1d33 100%);
}
.fixed {
position: fixed;
top: 1em;
left: 1em;
color: white;
}
</style>
```
### `<svelte:head>`
If you're building an application with Svelte — particularly if you're using [Sapper](https://sapper.svelte.technology) — then it's likely you'll need to add some content to the `<head>` of your page, such as adding a `<title>` element.
You can do that with the `<svelte:head>` tag:
```html
<!-- { title: '<svelte:head> tags' } -->
<svelte:head>
<title>{post.title} • My blog</title>
</svelte:head>
```
When [server rendering](guide#server-side-rendering), the `<head>` contents can be extracted separately to the rest of the markup.

@ -0,0 +1,621 @@
---
title: Directives
---
Directives are element or component-level instructions to Svelte. They look like attributes, except with a `:` character.
### Event handlers
In most applications, you'll need to respond to the user's actions. In Svelte, this is done with the `on:[event]` directive.
```html
<!-- { title: 'Event handlers' } -->
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>
```
```json
/* { hidden: true } */
{
count: 0
}
```
When the user clicks the button, Svelte calls `component.set(...)` with the provided arguments. You can call any method belonging to the component (whether [built-in](guide#component-api) or [custom](guide#custom-methods)), and any data property (or computed property) that's in scope:
```html
<!-- { title: 'Calling custom methods' } -->
<p>Select a category:</p>
{#each categories as category}
<button on:click="select(category)">select {category}</button>
{/each}
<script>
export default {
data() {
return {
categories: [
'animal',
'vegetable',
'mineral'
]
}
},
methods: {
select(name) {
alert(`selected ${name}`); // seriously, please don't do this
}
}
};
</script>
```
You can also access the `event` object in the method call:
```html
<!-- { title: 'Accessing `event`' } -->
<div on:mousemove="set({ x: event.clientX, y: event.clientY })">
coords: {x},{y}
</div>
<style>
div {
border: 1px solid purple;
width: 100%;
height: 100%;
}
</style>
```
The target node can be referenced as `this`, meaning you can do this sort of thing:
```html
<!-- { title: 'Calling node methods' } -->
<input on:focus="this.select()" value="click to select">
```
### Custom events
You can define your own custom events to handle complex user interactions like dragging and swiping. See the earlier section on [custom event handlers](guide#custom-event-handlers) for more information.
### Component events
Events are an excellent way for [nested components](guide#nested-components) to communicate with their parents. Let's revisit our earlier example, but turn it into a `<CategoryChooser>` component:
```html
<!-- { filename: 'CategoryChooser.html', repl: false } -->
<p>Select a category:</p>
{#each categories as category}
<button on:click="fire('select', { category })">select {category}</button>
{/each}
<script>
export default {
data() {
return {
categories: [
'animal',
'vegetable',
'mineral'
]
}
}
};
</script>
```
When the user clicks a button, the component will fire a `select` event, where the `event` object has a `category` property. Any component that nests `<CategoryChooser>` can listen for events like so:
```html
<!--{ title: 'Component events' }-->
<CategoryChooser on:select="playTwentyQuestions(event.category)"/>
<script>
import CategoryChooser from './CategoryChooser.html';
export default {
components: {
CategoryChooser
},
methods: {
playTwentyQuestions(category) {
alert(`ok! you chose ${category}`);
}
}
};
</script>
```
```html
<!--{ filename: 'CategoryChooser.html', hidden: true }-->
<p>Select a category:</p>
{#each categories as category}
<button on:click="fire('select', { category })">select {category}</button>
{/each}
<script>
export default {
data() {
return {
categories: [
'animal',
'vegetable',
'mineral'
]
}
}
};
</script>
```
Just as `this` in an element's event handler refers to the element itself, in a component event handler `this` refers to the component firing the event.
There is also a shorthand for listening for and re-firing an event unchanged.
```html
<!-- { repl: false } -->
<!-- these are equivalent -->
<Widget on:foo="fire('foo', event)"/>
<Widget on:foo/>
```
Since component events do not propagate as DOM events do, this can be used to pass events through intermediate components. This shorthand technique also applies to element events (`on:click` is equivalent to `on:click="fire('click', event)"`).
### Refs
Refs are a convenient way to store a reference to particular DOM nodes or components. Declare a ref with `ref:[name]`, and access it inside your component's methods with `this.refs.[name]`:
```html
<!-- { title: 'Refs' } -->
<canvas ref:canvas width=200 height=200></canvas>
<script>
import createRenderer from './createRenderer.js';
export default {
oncreate() {
const canvas = this.refs.canvas;
const ctx = canvas.getContext('2d');
const renderer = createRenderer(canvas, ctx);
this.on('destroy', renderer.stop);
}
}
</script>
```
```js
/* { filename: 'createRenderer.js', hidden: true } */
export default function createRenderer(canvas, ctx) {
let running = true;
loop();
return {
stop: () => {
running = false;
}
};
function loop() {
if (!running) return;
requestAnimationFrame(loop);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (let p = 0; p < imageData.data.length; p += 4) {
const i = p / 4;
const x = i % canvas.width;
const y = i / canvas.height >>> 0;
const t = window.performance.now();
const r = 64 + (128 * x / canvas.width) + (64 * Math.sin(t / 1000));
const g = 64 + (128 * y / canvas.height) + (64 * Math.cos(t / 1000));
const b = 128;
imageData.data[p + 0] = r;
imageData.data[p + 1] = g;
imageData.data[p + 2] = b;
imageData.data[p + 3] = 255;
}
ctx.putImageData(imageData, 0, 0);
}
}
```
> Since only one element or component can occupy a given `ref`, don't use them in `{#each ...}` blocks. It's fine to use them in `{#if ...}` blocks however.
Note that you can use refs in your `<style>` blocks — see [Special selectors](guide#special-selectors).
### Transitions
Transitions allow elements to enter and leave the DOM gracefully, rather than suddenly appearing and disappearing.
```html
<!-- { title: 'Transitions' } -->
<input type=checkbox bind:checked=visible> visible
{#if visible}
<p transition:fade>fades in and out</p>
{/if}
<script>
import { fade } from 'svelte-transitions';
export default {
transitions: { fade }
};
</script>
```
Transitions can have parameters — typically `delay` and `duration`, but often others, depending on the transition in question. For example, here's the `fly` transition from the [svelte-transitions](https://github.com/sveltejs/svelte-transitions) package:
```html
<!-- { title: 'Transition with parameters' } -->
<input type=checkbox bind:checked=visible> visible
{#if visible}
<p transition:fly="{y: 200, duration: 1000}">flies 200 pixels up, slowly</p>
{/if}
<script>
import { fly } from 'svelte-transitions';
export default {
transitions: { fly }
};
</script>
```
An element can have separate `in` and `out` transitions:
```html
<!-- { title: 'Transition in/out' } -->
<input type=checkbox bind:checked=visible> visible
{#if visible}
<p in:fly="{y: 50}" out:fade>flies up, fades out</p>
{/if}
<script>
import { fade, fly } from 'svelte-transitions';
export default {
transitions: { fade, fly }
};
</script>
```
Transitions are simple functions that take a `node` and any provided `parameters` and return an object with the following properties:
* `duration` — how long the transition takes in milliseconds
* `delay` — milliseconds before the transition starts
* `easing` — an [easing function](https://github.com/rollup/eases-jsnext)
* `css` — a function that accepts an argument `t` between 0 and 1 and returns the styles that should be applied at that moment
* `tick` — a function that will be called on every frame, with the same `t` argument, while the transition is in progress
Of these, `duration` is required, as is *either* `css` or `tick`. The rest are optional. Here's how the `fade` transition is implemented, for example:
```html
<!-- { title: 'Fade transition' } -->
<input type=checkbox bind:checked=visible> visible
{#if visible}
<p transition:fade>fades in and out</p>
{/if}
<script>
export default {
transitions: {
fade(node, { delay = 0, duration = 400 }) {
const o = +getComputedStyle(node).opacity;
return {
delay,
duration,
css: t => `opacity: ${t * o}`
};
}
}
};
</script>
```
> If the `css` option is used, Svelte will create a CSS animation that runs efficiently off the main thread. Therefore if you can achieve an effect using `css` rather than `tick`, you should.
### Bindings
As we've seen, data can be passed down to elements and components with attributes and [props](guide#props). Occasionally, you need to get data back up; for that we use bindings.
#### Component bindings
Component bindings keep values in sync between a parent and a child:
```html
<!-- { repl: false } -->
<Widget bind:childValue=parentValue/>
```
Whenever `childValue` changes in the child component, `parentValue` will be updated in the parent component and vice versa.
If the names are the same, you can shorten the declaration:
```html
<!-- { repl: false } -->
<Widget bind:value/>
```
> Use component bindings judiciously. They can save you a lot of boilerplate, but will make it harder to reason about data flow within your application if you overuse them.
#### Element bindings
Element bindings make it easy to respond to user interactions:
```html
<!-- { title: 'Element bindings' } -->
<h1>Hello {name}!</h1>
<input bind:value=name>
```
```json
/* { hidden: true } */
{
name: 'world'
}
```
Some bindings are *one-way*, meaning that the values are read-only. Most are *two-way* — changing the data programmatically will update the DOM. The following bindings are available:
| Name | Applies to | Kind |
|-----------------------------------------------------------------|----------------------------------------------|----------------------|
| `value` | `<input>` `<textarea>` `<select>` | <span>Two-way</span> |
| `checked` | `<input type=checkbox>` | <span>Two-way</span> |
| `group` (see note) | `<input type=checkbox>` `<input type=radio>` | <span>Two-way</span> |
| `currentTime` `paused` `played` `volume` | `<audio>` `<video>` | <span>Two-way</span> |
| `buffered` `duration` `seekable` | `<audio>` `<video>` | <span>One-way</span> |
| `offsetWidth` `offsetHeight` `clientWidth` `clientHeight` | All block-level elements | <span>One-way</span> |
| `scrollX` `scrollY` | `<svelte:window>` | <span>Two-way</span> |
| `online` `innerWidth` `innerHeight` `outerWidth` `outerHeight` | `<svelte:window>` | <span>One-way</span> |
> 'group' bindings allow you to capture the current value of a [set of radio inputs](repl?demo=binding-input-radio), or all the selected values of a [set of checkbox inputs](repl?demo=binding-input-checkbox-group).
Here is a complete example of using two way bindings with a form:
```html
<!-- { title: 'Form bindings' } -->
<form on:submit="handleSubmit(event)">
<input bind:value=name type=text>
<button type=submit>Say hello</button>
</form>
<script>
export default {
methods: {
handleSubmit(event) {
// prevent the page from reloading
event.preventDefault();
const { name } = this.get();
alert(`Hello ${name}!`);
}
}
};
</script>
```
```json
/* { hidden: true } */
{
name: "world"
}
```
### Actions
Actions let you decorate elements with additional functionality. Actions are functions which may return an object with lifecycle methods, `update` and `destroy`. The action will be called when its element is added to the DOM.
Use actions for things like:
* tooltips
* lazy loading images as the page is scrolled, e.g. `<img use:lazyload data-src='giant-photo.jpg'/>`
* capturing link clicks for your client router
* adding drag and drop
```html
<!-- { title: 'Actions' } -->
<button on:click="toggleLanguage()" use:tooltip="translations[language].tooltip">
{language}
</button>
<script>
export default {
actions: {
tooltip(node, text) {
const tooltip = document.createElement('div');
tooltip.textContent = text;
Object.assign(tooltip.style, {
position: 'absolute',
background: 'black',
color: 'white',
padding: '0.5em 1em',
fontSize: '12px',
pointerEvents: 'none',
transform: 'translate(5px, -50%)',
borderRadius: '2px',
transition: 'opacity 0.4s'
});
function position() {
const { top, right, bottom } = node.getBoundingClientRect();
tooltip.style.top = `${(top + bottom) / 2}px`;
tooltip.style.left = `${right}px`;
}
function append() {
document.body.appendChild(tooltip);
tooltip.style.opacity = 0;
setTimeout(() => tooltip.style.opacity = 1);
position();
}
function remove() {
tooltip.remove();
}
node.addEventListener('mouseenter', append);
node.addEventListener('mouseleave', remove);
return {
update(text) {
tooltip.textContent = text;
position();
},
destroy() {
tooltip.remove();
node.removeEventListener('mouseenter', append);
node.removeEventListener('mouseleave', remove);
}
}
}
},
methods: {
toggleLanguage() {
const { language } = this.get();
this.set({
language: language === 'english' ? 'latin' : 'english'
});
}
}
};
</script>
```
```json
/* { hidden: true } */
{
language: "english",
translations: {
english: {
tooltip: "Switch Languages",
},
latin: {
tooltip: "Itchsway Anguageslay",
},
}
}
```
### Classes
Classes let you toggle element classes on and off. To use classes add the directive `class` followed by a colon and the class name you want toggled (`class:the-class-name="anExpression"`). The expression inside the directive's quotes will be evaluated and toggle the class on and off depending on the truthiness of the expression's result. You can only add class directives to elements.
This example adds the class `active` to `<li>` elements when the `url` property matches the path their links target.
```html
<!-- { title: 'Classes' } -->
<ul class="links">
<li class:active="url === '/'"><a href="/" on:click="goto(event)">Home</a></li>
<li class:active="url.startsWith('/blog')"><a href="/blog/" on:click="goto(event)">Blog</a></li>
<li class:active="url.startsWith('/about')"><a href="/about/" on:click="goto(event)">About</a></li>
</ul>
<script>
export default {
methods: {
goto(event) {
event.preventDefault();
this.set({ url: event.target.pathname });
}
}
}
</script>
<style>
.links {
list-style: none;
}
.links li {
float: left;
padding: 10px;
}
/* classes added this way are processed with encapsulated styles, no need for :global() */
.active {
background: #eee;
}
</style>
```
```json
/* { hidden: true } */
{
"url": "/"
}
```
Classes will work with an existing class attribute on your element. If you find yourself adding multiple ternary statements inside a class attribute, classes can simplify your component. Classes are recognized by the compiler and <a href="guide#scoped-styles">scoped correctly</a>.
If your class name is the same as a property in your component's state, you can use the shorthand of a class binding which drops the expression (`class:myProp`).
Note that class names with dashes in them do not usually make good shorthand classes since the property will also need a dash in it. The example below uses a computed property to make working with this easier, but it may be easier to not use the shorthand in cases like this.
```html
<!-- { title: 'Classes shorthand' } -->
<div class:active class:is-selected class:isAdmin>
<p>Active? {active}</p>
<p>Selected? {isSelected}</p>
</div>
<button on:click="set({ active: !active })">Toggle Active</button>
<button on:click="set({ isSelected: !isSelected })">Toggle Selected</button>
<button on:click="set({ isAdmin: !isAdmin })">Toggle Admin</button>
<script>
export default {
computed: {
// Because shorthand relfects the var name, you must use component.set({ "is-selected": true }) or use a computed
// property like this. It might be better to avoid shorthand for class names which are not valid variable names.
"is-selected": ({ isSelected }) => isSelected
}
}
</script>
<style>
div {
width: 300px;
border: 1px solid #ccc;
background: #eee;
margin-bottom: 10px;
}
.active {
background: #fff;
}
.is-selected {
border-color: #99bbff;
box-shadow: 0 0 6px #99bbff;
}
.isAdmin {
outline: 2px solid red;
}
</style>
```
```json
/* { hidden: true } */
{
"active": true,
"isSelected": false,
"isAdmin": false,
}
```

@ -0,0 +1,99 @@
---
title: Plugins
---
Svelte can be extended with plugins and extra methods.
### Transition plugins
The [svelte-transitions](https://github.com/sveltejs/svelte-transitions) package includes a selection of officially supported transition plugins, such as [fade](https://github.com/sveltejs/svelte-transitions-fade), [fly](https://github.com/sveltejs/svelte-transitions-fly) and [slide](https://github.com/sveltejs/svelte-transitions-slide). You can include them in a component like so:
```html
<!-- { title: 'svelte-transitions' } -->
<label>
<input type=checkbox bind:checked=visible> visible
</label>
{#if visible}
<!-- use `in`, `out`, or `transition` (bidirectional) -->
<div transition:fly="{y:20}">hello!</div>
{/if}
<script>
import { fly } from 'svelte-transitions';
export default {
transitions: { fly }
};
</script>
```
```json
/* { hidden: true } */
{
visible: true
}
```
### Extra methods
The [svelte-extras](https://github.com/sveltejs/svelte-extras) package includes a handful of methods for tweening (animating), manipulating arrays and so on.
```html
<!-- { title: 'svelte-extras' } -->
<input bind:value=newTodo placeholder="buy milk">
<button on:click="push('todos', newTodo)">add todo</button>
<ul>
{#each todos as todo, i}
<li>
<button on:click="splice('todos', i, 1)">x</button>
{todo}
</li>
{/each}
</ul>
<style>
ul {
list-style: none;
padding: 0;
}
li button {
color: rgb(200,0,0);
background: rgba(200,0,0,0.1);
border-color: rgba(200,0,0,0.2);
padding: 0.2em 0.5em;
}
</style>
<script>
import { push, splice } from 'svelte-extras';
export default {
data() {
return {
newTodo: '',
todos: []
};
},
methods: {
push,
splice
}
};
</script>
```
```json
/* { hidden: true } */
{
todos: [
"wash the car",
"take the dog for a walk",
"mow the lawn"
]
}
```

@ -0,0 +1,37 @@
---
title: Static properties
---
### Setup
In some situations, you might want to add static properties to your component constructor. For that, we use the `setup` property:
```html
<!-- { title: 'Component setup' } -->
<p>check the console!</p>
<script>
export default {
setup(MyComponent) {
// someone importing this component will be able
// to access any properties or methods defined here:
//
// import MyComponent from './MyComponent.html';
// console.log(MyComponent.ANSWER); // 42
MyComponent.ANSWER = 42;
},
oncreate() {
console.log('the answer is', this.constructor.ANSWER);
console.dir(this.constructor);
}
};
</script>
```
### preload
If your component definition includes a `preload` function, it will be attached to the component constructor as a static method. It doesn't change the behaviour of your component in any way — instead, it's a convention that allows systems like [Sapper](https://sapper.svelte.technology) to delay rendering of a component until its data is ready.
See the section on [preloading](https://sapper.svelte.technology/guide#preloading) in the Sapper docs for more information.

@ -0,0 +1,95 @@
---
title: Server-side rendering
---
So far, we've discussed creating Svelte components *on the client*, which is to say the browser. But you can also render Svelte components in Node.js. This can result in better perceived performance as it means the application starts rendering while the page is still downloading, before any JavaScript executes. It also has SEO advantages in some cases, and can be beneficial for people running older browsers that can't or won't run your JavaScript for whatever reason.
### Using the compiler
If you're using the Svelte compiler, whether directly or via an integration like [rollup-plugin-svelte](https://github.com/rollup/rollup-plugin-svelte) or [svelte-loader](https://github.com/sveltejs/svelte-loader), you can tell it to generate a server-side component by passing the `generate: 'ssr'` option:
```js
const { js } = svelte.compile(source, {
generate: 'ssr' // as opposed to 'dom', the default
});
```
### Registering Svelte
Alternatively, an easy way to use the server-side renderer is to *register* it:
```js
require('svelte/ssr/register');
```
Now you can `require` your components:
```js
const Thing = require('./components/Thing.html');
```
If you prefer to use a different file extension, you can pass options like so:
```js
require('svelte/ssr/register')({
extensions: ['.svelte']
});
```
### Server-side API
Components have a different API in Node.js rather than creating instances with `set(...)` and `get()` methods, a component is an object with a `render(data, options)` method:
```js
require('svelte/ssr/register');
const Thing = require('./components/Thing.html');
const data = { answer: 42 };
const { html, css, head } = Thing.render(data);
```
All your [default data](guide#default-data), [computed properties](guide#computed-properties), [helpers](guide#helpers) and [nested components](guide#nested-components) will work as expected.
Any `oncreate` functions or component methods will *not* run — these only apply to client-side components.
> The SSR compiler will generate a CommonJS module for each of your components meaning that `import` and `export` statements are converted into their `require` and `module.exports` equivalents. If your components have non-component dependencies, they must also work as CommonJS modules in Node. If you're using ES2015 modules, we recommend the [`esm`](https://github.com/standard-things/esm) module for automatically converting them to CommonJS.
#### Using stores
If your components use [stores](guide#state-management), use the second argument:
```js
const { Store } = require('svelte/store.umd.js');
const { html } = Thing.render(data, {
store: new Store({
foo: 'bar'
})
});
```
#### Rendering styles
You can also extract any [scoped styles](guide#scoped-styles) that are used by the component or its children:
```js
const { css } = Thing.render(data);
```
You could put the resulting `css` in a separate stylesheet, or include them in the page inside a `<style>` tag. If you do this, you will probably want to prevent the client-side compiler from including the CSS again. For the CLI, use the `--no-css` flag. In build tool integrations like `rollup-plugin-svelte`, pass the `css: false` option.
#### Rendering `<head>` contents
If your component, any of its children, use the `<svelte:head>` [component](guide#-head-tags), you can extract the contents:
```js
const { head } = Thing.render(data);
```

@ -0,0 +1,304 @@
---
title: State management
---
Svelte components have built-in state management via the `get` and `set` methods. But as your application grows beyond a certain size, you may find that passing data between components becomes laborious.
For example, you might have an `<Options>` component inside a `<Sidebar>` component that allows the user to control the behaviour of a `<MainView>` component. You could use bindings or events to 'send' information up from `<Options>` through `<Sidebar>` to a common ancestor — say `<App>` — which would then have the responsibility of sending it back down to `<MainView>`. But that's cumbersome, especially if you decide you want to break `<MainView>` up into a set of smaller components.
Instead, a popular solution to this problem is to use a *global store* of data that cuts across your component hierarchy. React has [Redux](https://redux.js.org/) and [MobX](https://mobx.js.org/index.html) (though these libraries can be used anywhere, including with Svelte), and Vue has [Vuex](https://vuex.vuejs.org/en/).
Svelte has `Store`. `Store` can be used in any JavaScript app, but it's particularly well-suited to Svelte apps.
### The basics
Import `Store` from `svelte/store.js` (remember to include the curly braces, as it's a *named import*), then create a new store with some (optional) data:
```js
import { Store } from 'svelte/store.js';
const store = new Store({
name: 'world'
});
```
Each instance of `Store` has `get`, `set`, `on` and `fire` methods that behave identically to their counterparts on a Svelte component:
```js
const { name } = store.get(); // 'world'
store.on('state', ({ current }) => {
console.log(`hello ${current.name}`);
});
store.set({ name: 'everybody' }); // 'hello everybody'
```
### Creating components with stores
Let's adapt our [very first example](guide#understanding-svelte-components):
```html
<!-- { repl: false } -->
<h1>Hello {$name}!</h1>
<Greeting/>
<script>
import Greeting from './Greeting.html';
export default {
components: { Greeting }
};
</script>
```
```html
<!--{ filename: 'Greeting.html' }-->
<p>It's nice to see you, {$name}</p>
```
```js
/* { filename: 'main.js' } */
import App from './App.html';
import { Store } from 'svelte/store.js';
const store = new Store({
name: 'world'
});
const app = new App({
target: document.querySelector('main'),
store
});
window.store = store; // useful for debugging!
```
There are three important things to notice:
* We're passing `store` to `new App(...)` instead of `data`
* The template refers to `$name` instead of `name`. The `$` prefix tells Svelte that `name` is a *store property*
* Because `<Greeting>` is a child of `<App>`, it also has access to the store. Without it, `<App>` would have to pass the `name` property down as a component property (`<Greeting name={name}/>`)
Components that depend on store properties will re-render whenever they change.
### Declarative stores
As an alternative to adding the `store` option when instantiating, the component itself can declare a dependency on a store:
```html
<!-- { title: 'Declarative stores' } -->
<h1>Hello {$name}!</h1>
<Greeting/>
<script>
import Greeting from './Greeting.html';
import store from './store.js';
export default {
store: () => store,
components: { Greeting }
};
</script>
```
```html
<!--{ filename: 'Greeting.html' }-->
<p>It's nice to see you, {$name}</p>
```
```js
/* { filename: 'store.js' } */
import { Store } from 'svelte/store.js';
export default new Store({ name: 'world' });
```
Note that the `store` option is a function that *returns* a store, rather than the store itself — this provides greater flexibility.
### Computed store properties
Just like components, stores can have computed properties:
```js
store = new Store({
width: 10,
height: 10,
depth: 10,
density: 3
});
store.compute(
'volume',
['width', 'height', 'depth'],
(width, height, depth) => width * height * depth
);
store.get().volume; // 1000
store.set({ width: 20 });
store.get().volume; // 2000
store.compute(
'mass',
['volume', 'density'],
(volume, density) => volume * density
);
store.get().mass; // 6000
```
The first argument is the name of the computed property. The second is an array of *dependencies* — these can be data properties or other computed properties. The third argument is a function that recomputes the value whenever the dependencies change.
A component that was connected to this store could reference `{$volume}` and `{$mass}`, just like any other store property.
### Accessing the store inside components
Each component gets a reference to `this.store`. This allows you to attach behaviours in `oncreate`...
```html
<!-- { repl: false } -->
<script>
export default {
oncreate() {
const listener = this.store.on('state', ({ current }) => {
// ...
});
// listeners are not automatically removed — cancel
// them to prevent memory leaks
this.on('destroy', listener.cancel);
}
};
</script>
```
...or call store methods in your event handlers, using the same `$` prefix as data properties:
```html
<!-- { repl: false } -->
<button on:click="$set({ muted: true })">
Mute audio
</button>
```
### Custom store methods
`Store` doesn't have a concept of *actions* or *commits*, like Redux and Vuex. Instead, state is always updated with `store.set(...)`.
You can implement custom logic by subclassing `Store`:
```js
class TodoStore extends Store {
addTodo(description) {
const todo = {
id: generateUniqueId(),
done: false,
description
};
const todos = this.get().todos.concat(todo);
this.set({ todos });
}
toggleTodo(id) {
const todos = this.get().todos.map(todo => {
if (todo.id === id) {
return {
id,
done: !todo.done,
description: todo.description
};
}
return todo;
});
this.set({ todos });
}
}
const store = new TodoStore({
todos: []
});
store.addTodo('Finish writing this documentation');
```
Methods can update the store asynchronously:
```js
class NasdaqTracker extends Store {
async fetchStockPrices(ticker) {
const token = this.token = {};
const prices = await fetch(`/api/prices/${ticker}`).then(r => r.json());
if (token !== this.token) return; // invalidated by subsequent request
this.set({ prices });
}
}
const store = new NasdaqTracker();
store.fetchStockPrices('AMZN');
```
You can call these methods in your components, just like the built-in methods:
```html
<!-- { repl: false } -->
<input
placeholder="Enter a stock ticker"
on:change="$fetchStockPrices(this.value)"
>
```
### Store bindings
You can bind to store values just like you bind to component values — just add the `$` prefix:
```html
<!-- { repl: false } -->
<!-- global audio volume control -->
<input bind:value=$volume type=range min=0 max=1 step=0.01>
```
### Using store properties in computed properties
Just as in templates, you can access store properties in component computed properties by prefixing them with `$`:
```html
<!-- { repl: false } -->
{#if isVisible}
<div class="todo {todo.done ? 'done': ''}">
{todo.description}
</div>
{/if}
<script>
export default {
computed: {
// `todo` is a component property, `$filter` is
// a store property
isVisible: ({ todo, $filter }) => {
if ($filter === 'all') return true;
if ($filter === 'done') return todo.done;
if ($filter === 'pending') return !todo.done;
}
}
};
</script>
```
### Built-in optimisations
The Svelte compiler knows which store properties your components are interested in (because of the `$` prefix), and writes code that only listens for changes to those properties. Because of that, you needn't worry about having many properties on your store, even ones that update frequently — components that don't use them will be unaffected.

@ -0,0 +1,61 @@
---
title: Preprocessing
---
Some developers like to use non-standard languages such as [Pug](https://pugjs.org/api/getting-started.html), [Sass](http://sass-lang.com/) or [CoffeeScript](http://coffeescript.org/).
It's possible to use these languages, or anything else that can be converted to HTML, CSS and JavaScript, using *preprocessors*.
### svelte.preprocess
Svelte exports a `preprocess` function that takes some input source code and returns a Promise for a standard Svelte component, ready to be used with `svelte.compile`:
```js
const svelte = require('svelte');
const input = fs.readFileSync('App.html', 'utf-8');
svelte.preprocess(input, {
filename: 'App.html', // this is passed to each preprocessor
markup: ({ content, filename }) => {
return {
code: '<!-- some HTML -->',
map: {...}
};
},
style: ({ content, attributes, filename }) => {
return {
code: '/* some CSS */',
map: {...}
};
},
script: ({ content, attributes, filename }) => {
return {
code: '// some JavaScript',
map: {...}
};
}
}).then(preprocessed => {
fs.writeFileSync('preprocessed/App.html', preprocessed.toString());
const { js } = svelte.compile(preprocessed);
fs.writeFileSync('compiled/App.js', js.code);
});
```
The `markup` preprocessor, if specified, runs first. The `content` property represents the entire input string.
The `style` and `script` preprocessors receive the contents of the `<style>` and `<script>` elements respectively, along with any `attributes` on those elements (e.g. `<style lang='scss'>`).
All three preprocessors are optional. Each should return a `{ code, map }` object or a Promise that resolves to a `{ code, map }` object, where `code` is the resulting string and `map` is a sourcemap representing the transformation.
> The returned `map` objects are not currently used by Svelte, but will be in future versions
### Using build tools
Many build tool plugins, such as [rollup-plugin-svelte](https://github.com/rollup/rollup-plugin-svelte) and [svelte-loader](https://github.com/sveltejs/svelte-loader), allow you to specify `preprocess` options, in which case the build tool will do the grunt work.

@ -0,0 +1,150 @@
---
title: Advanced
---
### Keyed each blocks
Associating a *key* with a block allows Svelte to be smarter about how it adds and removes items to and from a list. To do so, add an `(expression)` that uniquely identifies each member of the list:
```html
<!-- { repl: false } -->
{#each people as person (person.name)}
<div>{person.name}</div>
{/each}
```
It's easier to show the effect of this than to describe it. Open the following example in the REPL:
```html
<!-- { title: 'Keyed each blocks' } -->
<button on:click="update()">update</button>
<section>
<h2>Keyed</h2>
{#each people as person (person.name)}
<div transition:slide>{person.name}</div>
{/each}
</section>
<section>
<h2>Non-keyed</h2>
{#each people as person}
<div transition:slide>{person.name}</div>
{/each}
</section>
<style>
button {
display: block;
}
section {
width: 10em;
float: left;
}
</style>
<script>
import { slide } from 'svelte-transitions';
var people = ['Alice', 'Barry', 'Cecilia', 'Douglas', 'Eleanor', 'Felix', 'Grace', 'Horatio', 'Isabelle'];
function random() {
return people
.filter(() => Math.random() < 0.5)
.map(name => ({ name }))
}
export default {
data() {
return { people: random() };
},
methods: {
update() {
this.set({ people: random() });
}
},
transitions: { slide }
};
</script>
```
### Hydration
If you're using [server-side rendering](guide#server-side-rendering), it's likely that you'll need to create a client-side version of your app *on top of* the server-rendered version. A naive way to do that would involve removing all the existing DOM and rendering the client-side app in its place:
```js
import App from './App.html';
const target = document.querySelector('#element-with-server-rendered-html');
// avoid doing this!
target.innerHTML = '';
new App({
target
});
```
Ideally, we want to reuse the existing DOM instead. This process is called *hydration*. First, we need to tell the compiler to include the code necessary for hydration to work by passing the `hydratable: true` option:
```js
const { js } = svelte.compile(source, {
hydratable: true
});
```
(Most likely, you'll be passing this option to [rollup-plugin-svelte](https://github.com/rollup/rollup-plugin-svelte) or [svelte-loader](https://github.com/sveltejs/svelte-loader).)
Then, when we instantiate the client-side component, we tell it to use the existing DOM with `hydrate: true`:
```js
import App from './App.html';
const target = document.querySelector('#element-with-server-rendered-html');
new App({
target,
hydrate: true
});
```
> It doesn't matter if the client-side app doesn't perfectly match the server-rendered HTML — Svelte will repair the DOM as it goes.
### Immutable
Because arrays and objects are *mutable*, Svelte must err on the side of caution when deciding whether or not to update things that refer to them.
But if all your data is [immutable](https://en.wikipedia.org/wiki/Immutable_object), you can use the `{ immutable: true }` compiler option to use strict object comparison (using `===`) everywhere in your app. If you have one component that uses immutable data you can set it to use the strict comparison for just that component.
In the example below, `searchResults` would normally be recalculated whenever `items` *might* have changed, but with `immutable: true` it will only update when `items` has *definitely* changed. This can improve the performance of your app.
```html
<!-- { repl: false } -->
{#each searchResults as item}
<div>{item.name}</div>
{/each}
<script>
import FuzzySearch from 'fuzzy-search';
export default {
immutable: true,
computed: {
searchResults: ({ searchString, items }) => {
if (!searchString) return items;
const searcher = new FuzzySearch(items, ['name', 'location']);
return searcher.search(searchString);
}
}
}
</script>
```
[Here's a live example](repl?demo=immutable) showing the effect of `immutable: true`.

@ -0,0 +1,109 @@
---
title: Custom elements
---
[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements) are an emerging web standard for creating DOM elements that encapsulate styles and behaviours, much like Svelte components. They are part of the [web components](https://developer.mozilla.org/en-US/docs/Web/Web_Components) family of specifications.
> Most browsers need [polyfills](https://www.webcomponents.org/polyfills) for custom elements. See [caniuse](https://caniuse.com/#feat=custom-elementsv1) for more details
Svelte components can be used as custom elements by doing the following:
1. Declaring a `tag` name. The value must contain a hyphen (`hello-world` in the example below)
2. Specifying `customElement: true` in the compiler configuration
```html
<!-- { filename: 'HelloWorld.html', repl: false } -->
<h1>Hello {name}!</h1>
<script>
export default {
tag: 'hello-world'
};
</script>
```
Importing this file will now register a globally-available `<hello-world>` custom element that accepts a `name` property:
```js
import './HelloWorld.html';
document.body.innerHTML = `<hello-world name="world"/>`;
const el = document.querySelector('hello-world');
el.name = 'everybody';
```
See [svelte-custom-elements.surge.sh](http://svelte-custom-elements.surge.sh/) ([source here](https://github.com/sveltejs/template-custom-element)) for a larger example.
The compiled custom elements are still full-fledged Svelte components and can be used as such:
```js
el.get().name === el.name; // true
el.set({ name: 'folks' }); // equivalent to el.name = 'folks'
```
One crucial difference is that styles are *fully encapsulated* — whereas Svelte will prevent component styles from leaking *out*, custom elements use [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM) which also prevents styles from leaking *in*.
### Using `<slot>`
Custom elements can use [slots](guide#composing-with-slot) to place child elements, just like regular Svelte components.
### Firing events
You can dispatch events inside custom elements to pass data out:
```js
// inside a component method
const event = new CustomEvent('message', {
detail: 'Hello parent!',
bubbles: true,
cancelable: true,
composed: true // makes the event jump shadow DOM boundary
});
this.dispatchEvent(event);
```
Other parts of the application can listen for these events with `addEventListener`:
```js
const el = document.querySelector('hello-world');
el.addEventListener('message', event => {
alert(event.detail);
});
```
> Note the `composed: true` attribute of the custom event. It enables the custom DOM event to cross the shadow DOM boundary and enter into main DOM tree.
### Observing properties
Svelte will determine, from the template and `computed` values, which properties the custom element has — for example, `name` in our `<hello-world>` example. You can specify this list of properties manually, for example to restrict which properties are 'visible' to the rest of your app:
```js
export default {
tag: 'my-thing',
props: ['foo', 'bar']
};
```
### Compiler options
Earlier, we saw the use of `customElement: true` to instruct the Svelte compiler to generate a custom element using the `tag` and (optional) `props` declared inside the component file.
Alternatively, you can pass `tag` and `props` direct to the compiler:
```js
const { js } = svelte.compile(source, {
customElement: {
tag: 'overridden-tag-name',
props: ['yar', 'boo']
}
});
```
These options will override the component's own settings, if any.
### Transpiling
* Custom elements use ES2015 classes (`MyThing extends HTMLElement`). Make sure you don't transpile the custom element code to ES5, and use a ES2015-aware minifier such as [uglify-es](https://www.npmjs.com/package/uglify-es).
* If you do need ES5 support, make sure to use `Reflect.construct` aware transpiler plugin such as [babel-plugin-transform-builtin-classes](https://github.com/WebReflection/babel-plugin-transform-builtin-classes) and a polyfill like [custom-elements-es5-adapterjs](https://github.com/webcomponents/webcomponentsjs#custom-elements-es5-adapterjs).

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save