mirror of https://github.com/sveltejs/svelte
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
7.8 KiB
202 lines
7.8 KiB
2 years ago
|
---
|
||
|
title: Svelte v2 is out!
|
||
|
description: Here's what you need to know
|
||
|
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 [Discord chatroom](https://svelte.dev/chat).
|
||
|
|
||
|
- Install Svelte v2 from npm
|
||
|
- Upgrade your templates with [svelte-upgrade](https://github.com/sveltejs/svelte-upgrade)
|
||
|
- Remove calls to `component.observe`, or add the `observe` method from [svelte-extras](https://github.com/sveltejs/svelte-extras)
|
||
|
- Rewrite calls to `component.get('foo')` as `component.get().foo`
|
||
|
- Return `destroy` from your custom event handlers, rather than `teardown`
|
||
|
- 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.
|
||
|
|
||
2 years ago
|
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.
|
||
2 years ago
|
|
||
|
<aside>If you need to show an actual `{` character, it's as easy as `&#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:
|
||
|
|
||
2 years ago
|
```svelte
|
||
2 years ago
|
<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...
|
||
|
|
||
2 years ago
|
```ts
|
||
|
// @noErrors
|
||
2 years ago
|
export default {
|
||
|
computed: {
|
||
2 years ago
|
d: (a, b, c) => (a = b + c)
|
||
2 years ago
|
}
|
||
|
};
|
||
|
```
|
||
|
|
||
2 years ago
|
...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!
|
||
2 years ago
|
|
||
|
In v2, we use [destructuring](http://www.jstips.co/en/javascript/use-destructuring-in-function-parameters/) instead:
|
||
|
|
||
2 years ago
|
```ts
|
||
|
// @noErrors
|
||
2 years ago
|
export default {
|
||
|
computed: {
|
||
2 years ago
|
d: ({ a, b, c }) => (a = b + c)
|
||
2 years ago
|
}
|
||
|
};
|
||
|
```
|
||
|
|
||
|
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... 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](https://babeljs.io/repl) or [Bublé](https://buble.surge.sh/).
|
||
|
|
||
|
## New lifecycle hooks
|
||
|
|
||
|
In addition to `oncreate` and `ondestroy`, Svelte v2 adds two more [lifecycle hooks](https://v2.svelte.dev/guide#lifecycle-hooks) for responding to state changes:
|
||
|
|
||
|
```js
|
||
2 years ago
|
// @noErrors
|
||
2 years ago
|
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
|
||
2 years ago
|
// @noErrors
|
||
2 years ago
|
component.on('state', ({ changed, current, previous }) => {
|
||
|
// ...
|
||
|
});
|
||
|
```
|
||
|
|
||
|
## component.observe
|
||
|
|
||
|
With the new lifecycle hooks, we no longer need the `component.observe(...)` method:
|
||
|
|
||
|
```js
|
||
2 years ago
|
// @noErrors
|
||
2 years ago
|
// 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}`);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
```
|
||
|
|
||
2 years ago
|
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.
|
||
2 years ago
|
|
||
|
However, if you prefer to use `component.observe(...)`, then you can install it from [svelte-extras](https://github.com/sveltejs/svelte-extras):
|
||
|
|
||
|
```js
|
||
2 years ago
|
// @noErrors
|
||
2 years ago
|
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
|
||
2 years ago
|
// @noErrors
|
||
2 years ago
|
// 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
|
||
|
|
||
2 years ago
|
If your app has [custom event handlers](https://v2.svelte.dev/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).
|
||
2 years ago
|
|
||
|
## No more type coercion
|
||
|
|
||
|
Previously, numeric values passed to components were treated as numbers:
|
||
|
|
||
2 years ago
|
```svelte
|
||
|
<Counter start="1" />
|
||
2 years ago
|
```
|
||
|
|
||
|
That causes unexpected behaviour, and has been changed: if you need to pass a literal number, do so as an expression:
|
||
|
|
||
2 years ago
|
```svelte
|
||
|
<Counter start={1} />
|
||
2 years ago
|
```
|
||
|
|
||
|
## 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
|
||
2 years ago
|
// @noErrors
|
||
2 years ago
|
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 [Discord chatroom](https://svelte.dev/chat) or raise an issue on the [tracker](https://github.com/sveltejs/svelte/issues).
|