diff --git a/.gitignore b/.gitignore
index b0e6896dbe..7a14244929 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,5 +33,8 @@ _output
/site/static/svelte-app.json
/site/static/contributors.jpg
/site/static/workers
+/site/static/organisations
/site/scripts/svelte-app
+/site/scripts/community
/site/src/routes/_contributors.js
+/site/src/routes/_components/WhosUsingSvelte.svelte
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4cf25421f6..bc6cf36109 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,25 @@
## Unreleased
+* Disallow two-way binding to a variable declared by an `{#await}` block ([#4012](https://github.com/sveltejs/svelte/issues/4012))
+* Allow access to `let:` variables in sibling attributes on slot root ([#4173](https://github.com/sveltejs/svelte/issues/4173))
+* Add some more known globals ([#4276](https://github.com/sveltejs/svelte/pull/4276))
+
+## 3.17.1
+
+* Only attach SSR mode markers to a component's `
` elements when compiling with `hydratable: true` ([#4258](https://github.com/sveltejs/svelte/issues/4258))
+
+## 3.17.0
+
+* Remove old `` elements during hydration so they aren't duplicated ([#1607](https://github.com/sveltejs/svelte/issues/1607))
* Prevent text input cursor jumping in Safari with one-way binding ([#3449](https://github.com/sveltejs/svelte/issues/3449))
* Expose compiler version in dev events ([#4047](https://github.com/sveltejs/svelte/issues/4047))
+* Don't run actions before their element is in the document ([#4166](https://github.com/sveltejs/svelte/issues/4166))
+* Fix reactive assignments with destructuring and stores where the destructured value should be undefined ([#4170](https://github.com/sveltejs/svelte/issues/4170))
+* Fix hydrating `{:else}` in `{#each}` ([#4202](https://github.com/sveltejs/svelte/issues/4202))
+* Do not automatically declare variables in reactive declarations when assigning to a member expression ([#4212](https://github.com/sveltejs/svelte/issues/4212))
+* Fix stringifying of attributes in SSR mode when there are spread attributes ([#4240](https://github.com/sveltejs/svelte/issues/4240))
+* Only render one `` in SSR mode when multiple components provide one ([#4250](https://github.com/sveltejs/svelte/pull/4250))
## 3.16.7
diff --git a/package-lock.json b/package-lock.json
index 6dc707c8d5..9ee0b53af6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "svelte",
- "version": "3.16.7",
+ "version": "3.17.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 9c249f499f..c7ac32f3ae 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "svelte",
- "version": "3.16.7",
+ "version": "3.17.1",
"description": "Cybernetically enhanced web apps",
"module": "index.mjs",
"main": "index",
diff --git a/site/content/docs/01-component-format.md b/site/content/docs/01-component-format.md
index 3d349af51d..e541292e13 100644
--- a/site/content/docs/01-component-format.md
+++ b/site/content/docs/01-component-format.md
@@ -147,24 +147,7 @@ If a statement consists entirely of an assignment to an undeclared variable, Sve
---
-A *store* is any object that allows reactive access to a value via a simple *store contract*.
-
-The [`svelte/store` module](docs#svelte_store) contains minimal store implementations which fulfil this contract. You can use these as the basis for your own stores, or you can implement your stores from scratch.
-
-A store must contain a `.subscribe` method, which must accept as its argument a subscription function. This subscription function must be immediately and synchronously called with the store's current value upon calling `.subscribe`. All of a store's active subscription functions must later be synchronously called whenever the store's value changes. The `.subscribe` method must also return an unsubscription function. Calling an unsubscription function must stop its subscription, and its corresponding subscription function must not be called again by the store.
-
-A store may optionally contain a `.set` method, which must accept as its argument a new value for the store, and which synchronously calls all of the store's active subscription functions. Such a store is called a *writable store*.
-
-```js
-const unsubscribe = store.subscribe(value => {
- console.log(value);
-}); // logs `value`
-
-// later...
-unsubscribe();
-```
-
----
+A *store* is an object that allows reactive access to a value via a simple *store contract*. The [`svelte/store` module](docs#svelte_store) contains minimal store implementations which fulfil this contract.
Any time you have a reference to a store, you can access its value inside a component by prefixing it with the `$` character. This causes Svelte to declare the prefixed variable, and set up a store subscription that will be unsubscribed when appropriate.
@@ -189,6 +172,20 @@ Local variables (that do not represent store values) must *not* have a `$` prefi
```
+##### Store contract
+
+```js
+store = { subscribe: (subscription: (value: any) => void) => () => void, set?: (value: any) => void }
+```
+
+You can create your own stores without relying on [`svelte/store`](docs#svelte_store), by implementing the *store contract*:
+
+1. A store must contain a `.subscribe` method, which must accept as its argument a subscription function. This subscription function must be immediately and synchronously called with the store's current value upon calling `.subscribe`. All of a store's active subscription functions must later be synchronously called whenever the store's value changes.
+2. The `.subscribe` method must return an unsubscribe function. Calling an unsubscribe function must stop its subscription, and its corresponding subscription function must not be called again by the store.
+3. A store may *optionally* contain a `.set` method, which must accept as its argument a new value for the store, and which synchronously calls all of the store's active subscription functions. Such a store is called a *writable store*.
+
+For interoperability with RxJS Observables, the `.subscribe` method is also allowed to return an object with an `.unsubscribe` method, rather than return the unsubscription function directly. Note however that unless `.subscribe` synchronously calls the subscription (which is not required by the Observable spec), Svelte will see the value of the store as `undefined` until it does.
+
### <script context="module">
@@ -256,3 +253,15 @@ To apply styles to a selector globally, use the `:global(...)` modifier.
}
```
+
+---
+
+If you want to make @keyframes that are accessible globally, you need to prepend your keyframe names with `-global-`.
+
+The `-global-` part will be removed when compiled, and the keyframe then be referenced using just `my-animation-name` elsewhere in your code.
+
+```html
+
+```
diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md
index b069c8abc0..0a4ca2ee1a 100644
--- a/site/content/docs/02-template-syntax.md
+++ b/site/content/docs/02-template-syntax.md
@@ -205,6 +205,8 @@ Iterating over lists of values can be done with an each block.
```
+You can use each blocks to iterate over any array or array-like value — that is, any object with a `length` property.
+
---
An each block can also specify an *index*, equivalent to the second argument in an `array.map(...)` callback:
@@ -1016,7 +1018,7 @@ DOMRect {
top: number,
width: number,
x: number,
- y:number
+ y: number
}
```
diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md
index 5bcbe8764c..c75ec694d9 100644
--- a/site/content/docs/03-run-time.md
+++ b/site/content/docs/03-run-time.md
@@ -214,7 +214,11 @@ Events dispatched from child components can be listened to in their parent. Any
### `svelte/store`
-The `svelte/store` module exports functions for creating [stores](docs#4_Prefix_stores_with_$_to_access_their_values).
+The `svelte/store` module exports functions for creating [readable](docs#readable), [writable](docs#writable) and [derived](docs#derived) stores.
+
+Keep in mind that you don't *have* to use these functions to enjoy the [reactive `$store` syntax](docs#4_Prefix_stores_with_$_to_access_their_values) in your components. Any object that correctly implements `.subscribe`, unsubscribe, and (optionally) `.set` is a valid store, and will work both with the special syntax, and with Svelte's built-in [`derived` stores](docs#derived).
+
+This makes it possible to wrap almost any other reactive state handling library for use in Svelte. Read more about the [store contract](docs#Store_contract) to see what a correct implementation looks like.
#### `writable`
@@ -883,7 +887,7 @@ Existing children of `target` are left where they are.
---
-The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](docs#svelte_compile).
+The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](docs#svelte_compile). Hydration of `` elements only works properly if the server-side rendering code was also compiled with `hydratable: true`, which adds a marker to each element in the `` so that the component knows which elements it's responsible for removing during hydration.
Whereas children of `target` are normally left alone, `hydrate: true` will cause any children to be removed. For that reason, the `anchor` option cannot be used alongside `hydrate: true`.
diff --git a/site/content/docs/04-compile-time.md b/site/content/docs/04-compile-time.md
index 45e4d3a4b4..262639d1da 100644
--- a/site/content/docs/04-compile-time.md
+++ b/site/content/docs/04-compile-time.md
@@ -68,7 +68,7 @@ The following options can be passed to the compiler. None are required:
| `generate` | `"dom"` | If `"dom"`, Svelte emits a JavaScript class for mounting to the DOM. If `"ssr"`, Svelte emits an object with a `render` method suitable for server-side rendering. If `false`, no JavaScript or CSS is returned; just metadata.
| `dev` | `false` | If `true`, causes extra code to be added to components that will perform runtime checks and provide debugging information during development.
| `immutable` | `false` | If `true`, tells the compiler that you promise not to mutate any objects. This allows it to be less conservative about checking whether values have changed.
-| `hydratable` | `false` | If `true`, enables the `hydrate: true` runtime option, which allows a component to upgrade existing DOM rather than creating new DOM from scratch.
+| `hydratable` | `false` | If `true` when generating DOM code, enables the `hydrate: true` runtime option, which allows a component to upgrade existing DOM rather than creating new DOM from scratch. When generating SSR code, this adds markers to `` elements so that hydration knows which to replace.
| `legacy` | `false` | If `true`, generates code that will work in IE9 and IE10, which don't support things like `element.dataset`.
| `accessors` | `false` | If `true`, getters and setters will be created for the component's props. If `false`, they will only be created for readonly exported values (i.e. those declared with `const`, `class` and `function`). If compiling with `customElement: true` this option defaults to `true`.
| `customElement` | `false` | If `true`, tells the compiler to generate a custom element constructor instead of a regular Svelte component.
diff --git a/site/package.json b/site/package.json
index d841808a2a..a94d264217 100644
--- a/site/package.json
+++ b/site/package.json
@@ -7,7 +7,7 @@
"copy-workers": "rm -rf static/workers && cp -r node_modules/@sveltejs/svelte-repl/workers static",
"migrate": "node-pg-migrate -r dotenv/config",
"sapper": "npm run copy-workers && sapper build --legacy",
- "update": "node scripts/update_template.js && node scripts/get-contributors.js",
+ "update": "node scripts/update_template.js && node scripts/get-contributors.js && node scripts/update_whos_using.js",
"start": "node __sapper__/build",
"test": "mocha -r esm test/**",
"deploy": "make deploy"
diff --git a/site/scripts/update_whos_using.js b/site/scripts/update_whos_using.js
new file mode 100644
index 0000000000..131a162359
--- /dev/null
+++ b/site/scripts/update_whos_using.js
@@ -0,0 +1,12 @@
+const sh = require('shelljs');
+
+sh.cd(__dirname + '/../');
+
+// fetch community repo
+sh.rm('-rf','scripts/community');
+sh.exec('npx degit sveltejs/community scripts/community');
+
+// copy over relevant files
+sh.cp('scripts/community/whos-using-svelte/WhosUsingSvelte.svelte', 'src/routes/_components/WhosUsingSvelte.svelte');
+sh.rm('-rf', 'static/organisations');
+sh.cp('-r', 'scripts/community/whos-using-svelte/organisations', 'static');
diff --git a/site/src/routes/_components/WhosUsingSvelte.svelte b/site/src/routes/_components/WhosUsingSvelte.svelte
deleted file mode 100644
index 5ae17ef7bc..0000000000
--- a/site/src/routes/_components/WhosUsingSvelte.svelte
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
-
diff --git a/site/static/organisations/absoluteweb.svg b/site/static/organisations/absoluteweb.svg
deleted file mode 100644
index e2aeb9421e..0000000000
--- a/site/static/organisations/absoluteweb.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/bekchy.png b/site/static/organisations/bekchy.png
deleted file mode 100644
index 011553cb42..0000000000
Binary files a/site/static/organisations/bekchy.png and /dev/null differ
diff --git a/site/static/organisations/beyonk.svg b/site/static/organisations/beyonk.svg
deleted file mode 100644
index 57d15142a8..0000000000
--- a/site/static/organisations/beyonk.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/buydotstar.svg b/site/static/organisations/buydotstar.svg
deleted file mode 100644
index da0e5c9211..0000000000
--- a/site/static/organisations/buydotstar.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
diff --git a/site/static/organisations/cashfree.svg b/site/static/organisations/cashfree.svg
deleted file mode 100644
index d0952dd71c..0000000000
--- a/site/static/organisations/cashfree.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/chess.svg b/site/static/organisations/chess.svg
deleted file mode 100644
index 752954f6e8..0000000000
--- a/site/static/organisations/chess.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/comigo.svg b/site/static/organisations/comigo.svg
deleted file mode 100644
index 44622a5195..0000000000
--- a/site/static/organisations/comigo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/datawrapper.svg b/site/static/organisations/datawrapper.svg
deleted file mode 100644
index f614df0eee..0000000000
--- a/site/static/organisations/datawrapper.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/dbnomics.jpg b/site/static/organisations/dbnomics.jpg
deleted file mode 100644
index 3d5991f869..0000000000
Binary files a/site/static/organisations/dbnomics.jpg and /dev/null differ
diff --git a/site/static/organisations/dbnomics.webp b/site/static/organisations/dbnomics.webp
deleted file mode 100644
index 14f3431bba..0000000000
Binary files a/site/static/organisations/dbnomics.webp and /dev/null differ
diff --git a/site/static/organisations/deck.svg b/site/static/organisations/deck.svg
deleted file mode 100644
index 21291ddfe9..0000000000
--- a/site/static/organisations/deck.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/dextra.png b/site/static/organisations/dextra.png
deleted file mode 100644
index 725f9bd511..0000000000
Binary files a/site/static/organisations/dextra.png and /dev/null differ
diff --git a/site/static/organisations/entriwise.png b/site/static/organisations/entriwise.png
deleted file mode 100644
index be305e1300..0000000000
Binary files a/site/static/organisations/entriwise.png and /dev/null differ
diff --git a/site/static/organisations/entur.svg b/site/static/organisations/entur.svg
deleted file mode 100644
index 98bb5cc937..0000000000
--- a/site/static/organisations/entur.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/from-now-on.png b/site/static/organisations/from-now-on.png
deleted file mode 100644
index 7da931dc34..0000000000
Binary files a/site/static/organisations/from-now-on.png and /dev/null differ
diff --git a/site/static/organisations/fusioncharts.svg b/site/static/organisations/fusioncharts.svg
deleted file mode 100644
index 6712115de8..0000000000
--- a/site/static/organisations/fusioncharts.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
\ No newline at end of file
diff --git a/site/static/organisations/godaddy.svg b/site/static/organisations/godaddy.svg
deleted file mode 100644
index e753ceed7b..0000000000
--- a/site/static/organisations/godaddy.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/grainger.svg b/site/static/organisations/grainger.svg
deleted file mode 100644
index af10fc52fe..0000000000
--- a/site/static/organisations/grainger.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/site/static/organisations/healthtree.png b/site/static/organisations/healthtree.png
deleted file mode 100644
index ec3f219d1c..0000000000
Binary files a/site/static/organisations/healthtree.png and /dev/null differ
diff --git a/site/static/organisations/iota.svg b/site/static/organisations/iota.svg
deleted file mode 100644
index 1ab864a958..0000000000
--- a/site/static/organisations/iota.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/itslearning.svg b/site/static/organisations/itslearning.svg
deleted file mode 100644
index 1d5fe6fcf4..0000000000
--- a/site/static/organisations/itslearning.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/jacoux.png b/site/static/organisations/jacoux.png
deleted file mode 100644
index 6d3f52017c..0000000000
Binary files a/site/static/organisations/jacoux.png and /dev/null differ
diff --git a/site/static/organisations/jingmnt.png b/site/static/organisations/jingmnt.png
deleted file mode 100644
index 326f5f0bbf..0000000000
Binary files a/site/static/organisations/jingmnt.png and /dev/null differ
diff --git a/site/static/organisations/mentorcv.png b/site/static/organisations/mentorcv.png
deleted file mode 100644
index 17cf95a9ac..0000000000
Binary files a/site/static/organisations/mentorcv.png and /dev/null differ
diff --git a/site/static/organisations/metrovias.svg b/site/static/organisations/metrovias.svg
deleted file mode 100644
index a81394de59..0000000000
--- a/site/static/organisations/metrovias.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/mustlab.png b/site/static/organisations/mustlab.png
deleted file mode 100644
index 4f3a29488b..0000000000
Binary files a/site/static/organisations/mustlab.png and /dev/null differ
diff --git a/site/static/organisations/nesta.svg b/site/static/organisations/nesta.svg
deleted file mode 100644
index 72f53e07b0..0000000000
--- a/site/static/organisations/nesta.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/nonkosi.svg b/site/static/organisations/nonkosi.svg
deleted file mode 100644
index 8639c0ce38..0000000000
--- a/site/static/organisations/nonkosi.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/nyt.svg b/site/static/organisations/nyt.svg
deleted file mode 100644
index 8735e53059..0000000000
--- a/site/static/organisations/nyt.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/nzz.svg b/site/static/organisations/nzz.svg
deleted file mode 100644
index 70f9486263..0000000000
--- a/site/static/organisations/nzz.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/oberonspace.svg b/site/static/organisations/oberonspace.svg
deleted file mode 100644
index 73fd68f8b5..0000000000
--- a/site/static/organisations/oberonspace.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/ofof.png b/site/static/organisations/ofof.png
deleted file mode 100644
index 5ecde9b0fd..0000000000
Binary files a/site/static/organisations/ofof.png and /dev/null differ
diff --git a/site/static/organisations/open-state-foundation.svg b/site/static/organisations/open-state-foundation.svg
deleted file mode 100644
index f8c010e7e2..0000000000
--- a/site/static/organisations/open-state-foundation.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/panascais.svg b/site/static/organisations/panascais.svg
deleted file mode 100644
index cb9e4f3afe..0000000000
--- a/site/static/organisations/panascais.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/site/static/organisations/pankod.svg b/site/static/organisations/pankod.svg
deleted file mode 100644
index 34578a7739..0000000000
--- a/site/static/organisations/pankod.svg
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
\ No newline at end of file
diff --git a/site/static/organisations/paperform.svg b/site/static/organisations/paperform.svg
deleted file mode 100644
index 3ee2540112..0000000000
--- a/site/static/organisations/paperform.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
\ No newline at end of file
diff --git a/site/static/organisations/razorpay.svg b/site/static/organisations/razorpay.svg
deleted file mode 100644
index 829adb319e..0000000000
--- a/site/static/organisations/razorpay.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/socialist-party.svg b/site/static/organisations/socialist-party.svg
deleted file mode 100644
index 9dde31a5c0..0000000000
--- a/site/static/organisations/socialist-party.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/softmus.png b/site/static/organisations/softmus.png
deleted file mode 100644
index 6d0c8af60a..0000000000
Binary files a/site/static/organisations/softmus.png and /dev/null differ
diff --git a/site/static/organisations/sqltribe.svg b/site/static/organisations/sqltribe.svg
deleted file mode 100644
index 2a51dfc0a7..0000000000
--- a/site/static/organisations/sqltribe.svg
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
\ No newline at end of file
diff --git a/site/static/organisations/stone.svg b/site/static/organisations/stone.svg
deleted file mode 100644
index 0401dbb292..0000000000
--- a/site/static/organisations/stone.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/strixcloud.svg b/site/static/organisations/strixcloud.svg
deleted file mode 100644
index 49fe96b061..0000000000
--- a/site/static/organisations/strixcloud.svg
+++ /dev/null
@@ -1,244 +0,0 @@
-
-
diff --git a/site/static/organisations/sucuri.png b/site/static/organisations/sucuri.png
deleted file mode 100644
index a30b161139..0000000000
Binary files a/site/static/organisations/sucuri.png and /dev/null differ
diff --git a/site/static/organisations/thunderdome.svg b/site/static/organisations/thunderdome.svg
deleted file mode 100644
index 0a5d8ee055..0000000000
--- a/site/static/organisations/thunderdome.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/tokopedia.svg b/site/static/organisations/tokopedia.svg
deleted file mode 100644
index d284f05d7b..0000000000
--- a/site/static/organisations/tokopedia.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/site/static/organisations/tsh.svg b/site/static/organisations/tsh.svg
deleted file mode 100644
index 0b0388b500..0000000000
--- a/site/static/organisations/tsh.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/site/static/organisations/webdesq.svg b/site/static/organisations/webdesq.svg
deleted file mode 100644
index c9f0012de0..0000000000
--- a/site/static/organisations/webdesq.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/site/static/organisations/zevvle.svg b/site/static/organisations/zevvle.svg
deleted file mode 100644
index 45a26c7a7c..0000000000
--- a/site/static/organisations/zevvle.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts
index 1a5d39ab28..9822529ece 100644
--- a/src/compiler/compile/Component.ts
+++ b/src/compiler/compile/Component.ts
@@ -472,7 +472,7 @@ export default class Component {
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(declarator, {
code: `unused-export-let`,
- message: `${this.name.name} has unused export property '${name}'. If it is for external reference only, please consider using \`export const '${name}'\``
+ message: `${this.name.name} has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\``
});
}
});
@@ -495,7 +495,7 @@ export default class Component {
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(specifier, {
code: `unused-export-let`,
- message: `${this.name.name} has unused export property '${specifier.exported.name}'. If it is for external reference only, please consider using \`export const '${specifier.exported.name}'\``
+ message: `${this.name.name} has unused export property '${specifier.exported.name}'. If it is for external reference only, please consider using \`export const ${specifier.exported.name}\``
});
}
}
@@ -603,6 +603,7 @@ export default class Component {
const { expression } = node.body;
if (expression.type !== 'AssignmentExpression') return;
+ if (expression.left.type === 'MemberExpression') return;
extract_names(expression.left).forEach(name => {
if (!this.var_lookup.has(name) && name[0] !== '$') {
diff --git a/src/compiler/compile/css/Stylesheet.ts b/src/compiler/compile/css/Stylesheet.ts
index 998a879687..246dab0f12 100644
--- a/src/compiler/compile/css/Stylesheet.ts
+++ b/src/compiler/compile/css/Stylesheet.ts
@@ -5,6 +5,7 @@ import Element from '../nodes/Element';
import { Ast, TemplateNode } from '../../interfaces';
import Component from '../Component';
import { CssNode } from './interfaces';
+import hash from "../utils/hash";
function remove_css_prefix(name: string): string {
return name.replace(/^-((webkit)|(moz)|(o)|(ms))-/, '');
@@ -37,15 +38,6 @@ function minify_declarations(
return c;
}
-// https://github.com/darkskyapp/string-hash/blob/master/index.js
-function hash(str: string): string {
- let hash = 5381;
- let i = str.length;
-
- while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
- return (hash >>> 0).toString(36);
-}
-
class Rule {
selectors: Selector[];
declarations: Declaration[];
diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts
index 28e6af5aa1..7d6fad0a81 100644
--- a/src/compiler/compile/nodes/Binding.ts
+++ b/src/compiler/compile/nodes/Binding.ts
@@ -50,6 +50,13 @@ export default class Binding extends Node {
message: 'Cannot bind to a variable declared with the let: directive'
});
} else if (this.is_contextual) {
+ if (scope.is_await(name)) {
+ component.error(this, {
+ code: 'invalid-binding',
+ message: 'Cannot bind to a variable declared with {#await ... then} or {:catch} blocks'
+ });
+ }
+
scope.dependencies_for_name.get(name).forEach(name => {
const variable = component.var_lookup.get(name);
if (variable) {
diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts
index a3b8dc7286..e8108858c5 100644
--- a/src/compiler/compile/nodes/Element.ts
+++ b/src/compiler/compile/nodes/Element.ts
@@ -151,6 +151,11 @@ export default class Element extends Node {
}
}
+ const has_let = info.attributes.some(node => node.type === 'Let');
+ if (has_let) {
+ scope = scope.child();
+ }
+
// Binding relies on Attribute, defer its evaluation
const order = ['Binding']; // everything else is -1
info.attributes.sort((a, b) => order.indexOf(a.type) - order.indexOf(b.type));
@@ -181,9 +186,16 @@ export default class Element extends Node {
this.handlers.push(new EventHandler(component, this, scope, node));
break;
- case 'Let':
- this.lets.push(new Let(component, this, scope, node));
+ case 'Let': {
+ const l = new Let(component, this, scope, node);
+ this.lets.push(l);
+ const dependencies = new Set([l.name.name]);
+
+ l.names.forEach(name => {
+ scope.add(name, dependencies, this);
+ });
break;
+ }
case 'Transition':
{
@@ -202,20 +214,7 @@ export default class Element extends Node {
}
});
- if (this.lets.length > 0) {
- this.scope = scope.child();
-
- this.lets.forEach(l => {
- const dependencies = new Set([l.name.name]);
-
- l.names.forEach(name => {
- this.scope.add(name, dependencies, this);
- });
- });
- } else {
- this.scope = scope;
- }
-
+ this.scope = scope;
this.children = map_children(component, this, this.scope, info.children);
this.validate();
diff --git a/src/compiler/compile/nodes/Head.ts b/src/compiler/compile/nodes/Head.ts
index 2c08dcd595..53e76d7a4d 100644
--- a/src/compiler/compile/nodes/Head.ts
+++ b/src/compiler/compile/nodes/Head.ts
@@ -1,9 +1,11 @@
import Node from './shared/Node';
import map_children from './shared/map_children';
+import hash from '../utils/hash';
export default class Head extends Node {
type: 'Head';
children: any[]; // TODO
+ id: string;
constructor(component, parent, scope, info) {
super(component, parent, scope, info);
@@ -18,5 +20,9 @@ export default class Head extends Node {
this.children = map_children(component, parent, scope, info.children.filter(child => {
return (child.type !== 'Text' || /\S/.test(child.data));
}));
+
+ if (this.children.length > 0) {
+ this.id = `svelte-${hash(this.component.source.slice(this.start, this.end))}`;
+ }
}
}
diff --git a/src/compiler/compile/nodes/shared/TemplateScope.ts b/src/compiler/compile/nodes/shared/TemplateScope.ts
index 5f30d0c883..4e087eedf5 100644
--- a/src/compiler/compile/nodes/shared/TemplateScope.ts
+++ b/src/compiler/compile/nodes/shared/TemplateScope.ts
@@ -42,4 +42,9 @@ export default class TemplateScope {
const owner = this.get_owner(name);
return owner && (owner.type === 'Element' || owner.type === 'InlineComponent');
}
+
+ is_await(name: string) {
+ const owner = this.get_owner(name);
+ return owner && (owner.type === 'ThenBlock' || owner.type === 'CatchBlock');
+ }
}
diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts
index c8fa884721..68d28024fe 100644
--- a/src/compiler/compile/render_dom/Block.ts
+++ b/src/compiler/compile/render_dom/Block.ts
@@ -450,7 +450,7 @@ export default class Block {
this.add_variable(dispose);
if (this.event_listeners.length === 1) {
- this.chunks.hydrate.push(
+ this.chunks.mount.push(
b`${dispose} = ${this.event_listeners[0]};`
);
@@ -458,7 +458,7 @@ export default class Block {
b`${dispose}();`
);
} else {
- this.chunks.hydrate.push(b`
+ this.chunks.mount.push(b`
${dispose} = [
${this.event_listeners}
];
diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts
index 5b13b486e6..4928b5a38c 100644
--- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts
+++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts
@@ -264,10 +264,23 @@ export default class EachBlockWrapper extends Wrapper {
block.chunks.init.push(b`
if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(#ctx);
+ }
+ `);
+
+ block.chunks.create.push(b`
+ if (${each_block_else}) {
${each_block_else}.c();
}
`);
+ if (this.renderer.options.hydratable) {
+ block.chunks.claim.push(b`
+ if (${each_block_else}) {
+ ${each_block_else}.l(${parent_nodes});
+ }
+ `);
+ }
+
block.chunks.mount.push(b`
if (${each_block_else}) {
${each_block_else}.m(${initial_mount_node}, ${initial_anchor_node});
diff --git a/src/compiler/compile/render_dom/wrappers/Head.ts b/src/compiler/compile/render_dom/wrappers/Head.ts
index 188c26931a..e0b723d6dd 100644
--- a/src/compiler/compile/render_dom/wrappers/Head.ts
+++ b/src/compiler/compile/render_dom/wrappers/Head.ts
@@ -3,11 +3,12 @@ import Renderer from '../Renderer';
import Block from '../Block';
import Head from '../../nodes/Head';
import FragmentWrapper from './Fragment';
-import { x } from 'code-red';
+import { x, b } from 'code-red';
import { Identifier } from 'estree';
export default class HeadWrapper extends Wrapper {
fragment: FragmentWrapper;
+ node: Head;
constructor(
renderer: Renderer,
@@ -32,6 +33,18 @@ export default class HeadWrapper extends Wrapper {
}
render(block: Block, _parent_node: Identifier, _parent_nodes: Identifier) {
- this.fragment.render(block, x`@_document.head` as unknown as Identifier, x`#nodes` as unknown as Identifier);
+ let nodes;
+ if (this.renderer.options.hydratable && this.fragment.nodes.length) {
+ nodes = block.get_unique_name('head_nodes');
+ block.chunks.claim.push(b`const ${nodes} = @query_selector_all('[data-svelte="${this.node.id}"]', @_document.head);`);
+ }
+
+ this.fragment.render(block, x`@_document.head` as unknown as Identifier, nodes);
+
+ if (nodes && this.renderer.options.hydratable) {
+ block.chunks.claim.push(
+ b`${nodes}.forEach(@detach);`
+ );
+ }
}
}
diff --git a/src/compiler/compile/render_ssr/Renderer.ts b/src/compiler/compile/render_ssr/Renderer.ts
index 00a7ee2fb5..fb9216327c 100644
--- a/src/compiler/compile/render_ssr/Renderer.ts
+++ b/src/compiler/compile/render_ssr/Renderer.ts
@@ -41,6 +41,7 @@ const handlers: Record = {
export interface RenderOptions extends CompileOptions{
locate: (c: number) => { line: number; column: number };
+ head_id?: string;
}
export default class Renderer {
diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts
index 81b8801686..e0982a0415 100644
--- a/src/compiler/compile/render_ssr/handlers/Element.ts
+++ b/src/compiler/compile/render_ssr/handlers/Element.ts
@@ -124,6 +124,10 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
}
});
+ if (options.hydratable && options.head_id) {
+ renderer.add_string(` data-svelte="${options.head_id}"`);
+ }
+
renderer.add_string('>');
if (node_contents !== undefined) {
diff --git a/src/compiler/compile/render_ssr/handlers/Head.ts b/src/compiler/compile/render_ssr/handlers/Head.ts
index d457942922..456e5c279b 100644
--- a/src/compiler/compile/render_ssr/handlers/Head.ts
+++ b/src/compiler/compile/render_ssr/handlers/Head.ts
@@ -3,8 +3,13 @@ import Head from '../../nodes/Head';
import { x } from 'code-red';
export default function(node: Head, renderer: Renderer, options: RenderOptions) {
+ const head_options = {
+ ...options,
+ head_id: node.id
+ };
+
renderer.push();
- renderer.render(node.children, options);
+ renderer.render(node.children, head_options);
const result = renderer.pop();
renderer.add_expression(x`($$result.head += ${result}, "")`);
diff --git a/src/compiler/compile/render_ssr/handlers/Title.ts b/src/compiler/compile/render_ssr/handlers/Title.ts
index 62d49d461a..a3f271ab1b 100644
--- a/src/compiler/compile/render_ssr/handlers/Title.ts
+++ b/src/compiler/compile/render_ssr/handlers/Title.ts
@@ -1,10 +1,20 @@
import Renderer, { RenderOptions } from '../Renderer';
import Title from '../../nodes/Title';
+import { x } from 'code-red';
export default function(node: Title, renderer: Renderer, options: RenderOptions) {
- renderer.add_string(``);
+ renderer.push();
+
+ renderer.add_string('');
renderer.render(node.children, options);
renderer.add_string(``);
+ const result = renderer.pop();
+
+ renderer.add_expression(x`($$result.title = ${result}, "")`);
}
diff --git a/src/compiler/compile/utils/hash.ts b/src/compiler/compile/utils/hash.ts
new file mode 100644
index 0000000000..7ac892611b
--- /dev/null
+++ b/src/compiler/compile/utils/hash.ts
@@ -0,0 +1,8 @@
+// https://github.com/darkskyapp/string-hash/blob/master/index.js
+export default function hash(str: string): string {
+ let hash = 5381;
+ let i = str.length;
+
+ while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
+ return (hash >>> 0).toString(36);
+}
\ No newline at end of file
diff --git a/src/compiler/utils/names.ts b/src/compiler/utils/names.ts
index 88d4d4a319..02cc12e087 100644
--- a/src/compiler/utils/names.ts
+++ b/src/compiler/utils/names.ts
@@ -5,6 +5,8 @@ export const globals = new Set([
'alert',
'Array',
'Boolean',
+ 'clearInterval',
+ 'clearTimeout',
'confirm',
'console',
'Date',
@@ -16,6 +18,9 @@ export const globals = new Set([
'Error',
'EvalError',
'Event',
+ 'fetch',
+ 'global',
+ 'globalThis',
'history',
'Infinity',
'InternalError',
@@ -41,11 +46,14 @@ export const globals = new Set([
'RegExp',
'sessionStorage',
'Set',
+ 'setInterval',
+ 'setTimeout',
'String',
'SyntaxError',
'TypeError',
'undefined',
'URIError',
+ 'URL',
'window'
]);
diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts
index c1d2f80101..10588a0804 100644
--- a/src/runtime/internal/Component.ts
+++ b/src/runtime/internal/Component.ts
@@ -127,7 +127,8 @@ export function init(component, options, instance, create_fragment, not_equal, p
let ready = false;
$$.ctx = instance
- ? instance(component, prop_values, (i, ret, value = ret) => {
+ ? instance(component, prop_values, (i, ret, ...rest) => {
+ const value = rest.length ? rest[0] : ret;
if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
if ($$.bound[i]) $$.bound[i](value);
if (ready) make_dirty(component, i);
diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts
index c641315bc3..f9e89f41b9 100644
--- a/src/runtime/internal/dom.ts
+++ b/src/runtime/internal/dom.ts
@@ -273,6 +273,10 @@ export function custom_event(type: string, detail?: T) {
return e;
}
+export function query_selector_all(selector: string, parent: HTMLElement = document.body) {
+ return Array.from(parent.querySelectorAll(selector));
+}
+
export class HtmlTag {
e: HTMLElement;
n: ChildNode[];
diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts
index 274006f243..646a81d817 100644
--- a/src/runtime/internal/ssr.ts
+++ b/src/runtime/internal/ssr.ts
@@ -25,9 +25,7 @@ export function spread(args, classes_to_add) {
else if (boolean_attributes.has(name.toLowerCase())) {
if (value) str += " " + name;
} else if (value != null) {
- str += " " + name + "=" + JSON.stringify(String(value)
- .replace(/"/g, '"')
- .replace(/'/g, '''));
+ str += ` ${name}="${String(value).replace(/"/g, '"').replace(/'/g, ''')}"`;
}
});
@@ -103,12 +101,13 @@ export function create_ssr_component(fn) {
on_destroy = [];
const result: {
+ title: string;
head: string;
css: Set<{
map: null;
code: string;
}>;
- } = { head: '', css: new Set() };
+ } = { title: '', head: '', css: new Set() };
const html = $$render(result, props, {}, options);
@@ -120,7 +119,7 @@ export function create_ssr_component(fn) {
code: Array.from(result.css).map(css => css.code).join('\n'),
map: null // TODO
},
- head: result.head
+ head: result.title + result.head
};
},
diff --git a/test/helpers.js b/test/helpers.js
index 2a03e0f436..a764d43f96 100644
--- a/test/helpers.js
+++ b/test/helpers.js
@@ -45,6 +45,12 @@ export function tryToReadFile(file) {
}
}
+export function cleanRequireCache() {
+ Object.keys(require.cache)
+ .filter(x => x.endsWith('.svelte'))
+ .forEach(file => delete require.cache[file]);
+}
+
const virtualConsole = new jsdom.VirtualConsole();
virtualConsole.sendTo(console);
@@ -68,6 +74,7 @@ window.scrollTo = function(pageXOffset, pageYOffset) {
export function env() {
window.document.title = '';
+ window.document.head.innerHTML = '';
window.document.body.innerHTML = '';
return window;
diff --git a/test/hydration/index.js b/test/hydration/index.js
index a0bfd6de4b..f57a0cdc1a 100644
--- a/test/hydration/index.js
+++ b/test/hydration/index.js
@@ -67,8 +67,16 @@ describe('hydration', () => {
}
const target = window.document.body;
+ const head = window.document.head;
+
target.innerHTML = fs.readFileSync(`${cwd}/_before.html`, 'utf-8');
+ let before_head;
+ try {
+ before_head = fs.readFileSync(`${cwd}/_before_head.html`, 'utf-8');
+ head.innerHTML = before_head;
+ } catch (err) {}
+
const snapshot = config.snapshot ? config.snapshot(target) : {};
const component = new SvelteComponent({
@@ -88,6 +96,19 @@ describe('hydration', () => {
}
}
+ if (before_head) {
+ try {
+ assert.htmlEqual(head.innerHTML, fs.readFileSync(`${cwd}/_after_head.html`, 'utf-8'));
+ } catch (error) {
+ if (shouldUpdateExpected()) {
+ fs.writeFileSync(`${cwd}/_after_head.html`, head.innerHTML);
+ console.log(`Updated ${cwd}/_after_head.html.`);
+ } else {
+ throw error;
+ }
+ }
+ }
+
if (config.test) {
config.test(assert, target, snapshot, component, window);
} else {
diff --git a/test/hydration/samples/each-else/_after.html b/test/hydration/samples/each-else/_after.html
new file mode 100644
index 0000000000..7920500ec3
--- /dev/null
+++ b/test/hydration/samples/each-else/_after.html
@@ -0,0 +1,4 @@
+
Hello, world
+
+ weird
+
\ No newline at end of file
diff --git a/test/hydration/samples/each-else/_before.html b/test/hydration/samples/each-else/_before.html
new file mode 100644
index 0000000000..7920500ec3
--- /dev/null
+++ b/test/hydration/samples/each-else/_before.html
@@ -0,0 +1,4 @@
+
Hello, world
+
+ weird
+
\ No newline at end of file
diff --git a/test/hydration/samples/each-else/main.svelte b/test/hydration/samples/each-else/main.svelte
new file mode 100644
index 0000000000..64d3a37c58
--- /dev/null
+++ b/test/hydration/samples/each-else/main.svelte
@@ -0,0 +1,15 @@
+
+
+
Hello, {name}
+{#each array as elem}
+
+ item
+
+{:else}
+
+ weird
+
+{/each}
diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_after.html b/test/hydration/samples/head-meta-hydrate-duplicate/_after.html
new file mode 100644
index 0000000000..3e5b375f0a
--- /dev/null
+++ b/test/hydration/samples/head-meta-hydrate-duplicate/_after.html
@@ -0,0 +1 @@
+
Just a dummy page.
\ No newline at end of file
diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_after_head.html b/test/hydration/samples/head-meta-hydrate-duplicate/_after_head.html
new file mode 100644
index 0000000000..10cf2c8b9a
--- /dev/null
+++ b/test/hydration/samples/head-meta-hydrate-duplicate/_after_head.html
@@ -0,0 +1,4 @@
+Some Title
+
+
+
\ No newline at end of file
diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_before.html b/test/hydration/samples/head-meta-hydrate-duplicate/_before.html
new file mode 100644
index 0000000000..3e5b375f0a
--- /dev/null
+++ b/test/hydration/samples/head-meta-hydrate-duplicate/_before.html
@@ -0,0 +1 @@
+
Just a dummy page.
\ No newline at end of file
diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_before_head.html b/test/hydration/samples/head-meta-hydrate-duplicate/_before_head.html
new file mode 100644
index 0000000000..d2f218fb8d
--- /dev/null
+++ b/test/hydration/samples/head-meta-hydrate-duplicate/_before_head.html
@@ -0,0 +1,4 @@
+Some Title
+
+
+
\ No newline at end of file
diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_config.js b/test/hydration/samples/head-meta-hydrate-duplicate/_config.js
new file mode 100644
index 0000000000..482efd564d
--- /dev/null
+++ b/test/hydration/samples/head-meta-hydrate-duplicate/_config.js
@@ -0,0 +1,5 @@
+export default {
+ test(assert, target, snapshot, component, window) {
+ assert.equal(window.document.querySelectorAll('meta').length, 2);
+ }
+};
diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/main.svelte b/test/hydration/samples/head-meta-hydrate-duplicate/main.svelte
new file mode 100644
index 0000000000..1a8b125dd2
--- /dev/null
+++ b/test/hydration/samples/head-meta-hydrate-duplicate/main.svelte
@@ -0,0 +1,8 @@
+
+ Some Title
+
+
+
+
+
+
diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js
index a56a4ddaed..ee1319845d 100644
--- a/test/server-side-rendering/index.js
+++ b/test/server-side-rendering/index.js
@@ -9,6 +9,7 @@ import {
loadSvelte,
setupHtmlEqual,
tryToLoadJson,
+ cleanRequireCache,
shouldUpdateExpected,
mkdirp
} from "../helpers.js";
@@ -27,11 +28,6 @@ let compile = null;
describe("ssr", () => {
before(() => {
- require("../../register")({
- extensions: ['.svelte', '.html'],
- sveltePath
- });
-
compile = loadSvelte(true).compile;
return setupHtmlEqual();
@@ -40,9 +36,11 @@ describe("ssr", () => {
fs.readdirSync(`${__dirname}/samples`).forEach(dir => {
if (dir[0] === ".") return;
+ const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`);
+
// add .solo to a sample directory name to only run that test, or
// .show to always show the output. or both
- const solo = /\.solo/.test(dir);
+ const solo = config.solo || /\.solo/.test(dir);
const show = /\.show/.test(dir);
if (solo && process.env.CI) {
@@ -51,6 +49,18 @@ describe("ssr", () => {
(solo ? it.only : it)(dir, () => {
dir = path.resolve(`${__dirname}/samples`, dir);
+
+ cleanRequireCache();
+
+ const compileOptions = {
+ sveltePath,
+ ...config.compileOptions,
+ generate: 'ssr',
+ format: 'cjs'
+ };
+
+ require("../../register")(compileOptions);
+
try {
const Component = require(`${dir}/main.svelte`).default;
@@ -133,18 +143,16 @@ describe("ssr", () => {
(config.skip ? it.skip : solo ? it.only : it)(dir, () => {
const cwd = path.resolve("test/runtime/samples", dir);
- Object.keys(require.cache)
- .filter(x => x.endsWith('.svelte'))
- .forEach(file => {
- delete require.cache[file];
- });
+ cleanRequireCache();
delete global.window;
- const compileOptions = Object.assign({ sveltePath }, config.compileOptions, {
+ const compileOptions = {
+ sveltePath,
+ ...config.compileOptions,
generate: 'ssr',
format: 'cjs'
- });
+ };
require("../../register")(compileOptions);
diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_config.js b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_config.js
new file mode 100644
index 0000000000..ae9b250f86
--- /dev/null
+++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_config.js
@@ -0,0 +1,5 @@
+export default {
+ compileOptions: {
+ hydratable: true
+ }
+};
diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html
new file mode 100644
index 0000000000..d2f218fb8d
--- /dev/null
+++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html
@@ -0,0 +1,4 @@
+Some Title
+
+
+
\ No newline at end of file
diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html
new file mode 100644
index 0000000000..a469e618fa
--- /dev/null
+++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html
@@ -0,0 +1,3 @@
+
+
+
Just a dummy page.
\ No newline at end of file
diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/main.svelte b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/main.svelte
new file mode 100644
index 0000000000..1a8b125dd2
--- /dev/null
+++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/main.svelte
@@ -0,0 +1,8 @@
+
+ Some Title
+
+
+
+
+
+
Just a dummy page.
\ No newline at end of file
diff --git a/test/server-side-rendering/samples/head-multiple-title/A.svelte b/test/server-side-rendering/samples/head-multiple-title/A.svelte
new file mode 100644
index 0000000000..b139b4ff77
--- /dev/null
+++ b/test/server-side-rendering/samples/head-multiple-title/A.svelte
@@ -0,0 +1,3 @@
+
+ A
+
diff --git a/test/server-side-rendering/samples/head-multiple-title/B.svelte b/test/server-side-rendering/samples/head-multiple-title/B.svelte
new file mode 100644
index 0000000000..4a29ecb04c
--- /dev/null
+++ b/test/server-side-rendering/samples/head-multiple-title/B.svelte
@@ -0,0 +1,3 @@
+
+ B
+
diff --git a/test/server-side-rendering/samples/head-multiple-title/_expected-head.html b/test/server-side-rendering/samples/head-multiple-title/_expected-head.html
new file mode 100644
index 0000000000..af5c5feba4
--- /dev/null
+++ b/test/server-side-rendering/samples/head-multiple-title/_expected-head.html
@@ -0,0 +1 @@
+B
\ No newline at end of file
diff --git a/test/server-side-rendering/samples/head-multiple-title/_expected.html b/test/server-side-rendering/samples/head-multiple-title/_expected.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/server-side-rendering/samples/head-multiple-title/data.json b/test/server-side-rendering/samples/head-multiple-title/data.json
new file mode 100644
index 0000000000..eab238e816
--- /dev/null
+++ b/test/server-side-rendering/samples/head-multiple-title/data.json
@@ -0,0 +1,3 @@
+{
+ "adjective": "custom"
+}
\ No newline at end of file
diff --git a/test/server-side-rendering/samples/head-multiple-title/main.svelte b/test/server-side-rendering/samples/head-multiple-title/main.svelte
new file mode 100644
index 0000000000..fb9a70b923
--- /dev/null
+++ b/test/server-side-rendering/samples/head-multiple-title/main.svelte
@@ -0,0 +1,10 @@
+
+
+
+ Main
+
+
+
diff --git a/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html
new file mode 100644
index 0000000000..a73bb17e8c
--- /dev/null
+++ b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte b/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte
new file mode 100644
index 0000000000..6919d9ea54
--- /dev/null
+++ b/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/test/validator/samples/binding-await-catch/errors.json b/test/validator/samples/binding-await-catch/errors.json
new file mode 100644
index 0000000000..00141686f3
--- /dev/null
+++ b/test/validator/samples/binding-await-catch/errors.json
@@ -0,0 +1,9 @@
+[
+ {
+ "code": "invalid-binding",
+ "message": "Cannot bind to a variable declared with {#await ... then} or {:catch} blocks",
+ "pos": 79,
+ "start": { "line": 6, "column": 9, "character": 79 },
+ "end": { "line": 6, "column": 27, "character": 97 }
+ }
+]
diff --git a/test/validator/samples/binding-await-catch/input.svelte b/test/validator/samples/binding-await-catch/input.svelte
new file mode 100644
index 0000000000..b640f6305b
--- /dev/null
+++ b/test/validator/samples/binding-await-catch/input.svelte
@@ -0,0 +1,7 @@
+
+{#await promise}
+{:catch error}
+
+{/await}
diff --git a/test/validator/samples/binding-await-then-2/errors.json b/test/validator/samples/binding-await-then-2/errors.json
new file mode 100644
index 0000000000..e734ed4717
--- /dev/null
+++ b/test/validator/samples/binding-await-then-2/errors.json
@@ -0,0 +1,9 @@
+[
+ {
+ "code": "invalid-binding",
+ "message": "Cannot bind to a variable declared with {#await ... then} or {:catch} blocks",
+ "pos": 78,
+ "start": { "line": 6, "column": 9, "character": 78 },
+ "end": { "line": 6, "column": 19, "character": 88 }
+ }
+]
diff --git a/test/validator/samples/binding-await-then-2/input.svelte b/test/validator/samples/binding-await-then-2/input.svelte
new file mode 100644
index 0000000000..e8c56c8e0b
--- /dev/null
+++ b/test/validator/samples/binding-await-then-2/input.svelte
@@ -0,0 +1,7 @@
+
+{#await promise}
+{:then value}
+
+{/await}
diff --git a/test/validator/samples/binding-await-then/errors.json b/test/validator/samples/binding-await-then/errors.json
new file mode 100644
index 0000000000..a611e7731f
--- /dev/null
+++ b/test/validator/samples/binding-await-then/errors.json
@@ -0,0 +1,9 @@
+[
+ {
+ "code": "invalid-binding",
+ "message": "Cannot bind to a variable declared with {#await ... then} or {:catch} blocks",
+ "pos": 75,
+ "start": { "line": 5, "column": 9, "character": 75 },
+ "end": { "line": 5, "column": 19, "character": 85 }
+ }
+]
diff --git a/test/validator/samples/binding-await-then/input.svelte b/test/validator/samples/binding-await-then/input.svelte
new file mode 100644
index 0000000000..bc55ef97e4
--- /dev/null
+++ b/test/validator/samples/binding-await-then/input.svelte
@@ -0,0 +1,6 @@
+
+{#await promise then value}
+
+{/await}
diff --git a/test/validator/samples/unreferenced-variables/warnings.json b/test/validator/samples/unreferenced-variables/warnings.json
index 7d9e0111bf..dfac58ebdb 100644
--- a/test/validator/samples/unreferenced-variables/warnings.json
+++ b/test/validator/samples/unreferenced-variables/warnings.json
@@ -6,7 +6,7 @@
"column": 12,
"line": 8
},
- "message": "Component has unused export property 'd'. If it is for external reference only, please consider using `export const 'd'`",
+ "message": "Component has unused export property 'd'. If it is for external reference only, please consider using `export const d`",
"pos": 102,
"start": {
"character": 102,
@@ -21,7 +21,7 @@
"column": 15,
"line": 8
},
- "message": "Component has unused export property 'e'. If it is for external reference only, please consider using `export const 'e'`",
+ "message": "Component has unused export property 'e'. If it is for external reference only, please consider using `export const e`",
"pos": 105,
"start": {
"character": 105,
@@ -36,7 +36,7 @@
"column": 18,
"line": 9
},
- "message": "Component has unused export property 'g'. If it is for external reference only, please consider using `export const 'g'`",
+ "message": "Component has unused export property 'g'. If it is for external reference only, please consider using `export const g`",
"pos": 125,
"start": {
"character": 125,
@@ -51,7 +51,7 @@
"column": 18,
"line": 10
},
- "message": "Component has unused export property 'h'. If it is for external reference only, please consider using `export const 'h'`",
+ "message": "Component has unused export property 'h'. If it is for external reference only, please consider using `export const h`",
"pos": 145,
"start": {
"character": 145,
@@ -66,7 +66,7 @@
"column": 25,
"line": 12
},
- "message": "Component has unused export property 'j'. If it is for external reference only, please consider using `export const 'j'`",
+ "message": "Component has unused export property 'j'. If it is for external reference only, please consider using `export const j`",
"pos": 187,
"start": {
"character": 187,