Merge branch 'master' into style-directives

pull/5923/head
tanhauhau 5 years ago
commit 56afb9c70a

@ -6,7 +6,7 @@ jobs:
timeout-minutes: 15 timeout-minutes: 15
strategy: strategy:
matrix: matrix:
node-version: [8, 10, 12, 14] node-version: [8, 10, 12, 14, 16]
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1

@ -0,0 +1,28 @@
name: Docs
on:
push:
branches:
- master
paths:
- site/content/**
jobs:
release:
name: Deploy docs
runs-on: ubuntu-latest
steps:
- name: my-app-install token
id: github-app
uses: getsentry/action-github-app-token@v1
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: run deploy docs workflow
uses: 'sveltejs/action-deploy-docs/dispatch@main'
with:
repo: 'svelte'
branch: 'master'
docs_path: 'site/content'
token: ${{ steps.github-app.outputs.token }}

12
.gitignore vendored

@ -24,13 +24,13 @@ _actual*.*
_output _output
/types /types
/site/cypress/screenshots/ /site/.svelte-kit/
/site/__sapper__/ /site/build/
/site/.env /site/.env
/site/.sessions
/site/static/svelte-app.json /site/static/svelte-app.json
/site/static/contributors.jpg /site/static/contributors.jpg
/site/static/workers /site/static/donors.jpg
/site/scripts/svelte-app /site/static/workers/
/site/scripts/community /site/scripts/svelte-app/
/site/src/routes/_contributors.js /site/src/routes/_contributors.js
/site/src/routes/_donors.js

@ -1,5 +1,75 @@
# Svelte changelog # Svelte changelog
## 3.44.2
* Fix overly restrictive preprocessor types ([#6904](https://github.com/sveltejs/svelte/pull/6904))
* More specific typing for crossfade function - returns a tuple, not an array ([#6926](https://github.com/sveltejs/svelte/issues/6926))
* Add `URLSearchParams` as a known global ([#6938](https://github.com/sveltejs/svelte/pull/6938))
* Add `types` field to `exports` map ([#6939](https://github.com/sveltejs/svelte/issues/6939))
## 3.44.1
* Fix code generation when a multi-line `return` statement contains comments ([code-red#36](https://github.com/Rich-Harris/code-red/issues/36))
* Fix code generation when `for`/`if`/`while` statements have empty bodies ([#6884](https://github.com/sveltejs/svelte/issues/6884))
## 3.44.0
* Add `enableSourcemap` compiler option ([#6835](https://github.com/sveltejs/svelte/pull/6835))
## 3.43.2
* Fix regression where user-specified `import`s were not rewritten according to the `sveltePath` option ([#6834](https://github.com/sveltejs/svelte/issues/6834))
## 3.43.1
* Prevent a rejecting promise used in `{#await}` during SSR from appearing as an unhandled rejection ([#6789](https://github.com/sveltejs/svelte/issues/6789))
## 3.43.0
* Use export map to expose no-op versions of lifecycle functions for SSR ([#6743](https://github.com/sveltejs/svelte/pull/6743))
* Prefer `context` passed to component constructor, even when running synchronously in another component ([#6753](https://github.com/sveltejs/svelte/issues/6753))
* Handle preprocessors that return empty sourcemaps ([#6757](https://github.com/sveltejs/svelte/pull/6757))
## 3.42.6
* Hide private preprocess typings ([#6622](https://github.com/sveltejs/svelte/issues/6622))
* Fix reactive function in `{:else if}` expression not being properly re-run ([#6727](https://github.com/sveltejs/svelte/pull/6727))
## 3.42.5
* In `draw` transition, account for `stroke-linecap` in determining length ([#4540](https://github.com/sveltejs/svelte/issues/4540))
* Fix regression with destructuring assignments with default values ([#6699](https://github.com/sveltejs/svelte/issues/6699))
## 3.42.4
* Only apply optimized `src` attribute handling when in an `html` namespace ([#6575](https://github.com/sveltejs/svelte/issues/6575))
* Fix styles for transitions and animations being attached to the wrong `document` in `<iframe>`s ([#6637](https://github.com/sveltejs/svelte/issues/6637))
* Fix `<select>` with a `{...spread}` attribute that didn't provide a `value` key getting its value improperly unset ([#6675](https://github.com/sveltejs/svelte/issues/6675))
## 3.42.3
* Add `BigInt` as a known global ([#6671](https://github.com/sveltejs/svelte/pull/6671))
* Fix regression where `onDestroy` in `svelte/ssr` was improperly a no-op ([#6676](https://github.com/sveltejs/svelte/issues/6676))
## 3.42.2
* Collapse whitespace in `class` and `style` attributes ([#6004](https://github.com/sveltejs/svelte/issues/6004))
* Deselect all `<option>`s in a `<select>` where the bound `value` doesn't match any of them ([#6126](https://github.com/sveltejs/svelte/issues/6126))
* In hydrated components, only rely on helpers for creating the types of elements present in the component ([#6555](https://github.com/sveltejs/svelte/issues/6555))
* Add `HTMLElement` and `SVGElement` as known globals ([#6643](https://github.com/sveltejs/svelte/issues/6643))
* Account for scaling in `flip` animations ([#6657](https://github.com/sveltejs/svelte/issues/6657))
## 3.42.1
* Fix regression with reordering keyed `{#each}` blocks when compiling with hydration enabled ([#6561](https://github.com/sveltejs/svelte/issues/6561))
## 3.42.0
* Allow `use:actions` to be used on `<svelte:body>` ([#3163](https://github.com/sveltejs/svelte/issues/3163))
* Improve parser errors for certain invalid components ([#6259](https://github.com/sveltejs/svelte/issues/6259), [#6288](https://github.com/sveltejs/svelte/issues/6288))
* Fix paths in generator JS sourcemaps to be relative ([#6598](https://github.com/sveltejs/svelte/pull/6598))
* Fix overzealous warnings about `context="module"` variables not being reactive ([#6606](https://github.com/sveltejs/svelte/issues/6606))
## 3.41.0 ## 3.41.0
* Support `export { ... } from` syntax in components ([#2214](https://github.com/sveltejs/svelte/issues/2214)) * Support `export { ... } from` syntax in components ([#2214](https://github.com/sveltejs/svelte/issues/2214))
@ -1995,7 +2065,7 @@ Also:
## 1.10.3 ## 1.10.3
* Prevent `'</script>'` string occurence breaking pages ([#349](https://github.com/sveltejs/svelte/pull/349)) * Prevent `'</script>'` string occurrence breaking pages ([#349](https://github.com/sveltejs/svelte/pull/349))
* Allow reference to whitelisted globals without properties ([#333](https://github.com/sveltejs/svelte/pull/333)) * Allow reference to whitelisted globals without properties ([#333](https://github.com/sveltejs/svelte/pull/333))
* Don't remove `&nbsp;` incorrectly ([#348](https://github.com/sveltejs/svelte/issues/348)) * Don't remove `&nbsp;` incorrectly ([#348](https://github.com/sveltejs/svelte/issues/348))
* `let` -> `var` in `addCss` block ([#351](https://github.com/sveltejs/svelte/pull/351)) * `let` -> `var` in `addCss` block ([#351](https://github.com/sveltejs/svelte/pull/351))

@ -64,7 +64,7 @@ npm run test -- -g transition
## svelte.dev ## svelte.dev
The source code for https://svelte.dev, including all the documentation, lives in the [site](site) directory. The site is built with [Sapper](https://sapper.svelte.dev). The source code for https://svelte.dev, including all the documentation, lives in the [site](site) directory. The site is built with [SvelteKit](https://kit.svelte.dev).
### Is svelte.dev down? ### Is svelte.dev down?

7379
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.41.0", "version": "3.44.2",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"module": "index.mjs", "module": "index.mjs",
"main": "index", "main": "index",
@ -22,26 +22,40 @@
"exports": { "exports": {
"./package.json": "./package.json", "./package.json": "./package.json",
".": { ".": {
"types": "./types/runtime/index.d.ts",
"browser": {
"import": "./index.mjs",
"require": "./index.js"
},
"node": {
"import": "./ssr.mjs",
"require": "./ssr.js"
},
"import": "./index.mjs", "import": "./index.mjs",
"require": "./index.js" "require": "./index.js"
}, },
"./compiler": { "./compiler": {
"types": "./types/compiler/index.d.ts",
"import": "./compiler.mjs", "import": "./compiler.mjs",
"require": "./compiler.js" "require": "./compiler.js"
}, },
"./animate": { "./animate": {
"types": "./types/runtime/animate/index.d.ts",
"import": "./animate/index.mjs", "import": "./animate/index.mjs",
"require": "./animate/index.js" "require": "./animate/index.js"
}, },
"./easing": { "./easing": {
"types": "./types/runtime/easing/index.d.ts",
"import": "./easing/index.mjs", "import": "./easing/index.mjs",
"require": "./easing/index.js" "require": "./easing/index.js"
}, },
"./internal": { "./internal": {
"types": "./types/runtime/internal/index.d.ts",
"import": "./internal/index.mjs", "import": "./internal/index.mjs",
"require": "./internal/index.js" "require": "./internal/index.js"
}, },
"./motion": { "./motion": {
"types": "./types/runtime/motion/index.d.ts",
"import": "./motion/index.mjs", "import": "./motion/index.mjs",
"require": "./motion/index.js" "require": "./motion/index.js"
}, },
@ -49,14 +63,17 @@
"require": "./register.js" "require": "./register.js"
}, },
"./store": { "./store": {
"types": "./types/runtime/store/index.d.ts",
"import": "./store/index.mjs", "import": "./store/index.mjs",
"require": "./store/index.js" "require": "./store/index.js"
}, },
"./transition": { "./transition": {
"types": "./types/runtime/transition/index.d.ts",
"import": "./transition/index.mjs", "import": "./transition/index.mjs",
"require": "./transition/index.js" "require": "./transition/index.js"
}, },
"./ssr": { "./ssr": {
"types": "./types/runtime/index.d.ts",
"import": "./ssr.mjs", "import": "./ssr.mjs",
"require": "./ssr.js" "require": "./ssr.js"
} }
@ -107,20 +124,20 @@
"@rollup/plugin-sucrase": "^3.1.0", "@rollup/plugin-sucrase": "^3.1.0",
"@rollup/plugin-typescript": "^2.0.1", "@rollup/plugin-typescript": "^2.0.1",
"@rollup/plugin-virtual": "^2.0.0", "@rollup/plugin-virtual": "^2.0.0",
"@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.7.0", "@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.8.0",
"@types/mocha": "^7.0.0", "@types/mocha": "^7.0.0",
"@types/node": "^8.10.53", "@types/node": "^8.10.53",
"@typescript-eslint/eslint-plugin": "^4.9.0", "@typescript-eslint/eslint-plugin": "^4.31.2",
"@typescript-eslint/parser": "^4.9.0", "@typescript-eslint/parser": "^4.31.2",
"acorn": "^8.4.1", "acorn": "^8.4.1",
"agadoo": "^1.1.0", "agadoo": "^1.1.0",
"c8": "^5.0.1", "c8": "^5.0.1",
"code-red": "^0.2.2", "code-red": "^0.2.3",
"codecov": "^3.5.0", "codecov": "^3.5.0",
"css-tree": "^1.1.2", "css-tree": "^1.1.2",
"eslint": "^7.15.0", "eslint": "^7.32.0",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.24.2",
"eslint-plugin-svelte3": "^2.7.3", "eslint-plugin-svelte3": "^3.2.1",
"estree-walker": "^3.0.0", "estree-walker": "^3.0.0",
"is-reference": "^3.0.0", "is-reference": "^3.0.0",
"jsdom": "^15.2.1", "jsdom": "^15.2.1",
@ -129,7 +146,7 @@
"magic-string": "^0.25.3", "magic-string": "^0.25.3",
"mocha": "^7.0.0", "mocha": "^7.0.0",
"periscopic": "^3.0.4", "periscopic": "^3.0.4",
"puppeteer": "^2.1.1", "puppeteer": "^2.0.0",
"rollup": "^1.27.14", "rollup": "^1.27.14",
"source-map": "^0.7.3", "source-map": "^0.7.3",
"source-map-support": "^0.5.13", "source-map-support": "^0.5.13",

@ -2,8 +2,6 @@
!/Dockerfile !/Dockerfile
!/package.json !/package.json
!/package-lock.json !/package-lock.json
!/__sapper__ !/build
/__sapper__/*
!/__sapper__/build
!/static !/static
!/content !/content

@ -1,13 +1,13 @@
NODE_ENV= NODE_ENV=
PORT= PORT=3000
BASEURL= BASEURL=http://localhost:3000
GITHUB_CLIENT_ID= GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET= GITHUB_CLIENT_SECRET=
MAPBOX_ACCESS_TOKEN= VITE_MAPBOX_ACCESS_TOKEN=
PGHOST=hostname PGHOST=localhost
PGPORT=port PGPORT=5432
PGUSER=username PGUSER=username
PGPASSWORD=password PGPASSWORD=password
PGDATABASE=database_name PGDATABASE=database_name

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

@ -1,7 +1,7 @@
# IMPORTANT: Don't use this Dockerfile in your own Sapper projects without also looking at the .dockerignore file. # IMPORTANT: Don't use this Dockerfile in your own projects without also looking at the .dockerignore file.
# Without an appropriate .dockerignore, this Dockerfile will copy a large number of unneeded files into your image. # Without an appropriate .dockerignore, this Dockerfile will copy a large number of unneeded files into your image.
FROM mhart/alpine-node:12 FROM mhart/alpine-node:14
# install dependencies # install dependencies
WORKDIR /app WORKDIR /app
@ -12,11 +12,11 @@ RUN npm ci --production
# Only copy over the Node pieces we need # Only copy over the Node pieces we need
# ~> Saves 35MB # ~> Saves 35MB
### ###
FROM mhart/alpine-node:slim-12 FROM mhart/alpine-node:slim-14
WORKDIR /app WORKDIR /app
COPY --from=0 /app . COPY --from=0 /app .
COPY . . COPY . .
EXPOSE 3000 EXPOSE 3000
CMD ["node", "__sapper__/build"] CMD ["node", "build"]

@ -5,10 +5,10 @@ PROJECT := svelte-dev
IMAGE := gcr.io/$(PROJECT)/$(SERVICE):$(HASH) IMAGE := gcr.io/$(PROJECT)/$(SERVICE):$(HASH)
sapper: sveltekit:
@echo "\n~> updating template & contributors list" @echo "\n~> updating template & contributors list"
@npm run update @npm run update
@echo "\n~> building Sapper app" @echo "\n~> building SvelteKit app"
@npm run build @npm run build
@ -17,6 +17,6 @@ docker:
@gcloud builds submit --project $(PROJECT) -t $(IMAGE) @gcloud builds submit --project $(PROJECT) -t $(IMAGE)
deploy: sapper docker deploy: sveltekit docker
@echo "\n~> deploying $(SERVICE) to Cloud Run servers" @echo "\n~> deploying $(SERVICE) to Cloud Run servers"
@gcloud run deploy $(SERVICE) --project $(PROJECT) --allow-unauthenticated --platform managed --region us-central1 --image $(IMAGE) --memory=512Mi @gcloud run deploy $(SERVICE) --project $(PROJECT) --allow-unauthenticated --platform managed --region us-central1 --image $(IMAGE) --memory=512Mi

@ -51,7 +51,7 @@ In order for the REPL's GitHub integration to work properly when running locally
## Building the site ## Building the site
To build the website, run `npm run build`. The output can be found in `__sapper__/build`. To build the website, run `npm run build`. The output can be found in `build`.
## Testing ## Testing

@ -1,17 +0,0 @@
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

@ -80,7 +80,7 @@ Again, you don't need to make this change manually — just run svelte-upgrade o
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. 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/). 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 ## New lifecycle hooks

@ -41,7 +41,7 @@ When we say that Svelte now supports TypeScript, we mean a few different things:
* You get autocompletion hints and type-checking as you're writing components, even in expressions inside markup * You get autocompletion hints and type-checking as you're writing components, even in expressions inside markup
* TypeScript files understand the Svelte component API — no more red squiggles when you import a `.svelte` file into a `.ts` module * TypeScript files understand the Svelte component API — no more red squiggles when you import a `.svelte` file into a `.ts` module
#### How does it work? ### How does it work?
To understand the two main parts of TypeScript support, we'll compare it to the technique TypeScript uses to provide dev tools. There is a compiler `tsc` which you run on the command-line to convert `*.ts` to `*.js`, then there is a `TSServer` which is a node API that responds to requests from text editors. The `TSServer` is what provides all the JavaScript and TypeScript realtime introspection for editors while coding, and it has most of the compiler's code inside it. To understand the two main parts of TypeScript support, we'll compare it to the technique TypeScript uses to provide dev tools. There is a compiler `tsc` which you run on the command-line to convert `*.ts` to `*.js`, then there is a `TSServer` which is a node API that responds to requests from text editors. The `TSServer` is what provides all the JavaScript and TypeScript realtime introspection for editors while coding, and it has most of the compiler's code inside it.
@ -52,7 +52,7 @@ The Svelte compiler support for TypeScript is handled by [Christian Kaisermann](
For the editor level, we took inspiration from [Pine's](https://github.com/octref) work in the [Vue](https://vuejs.org) ecosystem via [Vetur](https://github.com/vuejs/vetur). Vetur provides an [LSP](https://github.com/vuejs/vetur/blob/master/server), a VS Code extension and a [CLI](https://github.com/vuejs/vetur/blob/master/vti). Svelte now also has an [LSP](https://github.com/sveltejs/language-tools/blob/master/packages/language-server), a [VS Code extension](https://github.com/sveltejs/language-tools/blob/master/packages/svelte-vscode) and a [CLI](https://github.com/sveltejs/language-tools/blob/master/packages/svelte-check). For the editor level, we took inspiration from [Pine's](https://github.com/octref) work in the [Vue](https://vuejs.org) ecosystem via [Vetur](https://github.com/vuejs/vetur). Vetur provides an [LSP](https://github.com/vuejs/vetur/blob/master/server), a VS Code extension and a [CLI](https://github.com/vuejs/vetur/blob/master/vti). Svelte now also has an [LSP](https://github.com/sveltejs/language-tools/blob/master/packages/language-server), a [VS Code extension](https://github.com/sveltejs/language-tools/blob/master/packages/svelte-vscode) and a [CLI](https://github.com/sveltejs/language-tools/blob/master/packages/svelte-check).
#### `*.svelte` Introspection ### `*.svelte` Introspection
For the official Svelte VS Code extension, we built off the foundations which [James Birtles](https://github.com/UnwrittenFun) has created in [`UnwrittenFun/svelte-vscode`](https://github.com/UnwrittenFun/svelte-vscode) and [`UnwrittenFun/svelte-language-server`](https://github.com/UnwrittenFun/svelte-language-server/). For the official Svelte VS Code extension, we built off the foundations which [James Birtles](https://github.com/UnwrittenFun) has created in [`UnwrittenFun/svelte-vscode`](https://github.com/UnwrittenFun/svelte-vscode) and [`UnwrittenFun/svelte-language-server`](https://github.com/UnwrittenFun/svelte-language-server/).
@ -67,7 +67,7 @@ Before getting started, add the dependencies:
npm install --save-dev @tsconfig/svelte typescript svelte-preprocess svelte-check npm install --save-dev @tsconfig/svelte typescript svelte-preprocess svelte-check
``` ```
##### 1. Compiling TypeScript ### 1. Compiling TypeScript
You first need to set up [`svelte-preprocess`](https://github.com/sveltejs/svelte-preprocess#svelte-preprocess), which passes the contents of your `<script lang="ts">` blocks through the TypeScript compiler. You first need to set up [`svelte-preprocess`](https://github.com/sveltejs/svelte-preprocess#svelte-preprocess), which passes the contents of your `<script lang="ts">` blocks through the TypeScript compiler.
@ -103,7 +103,7 @@ To configure TypeScript, you will need to create a `tsconfig.json` in the root o
Your `include`/`exclude` may differ per project — these are defaults that should work across most Svelte projects. Your `include`/`exclude` may differ per project — these are defaults that should work across most Svelte projects.
##### 2. Editor Support ### 2. Editor Support
Any editor [using an LSP](https://langserver.org/#implementations-client) can be supported. The [VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) extension has been our primary focus, but there is work in progress [on Atom](https://github.com/sveltejs/language-tools/pull/160), and Vim via [coc-svelte](https://github.com/coc-extensions/coc-svelte) has been updated with the latest LSP. Any editor [using an LSP](https://langserver.org/#implementations-client) can be supported. The [VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) extension has been our primary focus, but there is work in progress [on Atom](https://github.com/sveltejs/language-tools/pull/160), and Vim via [coc-svelte](https://github.com/coc-extensions/coc-svelte) has been updated with the latest LSP.
@ -111,7 +111,7 @@ These editor extensions will improve your coding experience even if you only use
To switch a `<script>` to use TypeScript, use `<script lang="ts">` and that should be it. Hopefully you won't be seeing an ocean of red squiggles. To switch a `<script>` to use TypeScript, use `<script lang="ts">` and that should be it. Hopefully you won't be seeing an ocean of red squiggles.
##### 3. CI Checks ### 3. CI Checks
Having red squiggles is great, well, kinda. On the long run though, you want to be able to verify that there are no errors in your code. To verify your project is error free, you can use the CLI tool [`svelte-check`](https://www.npmjs.com/package/svelte-check). It acts like an editor asking for errors against all of your `.svelte` files. Having red squiggles is great, well, kinda. On the long run though, you want to be able to verify that there are no errors in your code. To verify your project is error free, you can use the CLI tool [`svelte-check`](https://www.npmjs.com/package/svelte-check). It acts like an editor asking for errors against all of your `.svelte` files.

@ -57,18 +57,18 @@ For all the features and bugfixes see the CHANGELOG for [Svelte](https://github.
- [Who are my representatives?](https://whoaremyrepresentatives.us/) is a website built with Svelte to help US residents get more info on their congressional representatives - [Who are my representatives?](https://whoaremyrepresentatives.us/) is a website built with Svelte to help US residents get more info on their congressional representatives
- [Pick Palette](https://github.com/bluwy/pick-palette) is a color palette manager made with Svelte! - [Pick Palette](https://github.com/bluwy/pick-palette) is a color palette manager made with Svelte!
#### In-depth learning: ### In-depth learning:
- [Svelte 3 Up and Running](https://www.amazon.com/dp/B08D6T6BKS/ref=cm_sw_r_tw_dp_x_OQMtFb3GPQCB2) is a new book about building production-ready static web apps with Svelte 3 - [Svelte 3 Up and Running](https://www.amazon.com/dp/B08D6T6BKS/ref=cm_sw_r_tw_dp_x_OQMtFb3GPQCB2) is a new book about building production-ready static web apps with Svelte 3
- [Sapper Tutorial (Crash Course)](https://www.youtube.com/playlist?list=PL4cUxeGkcC9gdr4Qhx83gBBcID-KMe-PQ) walks through the ins-and-outs of Sapper, the Svelte-powered application framework - [Sapper Tutorial (Crash Course)](https://www.youtube.com/playlist?list=PL4cUxeGkcC9gdr4Qhx83gBBcID-KMe-PQ) walks through the ins-and-outs of Sapper, the Svelte-powered application framework
- [Svelte Society Day France](https://france.sveltesociety.dev/) happened September 27th featuring a wide variety of topics all in French! You can find the full recording [here](https://www.youtube.com/watch?v=aS1TQ155JK4). - [Svelte Society Day France](https://france.sveltesociety.dev/) happened September 27th featuring a wide variety of topics all in French! You can find the full recording [here](https://www.youtube.com/watch?v=aS1TQ155JK4).
#### Plug-and-play components: ### Plug-and-play components:
- [svelte-zoom](https://github.com/vaheqelyan/svelte-zoom) brings "nearly native" pan-and-zoom to images on desktop and mobile - [svelte-zoom](https://github.com/vaheqelyan/svelte-zoom) brings "nearly native" pan-and-zoom to images on desktop and mobile
- [svelte-materialify](https://github.com/TheComputerM/svelte-materialify) is a Material component library for Svelte with over 50 components - [svelte-materialify](https://github.com/TheComputerM/svelte-materialify) is a Material component library for Svelte with over 50 components
- [svelte-undoable](https://github.com/macfja/svelte-undoable) makes it easy to introduce undo and redo functionality using `bind:` - [svelte-undoable](https://github.com/macfja/svelte-undoable) makes it easy to introduce undo and redo functionality using `bind:`
- [This Tilt component](https://svelte.dev/repl/7b23ad9d2693424482cd411b0378b55b?version=3.24.1) implements a common UX pattern where the hovered element tilts to follow the mouse - [This Tilt component](https://svelte.dev/repl/7b23ad9d2693424482cd411b0378b55b?version=3.24.1) implements a common UX pattern where the hovered element tilts to follow the mouse
#### Lots of examples of how use JS tech came out this month: ### Lots of examples of how use JS tech came out this month:
- [Sapper with PostCSS and Tailwind](https://codechips.me/sapper-with-postcss-and-tailwind/) - [Sapper with PostCSS and Tailwind](https://codechips.me/sapper-with-postcss-and-tailwind/)
- [PrismJS (Code block syntax highlighting)](https://github.com/phptuts/Svelte-PrismJS) - [PrismJS (Code block syntax highlighting)](https://github.com/phptuts/Svelte-PrismJS)
- [Filepond (Drag-and-drop file upload)](https://github.com/pqina/svelte-filepond) - [Filepond (Drag-and-drop file upload)](https://github.com/pqina/svelte-filepond)

@ -40,7 +40,7 @@ Aside from all that, we've been tempted by the thought of rewriting Sapper for a
## How is this new thing different? ## How is this new thing different?
The first of those foundational assumptions is that you need to use a module bundler like [webpack](https://webpack.js.org/) or [Rollup](http://rollupjs.org/) to build apps. These tools trace the dependency graph of your application, analysing and transforming code along the way (turning Svelte components to JS modules, for example), in order to create bundles of code that can run anywhere. As the original creator of Rollup, I can attest that it is a surprisingly complex problem with fiendish edge cases. The first of those foundational assumptions is that you need to use a module bundler like [webpack](https://webpack.js.org/) or [Rollup](https://rollupjs.org/) to build apps. These tools trace the dependency graph of your application, analysing and transforming code along the way (turning Svelte components to JS modules, for example), in order to create bundles of code that can run anywhere. As the original creator of Rollup, I can attest that it is a surprisingly complex problem with fiendish edge cases.
You certainly needed a bundler several years ago, because browsers didn't natively support the `import` keyword, but it's much less true today. Right now, we're seeing the rise of the *unbundled development* workflow, which is radically simpler: instead of eagerly bundling your app, a dev server can serve modules (converted to JavaScript, if necessary) *on-demand*, meaning startup is essentially instantaneous however large your app becomes. You certainly needed a bundler several years ago, because browsers didn't natively support the `import` keyword, but it's much less true today. Right now, we're seeing the rise of the *unbundled development* workflow, which is radically simpler: instead of eagerly bundling your app, a dev server can serve modules (converted to JavaScript, if necessary) *on-demand*, meaning startup is essentially instantaneous however large your app becomes.

@ -62,7 +62,7 @@ For all the features and bugfixes see the CHANGELOGs for [Svelte](https://github
- [svelte-store-router](https://github.com/zyxd/svelte-store-router) is a store-based router for Svelte that suggests that routing is just another global state and History API changes are just an optional side-effects of this state. - [svelte-store-router](https://github.com/zyxd/svelte-store-router) is a store-based router for Svelte that suggests that routing is just another global state and History API changes are just an optional side-effects of this state.
- [Routify](https://routify.dev/blog/routify-2-released) just released version 2 of its Svelte router. - [Routify](https://routify.dev/blog/routify-2-released) just released version 2 of its Svelte router.
- [svelte-error-boundary](https://www.npmjs.com/package/@crownframework/svelte-error-boundary) provides a simple error boundary component for Svelte that can be can be used with both DOM and SSR targets. - [svelte-error-boundary](https://www.npmjs.com/package/@crownframework/svelte-error-boundary) provides a simple error boundary component for Svelte that can be can be used with both DOM and SSR targets.
- [svelte2dts](https://www.npmjs.com/package/svelte2dts) generates d.ts files from svelte files, creating truly sharable and well typed components. - [svelte2dts](https://www.npmjs.com/package/svelte2dts) generates d.ts files from svelte files, creating truly shareable and well typed components.
## See you next month! ## See you next month!

@ -54,7 +54,7 @@ Want to learn more about how to get started, what's different compared to Sapper
- [Sapper Netlify](https://www.npmjs.com/package/sapper-netlify) is a Sapper project that can run on a Netlify function. - [Sapper Netlify](https://www.npmjs.com/package/sapper-netlify) is a Sapper project that can run on a Netlify function.
**Looking for a particular starter?** Check out [svelte-adders](https://github.com/svelte-add/svelte-adders) and a number of other integration examples at [sveltejs/integrations](https://github.com/sveltejs/integrations) **Looking for a particular starter?** Check out [svelte-adders](https://github.com/svelte-add/svelte-adders) and a number of other template examples at the community site [sveltesociety.dev](https://sveltesociety.dev/templates/)
**Learning Resources** **Learning Resources**
- [How to Build a Website with Svelte and SvelteKit](https://prismic.io/blog/svelte-sveltekit-tutorial) is a step-by-step tutorial walking through the new SvelteKit setup. - [How to Build a Website with Svelte and SvelteKit](https://prismic.io/blog/svelte-sveltekit-tutorial) is a step-by-step tutorial walking through the new SvelteKit setup.

@ -57,7 +57,7 @@ Last week, Svelte Summit blew us away with a mountain of content! [Check out the
- [Adds Supabase to Svelte](https://github.com/joshnuss/svelte-supabase) is an experimental command to run to add Supabase to your SvelteKit project - [Adds Supabase to Svelte](https://github.com/joshnuss/svelte-supabase) is an experimental command to run to add Supabase to your SvelteKit project
- [svelte-babylon](https://github.com/SectorXUSA/svelte-babylon) lets you use BabylonJS like A-Frame through reactive Svelte Components - [svelte-babylon](https://github.com/SectorXUSA/svelte-babylon) lets you use BabylonJS like A-Frame through reactive Svelte Components
**Looking for a starter or integration?** Check out [svelte-adders](https://github.com/svelte-add/svelte-adders) and a number of other integration examples at [sveltejs/integrations](https://github.com/sveltejs/integrations) **Looking for a starter or integration?** Check out [svelte-adders](https://github.com/svelte-add/svelte-adders) and a number of other template examples at the community site [sveltesociety.dev](https://sveltesociety.dev/templates)
**Learning Resources** **Learning Resources**

@ -0,0 +1,71 @@
---
title: What's new in Svelte: August 2021
description: Shadow DOM, export and await - oh my!
author: Daniel Sandoval
authorURL: https://desandoval.net
---
From The Changelog ([JS Party Ep. 182](https://changelog.com/jsparty/182)) to Svelte Radio (Episodes [29](https://share.transistor.fm/s/adc23e84) and [30](https://share.transistor.fm/s/6316622d)), it seems that folks couldn't help but talk about Svelte, this month! Also, shadow DOM support and new export and await functionality are new in Svelte.
## New in Svelte
July was the most active month for the Svelte core repo since late 2019 as we really worked to reduce the number of outstanding PRs and saw the release of Svelte 3.39.0, 3.40.0, and 3.41.0. Tons of bug fixes were added as well as the following new features:
- The `|trusted` event modifier allows you to check if an event is trusted before it's called ([#6137](https://github.com/sveltejs/svelte/issues/6137))
- The new `svelte/ssr` package to support work on improving SvelteKit SSR ([#6416](https://github.com/sveltejs/svelte/pull/6416))
- A new `errorMode` compiler option to support improved preprocessing of TypeScript files ([#6194](https://github.com/sveltejs/svelte/pull/6194))
- You can now specify a `ShadowRoot` as the `target` when creating a component - making it possible to render Svelte components inside the shadow DOM ([#5869](https://github.com/sveltejs/svelte/issues/5869))
- The `export { ... } from` ([#2214](https://github.com/sveltejs/svelte/issues/2214)), `export let { ... } =` ([#5612](https://github.com/sveltejs/svelte/issues/5612)) and `{#await ... then/catch}` ([#6270](https://github.com/sveltejs/svelte/issues/6270)) syntaxes are all now supported in Svelte components
For a full list of features and bug fixes, check out the [Svelte changelog](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md).
## SvelteKit Updates
- `prerender.force` is now `prerender.onError` which lets you fine-tune which errors fail the build and which do not ([#2007](https://github.com/sveltejs/kit/pull/2007))
- esbuild's configuration is now exposed for use with SvelteKit adapters ([#1914](https://github.com/sveltejs/kit/pull/1914))
- Error messages are friendlier now for common config errors ([#1910](https://github.com/sveltejs/kit/pull/1910)) and compiler errors ([#1827](https://github.com/sveltejs/kit/pull/1827))
- Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it ([#1847](https://github.com/sveltejs/kit/pull/1847))
- index.js exports will now be changed to directory exports when packaging - making for nicer imports ([#1905](https://github.com/sveltejs/kit/pull/1905))
- Vite.js's `mode` is now exposed from `$app/env` ([#1789](https://github.com/sveltejs/kit/pull/1789))
- Better types across the board ([#1778](https://github.com/sveltejs/kit/pull/1778), [#1791](https://github.com/sveltejs/kit/pull/1791), [#1646](https://github.com/sveltejs/kit/pull/1646))
To see all updates to SvelteKit, check out the [SvelteKit changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md).
## Features & bug fixes from around svelte/*
- Language Tools now better support the "Workplace Trust" functionality (used in VS Code)
- In svelte2tsx, ambient type declarations are now renamed to avoid conflicting declarations in the future. Users are now expected to provide the ambient type definitions themselves - fixing JS output
- Sapper released v0.29.2 which fixes regex routes, status codes when requesting a directory, and exports when a user has not provided a `base` tag ([changelog](https://github.com/sveltejs/sapper/blob/master/CHANGELOG.md))
---
## Community Showcase
**Apps & Sites**
- [Parsnip](https://www.parsnip.ai/) is a mobile-first, progressive-web-app that helps you to learn to cook at home. Check out the [conversation on Reddit](https://www.reddit.com/r/sveltejs/comments/oearb9/learning_to_cook_at_home_with_parsnip_built/) for all the geeky details.
- [Central Bank Digital Currency (CBDC) tracker](https://www.atlanticcouncil.org/cbdctracker/) is a site that keeps track of how countries around the world are adopting digital currencies.
- [Svelte Commerce](https://github.com/itswadesh/svelte-commerce) is an advanced frontend platform for eCommerce based on Sveltekit.
- [neovimcraft](https://neovimcraft.com/) is a SvelteKit site dedicated to neovim plugins
**Looking for a Svelte project to work on? Interested in helping make Svelte's presence on the web better?** Check out [the list of open issues](https://github.com/svelte-society/sveltesociety-2021/issues) if you'd like to contribute to the Svelte Society rewrite in SvelteKit.
**Educational Content**
- [How I Built a Cross-Platform Desktop Application with Svelte, Redis, and Rust](https://css-tricks.com/how-i-built-a-cross-platform-desktop-application-with-svelte-redis-and-rust/) is a blog post by Luke Edwards, Svelte maintainer and Developer Advocate from Cloudflare.
- [How to Create a Blog with SvelteKit and Strapi](https://strapi.io/blog/how-to-create-a-blog-with-svelte-kit-strapi) is a step-by-step tutorial by Aarnav Pai from Strapi
- [Sveltekit Markdown Blog](https://www.youtube.com/watch?v=sKKgT0SEioI&list=PLm_Qt4aKpfKgonq1zwaCS6kOD-nbOKx7V) is a YouTube tutorial series by WebJeda.
- [Using Custom Elements in Svelte](https://css-tricks.com/using-custom-elements-in-svelte/) is a deep dive into custom elements by Geoff Rich.
- [learn / graphql / svelte](https://hasura.io/learn/graphql/svelte-apollo/introduction/) is a free 2-hour GraphQL course course from Hasura.
- [How to add Magic Link to a SvelteKit application](https://magic.link/posts/magic-svelte) is a guide to the popular password-less login pattern.
**Libraries, Tools & Components**
- [Svelte-Capacitor](https://github.com/drannex42/svelte-capacitor/) just released v2.0.0 - making it even easier to build hybrid mobile apps for iOS and Android using Svelte and Capacitor with near native performance.
- [svelte-remixicon](https://github.com/ABarnob/svelte-remixicon) is an icon library for Svelte based on Remix Icon, consisting of more than 2000 icons.
- [SveltePress](https://github.com/GeopJr/SveltePress) is a documentation tool built on top of SvelteKit.
- [Svelte Starter Kit](https://github.com/one-aalam/svelte-starter-kit/tree/auth-supabase) is a boilerplate to quckly get up and running with Svelte, with Auth and User Profiles powered by Supabase.
- [Kahi UI](https://github.com/novacbn/kahi-ui) is a Svelte-first UI kit with Dark Mode built-in.
- [typesafe-i18n](https://github.com/ivanhofer/typesafe-i18n) is an opinionated, fully type-safe, lightweight localization library for TypeScript and JavaScript projects with no external dependencies.
Check out the community site [sveltesociety.dev](https://sveltesociety.dev/templates/) for more templates, adders and adapters from across the Svelte ecosystem.
## See you next month!
Want more updates? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs)!

@ -0,0 +1,83 @@
---
title: What's new in Svelte: September 2021
description: StackOverflow's most loved web framework
author: Daniel Sandoval
authorURL: https://desandoval.net
---
This month, Svelte was [voted StackOverflow's most loved web framework](https://insights.stackoverflow.com/survey/2021#section-most-loved-dreaded-and-wanted-web-frameworks), Tan Li Hau [talked to Svelte Radio](https://share.transistor.fm/s/84c7521b) about his [Svelte-filled YouTube channel](https://www.youtube.com/channel/UCbmC3HP3FaAFdcZkui8YoMQ), and SvelteKit made even more progress towards its 1.0 release!
## New in Svelte
- `use:actions` can now be used on `<svelte:body>` (**3.42.0**)
- `HTMLElement`, `SVGElement` (**3.42.2**) and `BigInt` (**3.42.3**) are now known globals
- There is less code in Svelte's output thanks to the following improvements in **3.42.2**:
- Whitespace is now collapsed in class and style attributes
- Hydrated components have been updated to only rely upon helpers for creating the types of elements present in the component
- Scaling is now accounted for in `flip` animations (**3.42.2**)
- All `<option>`s in a `<select>` are now deselected when the bound value doesn't match any of them (**3.42.2**)
For a full list of features and bug fixes, check out the [Svelte changelog](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md).
## SvelteKit Updates
Svelte maintainers are [looking for help getting SvelteKit to 1.0](https://github.com/sveltejs/kit/issues/2100). We've knocked out over 100 issues that were on the 1.0 milestone. There's only a couple dozen left and we'd love a hand making that list a bit shorter!
If you'd like to help, please consider working on any of the [1.0 milestone issues](https://github.com/sveltejs/kit/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.0).
The focus this past month was on continuing to iron out any kinks, with well over 100 PRs merged. A few new features went in as well...
- SvelteKit will now detect if a prerendered app is trying to access a query parameter and return an error instead of failing silently ([#2104](https://github.com/sveltejs/kit/pull/2104))
- `adapter-node` now lets you [add the Kit middleware to your own server](https://kit.svelte.dev/faq#integrations) for use with other middleware. You can also [add middleware in dev mode](https://kit.svelte.dev/faq#how-do-i-use-x-with-sveltekit-how-do-i-use-middleware) with more improvements to come in this area
- The new [`sequence` helper lets you chain together multiple `handle` calls](https://kit.svelte.dev/docs#modules-sveltejs-kit-hooks)
- A new [`handleError` hook](https://kit.svelte.dev/docs#hooks-handleerror) gives you the option to send data to an error tracking service, or to customise the formatting before printing the error to the console.
- `adapter-node` can now listen on socket path ([#2048](https://github.com/sveltejs/kit/pull/2048))
To see all updates to SvelteKit, check out the [SvelteKit changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md).
---
## Community Showcase
**Apps & Sites**
- [macos-web](https://github.com/PuruVJ/macos-web) by @puruvjdev has been rebuilt with Svelte from the ground up. Check out all the details in this [Twitter thread](https://twitter.com/puruvjdev/status/1426267327687847939)
- [Brave Search](https://search.brave.com/) is using Svelte
- [exatorrent](https://github.com/varbhat/exatorrent) is a self-hostable, easy-to-use, lightweight and feature-rich torrent client written in Go and Svelte
- [json2TsTypes](https://github.com/jatinhemnani01/json2TsTypes) is a simple tool which will convert your JSON to Typescript Types/Interfaces
- [Histogram.dev](https://histogram.dev/) generates histograms for each feature in a CSV
- [cybernetic.dev](https://cybernetic.dev/) is a collection of data-centric UI experiments made while learning Svelte
- [LunaNotes](https://chrome.google.com/webstore/detail/lunanotes-youtube-video-n/oehoffnnkgcdacmbkhmlbjedinpampak?hl=en) is a Chrome extension to help with taking YouTube video notes
- [theia.games](https://theia.games/#dev)'s built-in 3D environment editor lets you create a VR world with a menu built in Svelte
- [Ferrum](https://github.com/probablykasper/ferrum) is a music library and player available for Mac, Windows or Linux
- [Fluid Earth](https://github.com/byrd-polar/fluid-earth) is an interactive WebGL application for visualizing Earth's atmosphere and oceans
**Looking for a Svelte project to work on? Interested in helping make Svelte's presence on the web better?** Check out [the list of open issues](https://github.com/svelte-society/sveltesociety-2021/issues) if you'd like to contribute to the Svelte Society rewrite in SvelteKit.
**Educational Content**
- [Tauri with Standard Svelte or SvelteKit](https://medium.com/@cazanator/tauri-with-standard-svelte-or-sveltekit-ad7f103c37e7) walks through how to setup Svelte with Tauri, a new light-weight framework for developing cross-platform hybrid desktop applications
- [Svelte - Web App Development Reimagined [An Intro to Svelte]](https://www.youtube.com/watch?v=4CGzFwHoD0A&list=PLEx5khR4g7PKSASVAXXiAhkyx02_OeruP) is a great intro talk from the goto; conference
- [LevelUpTuts - Even More 5 Things I Like More In Svelte Than React](https://www.youtube.com/watch?v=ISmnG2sIOeM) highlights Svelte's approach to refs (don't need them), meta tags and more
- [State Management in Svelte Applications](https://auth0.com/blog/state-management-in-svelte-applications/) is a tutorial on how to use the Svelte state management store to manage state in Svelte applications
- [Migrating from Sapper to SvelteKit](https://shipbit.de/blog/migrating-from-sapper-to-svelte-kit/) is a review and retrospective of ShipBit's migration from Sapper
**Libraries, Tools & Components**
- [svelte-stripe-js](https://github.com/joshnuss/svelte-stripe-js) is everything you need to add Stripe to your Svelte project. 100% SvelteKit compatible
- [svelte-steps](https://github.com/shaozi/svelte-steps) is a customizable step component written in Svelte
- [simple-optics-module](https://gitlab.com/Samzelot/simple-optics-module) is an online open source optics tool for experimenting and teaching geometrical optics
- [inlang](https://github.com/samuelstroschein/inlang) is an internationalization (i18n) tool for SvelteKit apps
- [Sveno](https://github.com/pocinnovation/sveno) is a component transpiler that transforms React components to Svelte components
- [svelte-useactions](https://github.com/paolotiu/svelte-useactions) is a fully typed library for passing actions to components
- [Svelte-Element-Query](https://github.com/leveluptuts/Svelte-Element-Query) is a 322b library/action for element queries
- [svelte-meta-tags](https://github.com/oekazuma/svelte-meta-tags) is a plug-in that makes managing SEO easier in Svelte projects
- [svelte-domtree](https://github.com/alex-knyaz/svelte-domtree) lets you visualize the DOM - similar to DOM tree in Chrome DevTools
- [Diffx](https://github.com/jbjorge/diffx/tree/master/svelte), a cross-framework state management library, just added Svelte support
- [svelte-ionic-starter](https://github.com/Zettexe/svelte-ionic-starter) a project template for Svelte + Ionic + CapacitorJS apps with live reload and iOS/Android build targets
- [demo-sveltekit-sanity](https://github.com/stephane-vanraes/demo-sveltekit-sanity/) is a starter kit for SvelteKit and Sanity, an open source React CMS
Check out the community site [sveltesociety.dev](https://sveltesociety.dev/templates/) for more templates, adders and adapters from across the Svelte ecosystem.
## See you next month!
Want more updates? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs)!

@ -0,0 +1,99 @@
---
title: What's new in Svelte: October 2021
description: A whole year of "What's new in Svelte"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
Hey y'all 👋 It's been 1 year since "What's new in Svelte" started being cross-posted to the Svelte blog. I wanted to take this moment at the top to thank all of you for reading and for all the contributors every month. From the maintainers to everyone who posts their work in the Discord and Reddit, it's amazing to witness all the effort that goes into making the Svelte community great.
Keep up the good work, everyone! Now, let's dive into this month's news...
## New around Svelte
- New additions to Svelte's export map now expose no-op versions of lifecycle functions for SSR (Svelte **3.43.0**)
- Custom components with a `src` attribute no longer break `svelte-native` builds (Svelte **3.42.4**)
- Svelte plugin users without [the TypeScript plugin](https://www.npmjs.com/package/typescript-svelte-plugin) enabled will now be prompted to enable it. It enhances TypeScript and JavaScript files with additional intellisense to interact with Svelte files. [Please leave feedback](https://github.com/sveltejs/language-tools/issues/580) if you are using it (Svelte extensions **105.4.0**)
- Event modifiers have been added to intellisense as autocomplete and hover info (Svelte extensions **105.4.0**)
- TypeScript users no longer have to strictly separate type imports and value imports when using Svelte version 3.39 or higher and `svelte-preprocess` version 4.9.5 or higher. This means you can now write `import { MyInterface, myValue } from './somewhere'` instead of `import type { MyInterface } from './somewhere'; import { myValue } from './somewhere'`. Huge thanks to community member [@SomaticIT](https://github.com/SomaticIT) who mainly implemented this!
For a full list of features and bug fixes, check out the [Svelte changelog](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md).
## SvelteKit Updates
Nearly 100 PRs committed again this past month, but there's still lots to do and Svelte maintainers are [looking for help getting SvelteKit to 1.0](https://github.com/sveltejs/kit/issues/2100). Antony said it well in a [recent comment](https://github.com/sveltejs/kit/issues/2100#issuecomment-895446285) on the issue:
> If you think you are too n00b to contribute (you're not), then add tests, or write tests for the feature you want to add, before you add it! Start small, and learn the codebase that way.
If you'd like to help, please consider working on any of the [1.0 milestone issues labeled with "help wanted"](https://github.com/sveltejs/kit/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.0+label%3A%22help+wanted%22).
Notable SvelteKit improvements this month include...
- Service workers are now allowed to access files using the `$lib` alias ([#2326](https://github.com/sveltejs/kit/pull/2326))
- Svelte libraries should now work out-of-the-box without any Vite configuration ([#2343](https://github.com/sveltejs/kit/pull/2343))
- Improvements to package exports field ([#2345](https://github.com/sveltejs/kit/pull/2345) and [#2327](https://github.com/sveltejs/kit/pull/2327))
- [breaking] The `prerender.pages` config option has been renamed to `prerender.entries` ([#2380](https://github.com/sveltejs/kit/pull/2380))
- A new generic argument has beend added to allow typing Body from hooks ([#2413](https://github.com/sveltejs/kit/pull/2413))
- The `svelte` field will be added to package.json when running the package command ([#2431](https://github.com/sveltejs/kit/pull/2431))
- [breaking] The `context` parameter of the load function was renamed to `stuff` ([#2439](https://github.com/sveltejs/kit/pull/2439))
- Added an `entryPoint` option for building a custom server with `adapter-node` ([#2414](https://github.com/sveltejs/kit/pull/2414))
- `vite-plugin-svelte` improved support for [useVitePreprocess](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md#usevitepreprocess), which uses Vite to automatically preprocess TypeScript, PostCSS, Scss, etc in Svelte components ([#173](https://github.com/sveltejs/vite-plugin-svelte/pull/173))
To see all updates to SvelteKit, check out the [SvelteKit changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md).
---
## Community Showcase
**Apps & Sites**
- [radiofrance](https://www.radiofrance.fr/) just migrated their website to SvelteKit
- [FLAYKS](https://flayks.com/) is the portfolio site for Félix Péault made with SvelteKit, Sanity, and Anime.js
- [hirehive](https://www.hirehive.com/) is a candidate and job tracking site
- [Microsocial](https://microsocial.xyz/) is an experimental Peer-to-Peer Social Platform
- [Dylan Ipsum](https://www.dylanlyrics.app/) is a random text generator to replace lorem ipsum with Bob Dylan lyrics
- [Chip8 Svelte](https://github.com/mikeyhogarth/chip8-svelte) is a CHIP-8 emulator frontend, built on top of CHIP8 Typescript
**Looking for a Svelte project to work on? Interested in helping make Svelte's presence on the web better?** Check out [the list of open issues](https://github.com/svelte-society/sveltesociety-2021/issues) if you'd like to contribute to the Svelte Society rewrite in SvelteKit.
**Podcasts Featuring Svelte**
- [Syntax Podast: From React to SvelteKit](https://podcasts.apple.com/us/podcast/from-react-to-sveltekit/id1253186678?i=1000536276106) Scott talks with Wes about moving Level Up Tutorials from React to SvelteKit — why he did it, how, benefits, things to watch out for, and more!
- [Web Rush Podcast: Svelte Tools and Svelte Society](https://www.webrush.io/episodes/episode-150-svelte-tools-and-svelte-society) Kevin Åberg Kultalahti talks about what Svelte Society is, what he's excited about with Svelte, how important documentation is to any product, and much _much_ more
- [Svelte: The Compiled Future of Front End](https://www.arahansen.com/the-compiled-future-of-front-end/) details the history of component-based frontends and how a compiler changes everything
- [Svelte Radio: Contributing to Svelte with Martin 'Grygrflzr' Krisnanto Putra](https://share.transistor.fm/s/10aa305c) Grygrflzr shares his journey to becoming a maintainer and his views on React, Vite and a host of other things
- [Svelte Radio: Routify 3 with Jake and Willow](https://share.transistor.fm/s/10aa305c) the Svelte Radio crew sits down with the maintainers of Routify and discusses the just-released Routify 3
- [JS Party: 1Password](https://twitter.com/geoffrich_/status/1441816829853253640?s=20) mentioned on the latest episode of The Changelog's JS Party that they use Svelte to power their in-page suggestions
**Educational Content**
- [How I built a blog with Svelte and SvelteKit](https://fantinel.dev/blog-development-sveltekit/) is an introduction to Svelte, SvelteKit and Progressive Enhancement with code examples
- [I built a decentralized chat dapp](https://www.youtube.com/watch?v=J5x3OMXjgMc) is a tutorial on how to use popular web3 technologies like GUN to build a decentralized web app (dapp)
- [Writing a Svelte Store with TypeScript](https://javascript.plainenglish.io/writing-a-svelte-store-with-typescript-22fa1c901a4) is a deep dive into writing Svelte stores with TypeScript
- [How Svelte scopes component styles](https://geoffrich.net/posts/svelte-scoped-styles/) explains scoping using classes and more complex CSS specifiers
- [SvelteKit Hooks](https://www.youtube.com/watch?v=RarufLoEL08) shows how to use hooks.js in Sveltekit.. When you're done, check out [Part 2](https://www.youtube.com/watch?v=RmIBG3G0-VY)
- [An early look at SvelteKit](https://www.infoworld.com/article/3630395/an-early-look-at-sveltekit.html) is a post from Infoworld walking through the features and onboarding of SvelteKit
**Libraries, Tools & Components**
- [sveltekit-netlify-cms](https://github.com/buhrmi/sveltekit-netlify-cms) is a SvelteKit skeleton app configured for use with Netlify CMS
- [SvelteFireTS](https://github.com/jacobbowdoin/sveltefirets) is a SvelteKit + Typescript + Firebase library inspired by Fireship.io
- [stores-x](https://github.com/Anyass3/stores-x) lets you use Svelte stores just like vueX
- [sveltekit-snippets](https://github.com/stordahl/sveltekit-snippets) is a VSCode extension that provides snippets for common patterns in SvelteKit & Vanilla Svelte
- [svelte-xactor](https://github.com/wobsoriano/svelte-xactor) is a middleware that allows you to easily convert your xactor machines into a global store that implements the store contract
- [vite-plugin-pages-svelte](https://github.com/aldy505/vite-plugin-pages-svelte) is a vite plugin for automatic filesystem-based routing
- [sveltio](https://www.npmjs.com/package/sveltio) is a Svelte wrapper for valtio - a proxy-state library
- [svelte-transition-classes](https://github.com/rmarscher/svelte-transition-classes) is a custom Svelte transition for adding and swapping CSS classes
- [Svelte-Boring-Avatars](https://github.com/paolotiu/svelte-boring-avatars) is Svelte port of the popular [Boring Avatars](https://github.com/boringdesigners/boring-avatars) React project
- [Svelte DataTables](https://github.com/homescriptone/svelte-datatables) brings DataTable, a popular JavaScript library allowing you to easily display your data in a user-friendly table, into your Svelte project.
- [focus-svelte](https://github.com/chanced/focus-svelte) is a focus trap for Svelte with zero dependencies
- [filedrop-svelte](https://github.com/chanced/filedrop-svelte) is a file dropzone action & component for Svelte
Check out the community site [sveltesociety.dev](https://sveltesociety.dev/templates/) for more templates, adders and adapters from across the Svelte ecosystem.
## Before you go, answer the call for speakers!
Svelte Summit Fall 2021 (happening 20 November 2021) is looking for speakers. Submit your talk propsoal before 30 October... all are welcome to present and attend.
### More info on the [sessionize site](https://sessionize.com/svelte-summit-fall-2021/)
Can't wait for the summit? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs)!

@ -0,0 +1,85 @@
---
title: What's new in Svelte: November 2021
description: Over 5000 stars to light up the showcase
author: Daniel Sandoval
authorURL: https://desandoval.net
---
With SvelteKit crossing the [80% complete mark](https://github.com/sveltejs/kit/milestone/2), over [5000 stars](https://github.com/sveltejs/kit) on GitHub, and now having more usage than Sapper, there's never been a better time to try it out! Many in the community have, making for quite a large showcase this month...
Also, don't miss out on [Svelte Summit](https://sveltesummit.com/) on November 20th - featuring speakers from around the world. Keep an eye out for a watch party in your area 👀
Now onto what's new!
## New in Svelte and SvelteKit
- [svelte.dev](https://svelte.dev/) now runs on SvelteKit alongside [sveltesociety.dev](https://sveltesociety.dev). svelte.dev is a relatively complicated site with live code editing, authentication, and a markdown-based blog - making it a great way for us to really test out SvelteKit
- A new compiler option, `enableSourcemap`, provides more control over the compiler output for JS and CSS sourcemaps (**3.44.0**). With this new feature, SvelteKit and the Vite Svelte plugin can now properly handle environment variables in `.svelte` templates (See [sveltejs/kit#720](https://github.com/sveltejs/kit/issues/720) and [sveltejs/vite-plugin-svelte#201](https://github.com/sveltejs/vite-plugin-svelte/pull/201))
- The Svelte Language Tools now support reading the configuration of the VS Code CSS settings ([#1219](https://github.com/sveltejs/language-tools/issues/1219))
- `vite-plugin-svelte` added a new `experimental.prebundleSvelteLibraries` option that makes it much faster to load Svelte libraries with many components like icon libraries and UI frameworks. The option can be set in the root of `svelte.config.js`. Please test it out and give us feedback!
- SvelteKit will only route endpoints on the client, unless marked as `rel="external"` - reducing the size of the client JS and making it easier to refactor the router in the future ([2656](https://github.com/sveltejs/kit/pull/2656))
- SvelteKit no longer supports Node 12 ([2604](https://github.com/sveltejs/kit/pull/2604))
- SvelteKit was upgraded from Vite 2.6.0 to Vite 2.6.12 fixing an issue where Vite would corrupt the Svelte runtime (https://github.com/vitejs/vite/issues/4306). It also included two fixes from the SvelteKit team to avoid or make diagnosing Vite issues in SvelteKit templates easier (https://github.com/vitejs/vite/pull/5192 and https://github.com/vitejs/vite/pull/5193). Vite 2.7 is currently available in beta with additional fixes for SSR
To see all updates to Svelte and SvelteKit, check out the [Svelte](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md) and [SvelteKit changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md), respectively.
---
## Community Showcase
**Apps & Sites**
- [Tangent](http://tangentnotes.com/) is a clean and powerful notes app for Mac & Windows
- [The Pudding](https://pudding.cool/) is a digital publication that explains ideas debated in culture with visual essays - rebuilt in SvelteKit
- [Power Switcher](https://powerswitcher.axpo.com/) is an interactive overview of the development of the power supply in Switzerland, as energy sources migrate to cleaner sources
- [Sublive](https://sub.live/) is a new way of making music by connecting musicians all over the world with a low-latency and high-quality audio network
- [Vibify](https://www.vibify.me/) helps you find hidden playlists within your music using your Spotify listening history
- [Browse Marvel Unlimited by Year](https://marvel.geoffrich.net/) is a SvelteKit site to see what issues are available on Marvel Unlimited for a given year
- [Files](https://files.community/), a modern file explorer for Windows, has a new site rebuilt with SvelteKit
- [lil-hash](https://github.com/jackbow/lil-hash) is a simple URL shortener that produces easily rememberable and speakable shortened URLs
- [PWA Haven](https://github.com/ThaUnknown/pwa-haven) is a collection of small, fast, simple PWAs to replace native OS apps
- [DottoBit](https://dottobit.com/) is a multi-color 16-bit drawing program with URL sharing built-in
- [Former Fast Document for Print](https://github.com/zummon/former) is an invoice generator with beautiful designs, abilities for international languages and auto calculation
- [Helvetikon](https://github.com/noahsalvi/helvetikon) is a community maintained dictionary for the Swiss German language
- [Palitra App](https://palitra.app/) is a search-based color pallete generator
**Podcasts Featuring Svelte**
- [Svelte Radio](https://www.svelteradio.com/episodes/svelte-summit-is-coming-up-and-svelte-is-growing) dives into the tech behind the recently released Svelte Summit website and a bunch of other fun stuff!
- [PodRocket](https://podrocket.logrocket.com/rich-harris), LogRocket's podcast, talks Svelte with Rich Harris
- [PodRocket also dove deep](https://podrocket.logrocket.com/elderjs) into Elder.js with Nick Reese
- [Web Rush](https://webrush.io/episodes/episode-153-single-page-application-vs-multi-page-application-with-rich-harris) and Rich Harris talk about the differences between a SPA and MPA, what role the server rendering plays, what client side hydration is, and the state of modern tooling for developing an SPA or MPA
- [devtools.fm](https://devtools.fm/episode/15) talks with Rich Harris about developing engaging data visualizations and building the tools of tomorrow
**Educational Content**
- [Have Single-Page Apps Ruined the Web?](https://www.youtube.com/watch?v=860d8usGC0o) Rich Harris answers the controversial question at this year's Jamstack Conf
- [Svelte vs SvelteKit - What's The Difference?](https://www.youtube.com/watch?v=IKhtnhQKjxQ) LevelUpTuts provides a quick guide to explaining the relationship between the two projects. You can check out the rest of Scott Tolinski's guides to Svelte in his new series, ["Weekly Svelte"](https://www.youtube.com/playlist?list=PLLnpHn493BHF-Onm1MQgKC1psvW-rJuYi)
- [WebJeda's SvelteKit Hooks](https://www.youtube.com/watch?v=RarufLoEL08&list=PLm_Qt4aKpfKgzcTiMT2cgWGBDBIPK06DQ) series continues this month with Part 3 - Cookie Session Authentication
- [Writing Context Aware Styles in a Svelte App](https://www.ryanfiller.com/blog/tips/svelte-contex-aware-styles) is a guide to writing self-contained components that are able to dynamically adapt to their parents
- [A Beginners Guide to SvelteKit](https://www.sitepoint.com/a-beginners-guide-to-sveltekit/) takes a beginner-friendly look at both Svelte and SvelteKit and build out a simple web app showing profile pages of imaginary users
- [Svelte vs React: Ending the Debate](https://massivepixel.io/blog/svelte-vs-react/) is a historical take on the age-old argument
- [Svelte Snacks | Custom Events for Modal Actions](https://jeremydayslice.hashnode.dev/svelte-snacks-or-custom-events-for-modal-actions) walks through a solid implementation of Svelte's handy custom event system
- [What Svelte's accessibility warnings won't tell you](https://geoffrich.net/posts/svelte-a11y-limits/) explains how Svelte's a11y warnings work and why you shouldn't count on them to make your app accessible
**Libraries, Tools & Components**
- [svelte-adapter-azure-swa](https://github.com/geoffrich/svelte-adapter-azure-swa) is an adapter for Svelte apps that creates an Azure Static Web App, using an Azure function for dynamic server rendering
- [Inlang](https://docs.inlang.dev/getting-started/svelte-kit) is a localization and internationalization toolkit that now supports SvelteKit
- [svelte-translate-tools](https://github.com/noelmugnier/svelte-translate-tools) extract/generate/compile translation files for your Svelte App at build time
- [@egjs/svelte-infinitegrid](https://github.com/naver/egjs-infinitegrid/tree/master/packages/svelte-infinitegrid) lets you implement various grids composed of different card elements whose sizes vary
- [svelte-reactive-css-preprocess](https://github.com/srmullen/svelte-reactive-css-preprocess) makes it easier to update css variable values whenever your component state changes
- [Sveltegen](https://github.com/snuffyDev/sveltegen) is a CLI for simple and easy creation of actions, components, and routes
- [svelte-advanced-multistep-form](https://www.npmjs.com/package/svelte-advanced-multistep-form) helps to wrap form elements passing down styles to the component to be rendered, also it presents each form step in a ordered and stylish way
- [gQuery](https://github.com/leveluptuts/gQuery) is a GraphQL Fetcher & Cache for SvelteKit
- [date-picker-svelte](https://github.com/probablykasper/date-picker-svelte) is a date and time picker for Svelte
- [TwelveUI](https://twelveui.readme.io/reference/what-is-twelveui) is a Svelte component library with accessibility built-in
- [svelte-outclick](https://github.com/babakfp/svelte-outclick/) is a Svelte component that allows you to listen for clicks outside of an element, by providing you an outclick event
- [svelte-zero-api](https://github.com/ymzuiku/svelte-zero-api) lets you use SvelteKit APIs like client functions - with support for Typescript
- [svelte-recaptcha-v2](https://github.com/basaran/svelte-recaptcha-v2) is a Google reCAPTCHA v2 implementation for Svelte SPA, SSR and sveltekit static sites.
- [Svelte Body](https://github.com/ghostdevv/svelte-body) lets you apply styles to the body in routes - designed to work with SvelteKit and Routify.
- [svelte-debug-console](https://github.com/basaran/svelte-debug-console) is a debug.js implementation for Svelte SPA, SSR and sveltekit static sites that lets you see your debug statements in the browser.
- [SVEO](https://github.com/didier/sveo) is a dependency-free approach to declare metadata on SvelteKit pages
- [@svelte-drama/suspense](https://www.npmjs.com/package/@svelte-drama/suspense) is a Svelte component that implements the core idea of React's `<Suspense>`. Also check out [SWR for Svelte](https://www.npmjs.com/package/@svelte-drama/swr) to make refetching even easier.
- [sveltekit-adapter-browser-extension](https://github.com/antony/sveltekit-adapter-browser-extension) is an adapter for SvelteKit which turns your app into a cross-platform browser extension
Check out the community site [sveltesociety.dev](https://sveltesociety.dev/templates/) for more tools, templates, adders and adapters from across the Svelte ecosystem.
Looking for more Svelte goodness? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs)!

@ -13,11 +13,11 @@ All three sections — script, styles and markup — are optional.
// logic goes here // logic goes here
</script> </script>
<!-- markup (zero or more items) goes here -->
<style> <style>
/* styles go here */ /* styles go here */
</style> </style>
<!-- markup (zero or more items) goes here -->
``` ```
### &lt;script&gt; ### &lt;script&gt;

@ -309,7 +309,7 @@ An each block can also have an `{:else}` clause, which is rendered if the list i
--- ---
Await blocks allow you to branch on the three possible states of a Promise — pending, fulfilled or rejected. Await blocks allow you to branch on the three possible states of a Promise — pending, fulfilled or rejected. In SSR mode, only the pending state will be rendered on the server.
```sv ```sv
{#await promise} {#await promise}
@ -350,7 +350,7 @@ If you don't care about the pending state, you can also omit the initial block.
--- ---
If conversely you only want to show the error state, you can omit the `then` block. Similarly, if you only want to show the error state, you can omit the `then` block.
```sv ```sv
{#await promise catch error} {#await promise catch error}
@ -515,8 +515,8 @@ The following modifiers are available:
* `nonpassive` — explicitly set `passive: false` * `nonpassive` — explicitly set `passive: false`
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase
* `once` — remove the handler after the first time it runs * `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself * `self` — only trigger handler if `event.target` is the element itself
* `trusted` — only trigger handler if `event.trusted` is `true`. I.e. if the event is triggered by a user action. * `trusted` — only trigger handler if `event.isTrusted` is `true`. I.e. if the event is triggered by a user action.
Modifiers can be chained together, e.g. `on:click|once|capture={...}`. Modifiers can be chained together, e.g. `on:click|once|capture={...}`.
@ -602,6 +602,22 @@ On `<input>` elements with `type="file"`, you can use `bind:files` to get the [`
/> />
``` ```
---
`bind:` can be used together with `on:` directives. The order that they are defined in determines the value of the bound variable when the event handler is called.
```sv
<script>
let value = 'Hello World';
</script>
<input
on:input="{() => console.log('Old value:', value)}"
bind:value
on:input="{() => console.log('New value:', value)}"
/>
```
##### Binding `<select>` value ##### Binding `<select>` value
@ -651,6 +667,19 @@ Elements with the `contenteditable` attribute support `innerHTML` and `textConte
<div contenteditable="true" bind:innerHTML={html}></div> <div contenteditable="true" bind:innerHTML={html}></div>
``` ```
---
`<details>` elements support binding to the `open` property.
```sv
<details bind:open={isOpen}>
<summary>Details</summary>
<p>
Something small enough to escape casual notice.
</p>
</details>
```
##### Media element bindings ##### Media element bindings
--- ---
@ -670,7 +699,7 @@ Media elements (`<audio>` and `<video>`) have their own set of bindings — six
* `playbackRate` — how fast or slow to play the video, where 1 is 'normal' * `playbackRate` — how fast or slow to play the video, where 1 is 'normal'
* `paused` — this one should be self-explanatory * `paused` — this one should be self-explanatory
* `volume` — a value between 0 and 1 * `volume` — a value between 0 and 1
* `muted` — a boolean value where `true` is muted * `muted` — a boolean value indicating whether the player is muted
Videos additionally have readonly `videoWidth` and `videoHeight` bindings. Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
@ -1003,20 +1032,22 @@ A custom transition function can also return a `tick` function, which is called
<script> <script>
export let visible = false; export let visible = false;
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 1 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === Node.TEXT_NODE node.childNodes[0].nodeType === Node.TEXT_NODE
); );
if (!valid) return {}; if (!valid) {
throw new Error(`This transition only works on elements with a single text node child`);
}
const text = node.textContent; const text = node.textContent;
const duration = text.length * speed; const duration = text.length / (speed * 0.01);
return { return {
duration, duration,
tick: (t, u) => { tick: t => {
const i = ~~(text.length * t); const i = ~~(text.length * t);
node.textContent = text.slice(0, i); node.textContent = text.slice(0, i);
} }
@ -1025,7 +1056,7 @@ A custom transition function can also return a `tick` function, which is called
</script> </script>
{#if visible} {#if visible}
<p in:typewriter="{{ speed: 20 }}"> <p in:typewriter="{{ speed: 1 }}">
The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog
</p> </p>
{/if} {/if}
@ -1157,7 +1188,7 @@ DOMRect {
--- ---
An animation is triggered when the contents of a [keyed each block](docs#each) are re-ordered. Animations do not run when an element is removed, only when the each block's data is reordered. Animate directives must be on an element that is an *immediate* child of a keyed each block. An animation is triggered when the contents of a [keyed each block](docs#each) are re-ordered. Animations do not run when an element is added or removed, only when the index of an existing data item within the each block changes. Animate directives must be on an element that is an *immediate* child of a keyed each block.
Animations can be used with Svelte's [built-in animation functions](docs#svelte_animate) or [custom animation functions](docs#Custom_animation_functions). Animations can be used with Svelte's [built-in animation functions](docs#svelte_animate) or [custom animation functions](docs#Custom_animation_functions).
@ -1186,7 +1217,7 @@ As with actions and transitions, animations can have parameters.
--- ---
Animations can use custom functions that provide the `node`, an `animation` object and any `paramaters` as arguments. The `animation` parameter is an object containing `from` and `to` properties each containing a [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect#Properties) describing the geometry of the element in its `start` and `end` positions. The `from` property is the DOMRect of the element in its starting position, the `to` property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated. Animations can use custom functions that provide the `node`, an `animation` object and any `parameters` as arguments. The `animation` parameter is an object containing `from` and `to` properties each containing a [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect#Properties) describing the geometry of the element in its `start` and `end` positions. The `from` property is the DOMRect of the element in its starting position, the `to` property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated.
If the returned object has a `css` method, Svelte will create a CSS animation that plays on the element. If the returned object has a `css` method, Svelte will create a CSS animation that plays on the element.
@ -1288,7 +1319,7 @@ As with DOM events, if the `on:` directive is used without a value, the componen
--- ---
As of [Svelte 3.38](https://github.com/sveltejs/svelte/issues/6268) ([RFC](https://github.com/sveltejs/rfcs/pull/13)), you can pass styles as props to components for the purposes of theming, using CSS custom properties. You can also pass styles as props to components for the purposes of theming, using CSS custom properties.
Svelte's implementation is essentially syntactic sugar for adding a wrapper element. This example: Svelte's implementation is essentially syntactic sugar for adding a wrapper element. This example:
@ -1315,7 +1346,7 @@ Desugars to this:
</div> </div>
``` ```
**Note**: Since this is an extra div, beware that your CSS structure might accidentally target this. Be mindful of this added wrapper element when using this feature. Also note that not all browsers support `display: contents`: https://caniuse.com/css-display-contents **Note**: Since this is an extra `<div>`, beware that your CSS structure might accidentally target this. Be mindful of this added wrapper element when using this feature.
--- ---
@ -1466,7 +1497,7 @@ In order to place content in a slot without using a wrapper element, you can use
--- ---
`$$slots` is an object whose keys are the names of the slots passed into the component by the parent. If the parent does not pass in a slot with a particular name, that name will not be a present in `$$slots`. This allows components to render a slot (and other elements, like wrappers for styling) only if the parent provides it. `$$slots` is an object whose keys are the names of the slots passed into the component by the parent. If the parent does not pass in a slot with a particular name, that name will not be present in `$$slots`. This allows components to render a slot (and other elements, like wrappers for styling) only if the parent provides it.
Note that explicitly passing in an empty named slot will add that slot's name to `$$slots`. For example, if a parent passes `<div slot="title" />` to a child component, `$$slots.title` will be truthy within the child. Note that explicitly passing in an empty named slot will add that slot's name to `$$slots`. For example, if a parent passes `<div slot="title" />` to a child component, `$$slots.title` will be truthy within the child.
@ -1587,7 +1618,7 @@ If `this` is falsy, no component is rendered.
The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering. The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering.
Contrary to `<svelte:self>` this element can only be at the top level of your component and must never be inside a block or element. Unlike `<svelte:self>`, this element may only appear the top level of your component and must never be inside a block or element.
```sv ```sv
<script> <script>
@ -1626,12 +1657,15 @@ All except `scrollX` and `scrollY` are readonly.
--- ---
As with `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave` which don't fire on `window`; and it has to appear at the top level of your component. Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave`, which don't fire on `window`. It also lets you use [actions](docs#use_action) on the `<body>` element.
`<svelte:body>` also has to appear at the top level of your component.
```sv ```sv
<svelte:body <svelte:body
on:mouseenter={handleMouseenter} on:mouseenter={handleMouseenter}
on:mouseleave={handleMouseleave} on:mouseleave={handleMouseleave}
use:someAction
/> />
``` ```
@ -1646,7 +1680,7 @@ As with `<svelte:window>`, this element allows you to add listeners to events on
This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `html` content. This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `html` content.
As with `<svelte:window>` and `<svelte:head>` this element has to appear at the top level of your component and cannot be inside a block or other element. As with `<svelte:window>` and `<svelte:body>`, this element has to appear at the top level of your component and cannot be inside a block or other element.
```sv ```sv
<svelte:head> <svelte:head>

@ -357,7 +357,7 @@ store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) =
--- ---
Derives a store from one or more other stores. Whenever those dependencies change, the callback runs. Derives a store from one or more other stores. The callback runs initially when the first subscriber subscribes and then whenever the store dependencies change.
In the simplest version, `derived` takes a single store, and the callback returns a derived value. In the simplest version, `derived` takes a single store, and the callback returns a derived value.
@ -533,7 +533,7 @@ A `spring` store gradually changes to its target value based on its `stiffness`
* `stiffness` (`number`, default `0.15`) — a value between 0 and 1 where higher means a 'tighter' spring * `stiffness` (`number`, default `0.15`) — a value between 0 and 1 where higher means a 'tighter' spring
* `damping` (`number`, default `0.8`) — a value between 0 and 1 where lower means a 'springier' spring * `damping` (`number`, default `0.8`) — a value between 0 and 1 where lower means a 'springier' spring
* `precision` (`number`, default `0.001`) — determines the threshold at which the spring is considered to have 'settled', where lower means more precise * `precision` (`number`, default `0.01`) — determines the threshold at which the spring is considered to have 'settled', where lower means more precise
--- ---
@ -848,7 +848,7 @@ The `flip` function calculates the start and end position of an element and anim
* `easing` (`function`, default `cubicOut`) — an [easing function](docs#svelte_easing) * `easing` (`function`, default `cubicOut`) — an [easing function](docs#svelte_easing)
`duration` can be be provided as either: `duration` can be provided as either:
- a `number`, in milliseconds. - a `number`, in milliseconds.
- a function, `distance: number => duration: number`, receiving the distance the element will travel in pixels and returning the duration in milliseconds. This allows you to assign a duration that is relative to the distance travelled by each element. - a function, `distance: number => duration: number`, receiving the distance the element will travel in pixels and returning the duration in milliseconds. This allows you to assign a duration that is relative to the distance travelled by each element.

@ -6,7 +6,7 @@ Typically, you won't interact with the Svelte compiler directly, but will instea
* [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte) for users of [Rollup](https://rollupjs.org) * [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte) for users of [Rollup](https://rollupjs.org)
* [svelte-loader](https://github.com/sveltejs/svelte-loader) for users of [webpack](https://webpack.js.org) * [svelte-loader](https://github.com/sveltejs/svelte-loader) for users of [webpack](https://webpack.js.org)
* or one of the [community-maintained plugins](https://github.com/sveltejs/integrations#bundler-plugins) * or one of the [community-maintained plugins](https://sveltesociety.dev/tools)
Nonetheless, it's useful to understand how to use the compiler, since bundler plugins generally expose compiler options to you. Nonetheless, it's useful to understand how to use the compiler, since bundler plugins generally expose compiler options to you.
@ -68,7 +68,7 @@ The following options can be passed to the compiler. None are required:
| `name` | `"Component"` | `string` that sets the name of the resulting JavaScript class (though the compiler will rename it if it would otherwise conflict with other variables in scope). It will normally be inferred from `filename`. | `name` | `"Component"` | `string` that sets the name of the resulting JavaScript class (though the compiler will rename it if it would otherwise conflict with other variables in scope). It will normally be inferred from `filename`.
| `format` | `"esm"` | If `"esm"`, creates a JavaScript module (with `import` and `export`). If `"cjs"`, creates a CommonJS module (with `require` and `module.exports`), which is useful in some server-side rendering situations or for testing. | `format` | `"esm"` | If `"esm"`, creates a JavaScript module (with `import` and `export`). If `"cjs"`, creates a CommonJS module (with `require` and `module.exports`), which is useful in some server-side rendering situations or for testing.
| `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. | `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.
| `errorMode` | `"throw"` | If `"throw"`, Svelte throws when a compilation error occured. If `"warn"`, Svelte will treat errors as warnings and add them to the warning report. | `errorMode` | `"throw"` | If `"throw"`, Svelte throws when a compilation error occurred. If `"warn"`, Svelte will treat errors as warnings and add them to the warning report.
| `varsReport` | `"strict"` | If `"strict"`, Svelte returns a variables report with only variables that are not globals nor internals. If `"full"`, Svelte returns a variables report with all detected variables. If `false`, no variables report is returned. | `varsReport` | `"strict"` | If `"strict"`, Svelte returns a variables report with only variables that are not globals nor internals. If `"full"`, Svelte returns a variables report with all detected variables. If `false`, no variables report is returned.
| `dev` | `false` | If `true`, causes extra code to be added to components that will perform runtime checks and provide debugging information during development. | `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. | `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.
@ -82,6 +82,8 @@ The following options can be passed to the compiler. None are required:
| `loopGuardTimeout` | 0 | A `number` that tells Svelte to break the loop if it blocks the thread for more than `loopGuardTimeout` ms. This is useful to prevent infinite loops. **Only available when `dev: true`** | `loopGuardTimeout` | 0 | A `number` that tells Svelte to break the loop if it blocks the thread for more than `loopGuardTimeout` ms. This is useful to prevent infinite loops. **Only available when `dev: true`**
| `preserveComments` | `false` | If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out. | `preserveComments` | `false` | If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out.
| `preserveWhitespace` | `false` | If `true`, whitespace inside and between elements is kept as you typed it, rather than removed or collapsed to a single space where possible. | `preserveWhitespace` | `false` | If `true`, whitespace inside and between elements is kept as you typed it, rather than removed or collapsed to a single space where possible.
| `sourcemap` | `object \| string` | An initial sourcemap that will be merged into the final output sourcemap. This is usually the preprocessor sourcemap.
| `enableSourcemap` | `boolean \| { js: boolean; css: boolean; }` | If `true`, Svelte generate sourcemaps for components. Use an object with `js` or `css` for more granular control of sourcemap generation. By default, this is `true`.
| `outputFilename` | `null` | A `string` used for your JavaScript sourcemap. | `outputFilename` | `null` | A `string` used for your JavaScript sourcemap.
| `cssOutputFilename` | `null` | A `string` used for your CSS sourcemap. | `cssOutputFilename` | `null` | A `string` used for your CSS sourcemap.
| `sveltePath` | `"svelte"` | The location of the `svelte` package. Any imports from `svelte` or `svelte/[module]` will be modified accordingly. | `sveltePath` | `"svelte"` | The location of the `svelte` package. Any imports from `svelte` or `svelte/[module]` will be modified accordingly.
@ -188,7 +190,7 @@ const ast = svelte.parse(source, { filename: 'App.svelte' });
### `svelte.preprocess` ### `svelte.preprocess`
A number of [community-maintained preprocessing plugins](https://github.com/sveltejs/integrations#preprocessors) are available to allow you to use Svelte with tools like TypeScript, PostCSS, SCSS, and Less. A number of [community-maintained preprocessing plugins](https://sveltesociety.dev/tools#preprocessors) are available to allow you to use Svelte with tools like TypeScript, PostCSS, SCSS, and Less.
You can write your own preprocessor using the `svelte.preprocess` API. You can write your own preprocessor using the `svelte.preprocess` API.

@ -10,8 +10,10 @@
<ul> <ul>
{#each cats as { id, name }, i} {#each cats as { id, name }, i}
<li><a target="_blank" href="https://www.youtube.com/watch?v={id}"> <li>
<a target="_blank" href="https://www.youtube.com/watch?v={id}">
{i + 1}: {name} {i + 1}: {name}
</a></li> </a>
</li>
{/each} {/each}
</ul> </ul>

@ -1,5 +1,5 @@
<script> <script>
import marked from 'marked'; import { marked } from 'marked';
let text = `Some words are *italic*, some are **bold**`; let text = `Some words are *italic*, some are **bold**`;
</script> </script>

@ -1,7 +1,7 @@
<script> <script>
let visible = false; let visible = false;
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 1 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === Node.TEXT_NODE node.childNodes[0].nodeType === Node.TEXT_NODE
@ -12,7 +12,7 @@
} }
const text = node.textContent; const text = node.textContent;
const duration = text.length * speed; const duration = text.length / (speed * 0.01);
return { return {
duration, duration,
@ -30,7 +30,7 @@
</label> </label>
{#if visible} {#if visible}
<p in:typewriter> <p transition:typewriter>
The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog
</p> </p>
{/if} {/if}

@ -36,5 +36,10 @@ export default [
{ x: 2013, y: 5.35 }, { x: 2013, y: 5.35 },
{ x: 2014, y: 5.28 }, { x: 2014, y: 5.28 },
{ x: 2015, y: 4.63 }, { x: 2015, y: 4.63 },
{ x: 2016, y: 4.72 } { x: 2016, y: 4.72 },
{ x: 2017, y: 4.82 },
{ x: 2018, y: 4.79 },
{ x: 2019, y: 4.36 },
{ x: 2020, y: 4 },
{ x: 2021, y: 4.92 }
]; ];

@ -1,9 +1,9 @@
<script> <script>
import { onMount, setContext } from 'svelte'; import { onDestroy, setContext } from 'svelte';
import { mapbox, key } from './mapbox.js'; import { mapbox, key } from './mapbox.js';
setContext(key, { setContext(key, {
getMap: () => map getMap: () => map,
}); });
export let lat; export let lat;
@ -13,32 +13,31 @@
let container; let container;
let map; let map;
onMount(() => { function load() {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://unpkg.com/mapbox-gl/dist/mapbox-gl.css';
link.onload = () => {
map = new mapbox.Map({ map = new mapbox.Map({
container, container,
style: 'mapbox://styles/mapbox/streets-v9', style: 'mapbox://styles/mapbox/streets-v9',
center: [lon, lat], center: [lon, lat],
zoom zoom,
}); });
}; }
document.head.appendChild(link);
return () => { onDestroy(() => {
map.remove(); if (map) map.remove();
link.parentNode.removeChild(link);
};
}); });
</script> </script>
<svelte:head>
<link
rel="stylesheet"
href="https://unpkg.com/mapbox-gl/dist/mapbox-gl.css"
on:load={load}
/>
</svelte:head>
<div bind:this={container}> <div bind:this={container}>
{#if map} {#if map}
<slot></slot> <slot />
{/if} {/if}
</div> </div>

@ -1,4 +1,4 @@
import emotion from 'emotion/dist/emotion.umd.min.js'; import emotion from '@emotion/css@11.1.3/dist/emotion-css.umd.min.js';
const { css } = emotion; const { css } = emotion;

@ -4,6 +4,6 @@ question: Are there any books?
There are a few books: There are a few books:
- [Svelte Handbook](https://flaviocopes.com/page/download-svelte-handbook/) by Flavio Copes - [Svelte Handbook](https://flaviocopes.com/page/svelte-handbook/) by Flavio Copes
- [Svelte 3 Up and Running](https://www.amazon.com/dp/B08D6T6BKS/) by Alessandro Segala - [Svelte 3 Up and Running](https://www.amazon.com/dp/B08D6T6BKS/) by Alessandro Segala
- [Svelte and Sapper in Action](https://www.manning.com/books/svelte-and-sapper-in-action) by R. Mark Volkmann - [Svelte and Sapper in Action](https://www.manning.com/books/svelte-and-sapper-in-action) by R. Mark Volkmann

@ -0,0 +1,5 @@
---
question: Is there a tool to automatically format my .svelte files?
---
You can use prettier with the [prettier-plugin-svelte](https://www.npmjs.com/package/prettier-plugin-svelte) plugin.

@ -4,10 +4,10 @@ question: Is there a router?
The official routing library is [SvelteKit](https://kit.svelte.dev/), which is currently in beta. SvelteKit provides a filesystem router, server-side rendering (SSR), and hot module reloading (HMR) in one easy-to-use package. It shares similarities with Next.js for React. The official routing library is [SvelteKit](https://kit.svelte.dev/), which is currently in beta. SvelteKit provides a filesystem router, server-side rendering (SSR), and hot module reloading (HMR) in one easy-to-use package. It shares similarities with Next.js for React.
However, you can use any router lib you want. A lot of people use [page.js](https://github.com/visionmedia/page.js). There's also [navaid](https://github.com/lukeed/navaid), which is very similar. However, you can use any router lib you want. A lot of people use [page.js](https://github.com/visionmedia/page.js). There's also [navaid](https://github.com/lukeed/navaid), which is very similar. And [universal-router](https://github.com/kriasoft/universal-router), which is isomorphic with child routes, but without built-in history support.
If you prefer a declarative HTML approach, there's [svelte-routing](https://github.com/EmilTholin/svelte-routing). If you prefer a declarative HTML approach, there's the isomorphic [svelte-routing](https://github.com/EmilTholin/svelte-routing) library and a fork of it called [svelte-navigator](https://github.com/mefechoel/svelte-navigator) containing some additional functionality.
If you need hash-based routing on the client side, check out [svelte-spa-router](https://github.com/ItalyPaleAle/svelte-spa-router), or [abstract-state-router](https://github.com/TehShrike/abstract-state-router/), a mature router for business software. If you need hash-based routing on the client side, check out [svelte-spa-router](https://github.com/ItalyPaleAle/svelte-spa-router) or [abstract-state-router](https://github.com/TehShrike/abstract-state-router/).
For filesystem-based routing, you can take a look at [Routify](https://routify.dev). [Routify](https://routify.dev) is another filesystem-based router, similar to SvelteKit's router. Version 3 supports Svelte's native SSR.

@ -10,7 +10,7 @@ First, you'll need to integrate Svelte with a build tool. There are officially m
* [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte) * [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte)
* [svelte-loader](https://github.com/sveltejs/svelte-loader) * [svelte-loader](https://github.com/sveltejs/svelte-loader)
...and a variety of [community-maintained ones](https://github.com/sveltejs/integrations#bundler-plugins). ...and a variety of [community-maintained ones](https://sveltesociety.dev/tools).
Don't worry if you're relatively new to web development and haven't used these tools before. We've prepared a simple step-by-step guide, [Svelte for new developers](blog/svelte-for-new-developers), which walks you through the process. Don't worry if you're relatively new to web development and haven't used these tools before. We've prepared a simple step-by-step guide, [Svelte for new developers](blog/svelte-for-new-developers), which walks you through the process.

@ -38,4 +38,4 @@ const foo = obj.foo;
foo.bar = 'baz'; foo.bar = 'baz';
``` ```
...won't update references to `obj.foo.bar`, unless you follow it up with `obj = obj`. ...won't trigger reactivity on `obj.foo.bar`, unless you follow it up with `obj = obj`.

@ -25,6 +25,6 @@ The full list of modifiers:
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture)) * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture))
* `once` — remove the handler after the first time it runs * `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself * `self` — only trigger handler if event.target is the element itself
* `trusted` — only trigger handler if `event.trusted` is `true`. I.e. if the event is triggered by a user action. * `trusted` — only trigger handler if `event.isTrusted` is `true`. I.e. if the event is triggered by a user action.
You can chain modifiers together, e.g. `on:click|once|capture={...}`. You can chain modifiers together, e.g. `on:click|once|capture={...}`.

@ -14,3 +14,8 @@
</label> </label>
<p>{a} + {b} = {a + b}</p> <p>{a} + {b} = {a + b}</p>
<style>
label { display: flex }
input, p { margin: 6px }
</style>

@ -14,3 +14,8 @@
</label> </label>
<p>{a} + {b} = {a + b}</p> <p>{a} + {b} = {a + b}</p>
<style>
label { display: flex }
input, p { margin: 6px }
</style>

@ -1,5 +1,5 @@
<script> <script>
import marked from 'marked'; import { marked } from 'marked';
let value = `Some words are *italic*, some are **bold**`; let value = `Some words are *italic*, some are **bold**`;
</script> </script>

@ -1,5 +1,5 @@
<script> <script>
import marked from 'marked'; import { marked } from 'marked';
let value = `Some words are *italic*, some are **bold**`; let value = `Some words are *italic*, some are **bold**`;
</script> </script>

@ -18,4 +18,4 @@ Returning to our [earlier ice cream example](tutorial/group-inputs), we can repl
</select> </select>
``` ```
> Press and hold the `control` key for selecting multiple options. > Press and hold the `control` key (or the `command` key on MacOS) for selecting multiple options.

@ -4,7 +4,7 @@ title: Media elements
The `<audio>` and `<video>` elements have several properties that you can bind to. This example demonstrates a few of them. The `<audio>` and `<video>` elements have several properties that you can bind to. This example demonstrates a few of them.
On line 58, add `currentTime={time}`, `duration` and `paused` bindings: On line 62, add `currentTime={time}`, `duration` and `paused` bindings:
```html ```html
<video <video

@ -15,7 +15,7 @@
for (let p = 0; p < imageData.data.length; p += 4) { for (let p = 0; p < imageData.data.length; p += 4) {
const i = p / 4; const i = p / 4;
const x = i % canvas.width; const x = i % canvas.width;
const y = i / canvas.height >>> 0; const y = i / canvas.width >>> 0;
const r = 64 + (128 * x / canvas.width) + (64 * Math.sin(t / 1000)); 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 g = 64 + (128 * y / canvas.height) + (64 * Math.cos(t / 1000));

@ -15,7 +15,7 @@
for (let p = 0; p < imageData.data.length; p += 4) { for (let p = 0; p < imageData.data.length; p += 4) {
const i = p / 4; const i = p / 4;
const x = i % canvas.width; const x = i % canvas.width;
const y = i / canvas.height >>> 0; const y = i / canvas.width >>> 0;
const r = 64 + (128 * x / canvas.width) + (64 * Math.sin(t / 1000)); 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 g = 64 + (128 * y / canvas.height) + (64 * Math.cos(t / 1000));

@ -6,7 +6,7 @@
let count_value; let count_value;
const unsubscribe = count.subscribe(value => { count.subscribe(value => {
count_value = value; count_value = value;
}); });
</script> </script>

@ -13,7 +13,7 @@
return ` return `
transform: scale(${eased}) rotate(${eased * 1080}deg); transform: scale(${eased}) rotate(${eased * 1080}deg);
color: hsl( color: hsl(
${~~(t * 360)}, ${Math.trunc(t * 360)},
${Math.min(100, 1000 - 1000 * t)}%, ${Math.min(100, 1000 - 1000 * t)}%,
${Math.min(50, 500 - 500 * t)}% ${Math.min(50, 500 - 500 * t)}%
);` );`

@ -59,7 +59,7 @@ We can get a lot more creative though. Let's make something truly gratuitous:
return ` return `
transform: scale(${eased}) rotate(${eased * 1080}deg); transform: scale(${eased}) rotate(${eased * 1080}deg);
color: hsl( color: hsl(
${~~(t * 360)}, ${Math.trunc(t * 360)},
${Math.min(100, 1000 - 1000 * t)}%, ${Math.min(100, 1000 - 1000 * t)}%,
${Math.min(50, 500 - 500 * t)}% ${Math.min(50, 500 - 500 * t)}%
);` );`

@ -16,7 +16,7 @@
</label> </label>
{#if visible} {#if visible}
<p in:typewriter> <p transition:typewriter>
The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog
</p> </p>
{/if} {/if}

@ -1,7 +1,7 @@
<script> <script>
let visible = false; let visible = false;
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 1 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === Node.TEXT_NODE node.childNodes[0].nodeType === Node.TEXT_NODE
@ -12,12 +12,12 @@
} }
const text = node.textContent; const text = node.textContent;
const duration = text.length * speed; const duration = text.length / (speed * 0.01);
return { return {
duration, duration,
tick: t => { tick: t => {
const i = ~~(text.length * t); const i = Math.trunc(text.length * t);
node.textContent = text.slice(0, i); node.textContent = text.slice(0, i);
} }
}; };
@ -30,7 +30,7 @@
</label> </label>
{#if visible} {#if visible}
<p in:typewriter> <p transition:typewriter>
The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog
</p> </p>
{/if} {/if}

@ -5,7 +5,7 @@ title: Custom JS transitions
While you should generally use CSS for transitions as much as possible, there are some effects that can't be achieved without JavaScript, such as a typewriter effect: While you should generally use CSS for transitions as much as possible, there are some effects that can't be achieved without JavaScript, such as a typewriter effect:
```js ```js
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 1 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === Node.TEXT_NODE node.childNodes[0].nodeType === Node.TEXT_NODE
@ -16,12 +16,12 @@ function typewriter(node, { speed = 50 }) {
} }
const text = node.textContent; const text = node.textContent;
const duration = text.length * speed; const duration = text.length / (speed * 0.01);
return { return {
duration, duration,
tick: t => { tick: t => {
const i = ~~(text.length * t); const i = Math.trunc(text.length * t);
node.textContent = text.slice(0, i); node.textContent = text.slice(0, i);
} }
}; };

@ -6,7 +6,7 @@ Ordinarily, transitions will play on elements when any container block is added
Instead, we'd like transitions to play only when individual items are added and removed — in other words, when the user drags the slider. Instead, we'd like transitions to play only when individual items are added and removed — in other words, when the user drags the slider.
We can achieve this with a *local* transition, which only plays when the immediate parent block is added or removed: We can achieve this with a *local* transition, which only plays when the block with the transition itself is added or removed:
```html ```html
<div transition:slide|local> <div transition:slide|local>

@ -1,5 +1,5 @@
<script> <script>
import { onMount } from 'svelte'; import { onDestroy } from 'svelte';
import { mapbox } from './mapbox.js'; import { mapbox } from './mapbox.js';
// set the context here... // set the context here...
@ -11,32 +11,32 @@
let container; let container;
let map; let map;
onMount(() => { function load() {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://unpkg.com/mapbox-gl/dist/mapbox-gl.css';
link.onload = () => {
map = new mapbox.Map({ map = new mapbox.Map({
container, container,
style: 'mapbox://styles/mapbox/streets-v9', style: 'mapbox://styles/mapbox/streets-v9',
center: [lon, lat], center: [lon, lat],
zoom zoom,
}); });
}; }
document.head.appendChild(link);
return () => { onDestroy(() => {
map.remove(); if (map) map.remove();
link.parentNode.removeChild(link);
};
}); });
</script> </script>
<!-- this special element will be explained in a later section -->
<svelte:head>
<link
rel="stylesheet"
href="https://unpkg.com/mapbox-gl/dist/mapbox-gl.css"
on:load={load}
/>
</svelte:head>
<div bind:this={container}> <div bind:this={container}>
{#if map} {#if map}
<slot></slot> <slot />
{/if} {/if}
</div> </div>

@ -1,9 +1,9 @@
<script> <script>
import { onMount, setContext } from 'svelte'; import { onDestroy, setContext } from 'svelte';
import { mapbox, key } from './mapbox.js'; import { mapbox, key } from './mapbox.js';
setContext(key, { setContext(key, {
getMap: () => map getMap: () => map,
}); });
export let lat; export let lat;
@ -13,32 +13,32 @@
let container; let container;
let map; let map;
onMount(() => { function load() {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://unpkg.com/mapbox-gl/dist/mapbox-gl.css';
link.onload = () => {
map = new mapbox.Map({ map = new mapbox.Map({
container, container,
style: 'mapbox://styles/mapbox/streets-v9', style: 'mapbox://styles/mapbox/streets-v9',
center: [lon, lat], center: [lon, lat],
zoom zoom,
}); });
}; }
document.head.appendChild(link);
return () => { onDestroy(() => {
map.remove(); if (map) map.remove();
link.parentNode.removeChild(link);
};
}); });
</script> </script>
<!-- this special element will be explained in a later section -->
<svelte:head>
<link
rel="stylesheet"
href="https://unpkg.com/mapbox-gl/dist/mapbox-gl.css"
on:load={load}
/>
</svelte:head>
<div bind:this={container}> <div bind:this={container}>
{#if map} {#if map}
<slot></slot> <slot />
{/if} {/if}
</div> </div>

@ -45,5 +45,6 @@
span { span {
position: absolute; position: absolute;
font-size: 5vw; font-size: 5vw;
user-select: none;
} }
</style> </style>

@ -0,0 +1,15 @@
version: "3.0"
services:
postgres:
image: postgres:13.4
ports:
- "5432:5432"
environment:
- POSTGRES_DB=${PGDATABASE}
- POSTGRES_USER=${PGUSER}
- POSTGRES_PASSWORD=${PGPASSWORD}
adminer:
image: adminer
restart: always
ports:
- "4000:8080"

4946
site/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -2,62 +2,43 @@
"name": "svelte.dev", "name": "svelte.dev",
"version": "1.0.0", "version": "1.0.0",
"description": "Docs and examples for Svelte", "description": "Docs and examples for Svelte",
"type": "module",
"scripts": { "scripts": {
"dev": "node scripts/update.js && npm run copy-workers && sapper dev", "dev": "node scripts/update.js && npm run copy-workers && svelte-kit dev",
"copy-workers": "node scripts/copy-workers.js", "copy-workers": "node scripts/copy-workers.js",
"migrate": "node-pg-migrate -r dotenv/config", "migrate": "node-pg-migrate -r dotenv/config",
"build": "node scripts/update.js && npm run copy-workers && sapper build --legacy", "build": "node scripts/update.js && npm run copy-workers && svelte-kit build",
"update": "node scripts/update.js --force=true", "update": "node scripts/update.js --force=true",
"start": "node __sapper__/build", "preview": "svelte-kit preview",
"test": "mocha -r esm test/**", "start": "node build",
"test": "uvu test",
"deploy": "make deploy" "deploy": "make deploy"
}, },
"dependencies": { "dependencies": {
"@polka/redirect": "^1.0.0-next.7",
"@polka/send": "^1.0.0-next.7",
"cookie": "^0.4.0", "cookie": "^0.4.0",
"devalue": "^2.0.0", "devalue": "^2.0.0",
"do-not-zip": "^1.0.0", "do-not-zip": "^1.0.0",
"flru": "^1.0.2", "flru": "^1.0.2",
"httpie": "^1.1.2", "httpie": "^1.1.2",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"marked": "^1.0.0", "marked": "3.0.5",
"pg": "^7.12.1", "pg": "^8.7.1",
"polka": "^1.0.0-next.9",
"prism-svelte": "^0.4.3", "prism-svelte": "^0.4.3",
"prismjs": "^1.24.0", "prismjs": "^1.25.0"
"sirv": "^1.0.0",
"yootils": "0.0.16"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.6.0",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.6.0",
"@babel/preset-env": "^7.6.0",
"@babel/runtime": "^7.6.0",
"@rollup/plugin-babel": "^5.0.0",
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"@rollup/plugin-replace": "^2.2.0",
"@sindresorhus/slugify": "^0.9.1", "@sindresorhus/slugify": "^0.9.1",
"@sveltejs/adapter-node": "next",
"@sveltejs/kit": "next",
"@sveltejs/site-kit": "^1.4.0", "@sveltejs/site-kit": "^1.4.0",
"@sveltejs/svelte-repl": "^0.2.1", "@sveltejs/svelte-repl": "0.3.0",
"degit": "^2.1.4", "degit": "^2.1.4",
"dotenv": "^8.1.0", "dotenv": "^10.0.0",
"esm": "^3.2.25",
"jimp": "^0.8.0", "jimp": "^0.8.0",
"mocha": "^6.2.0",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"node-pg-migrate": "^3.22.0", "node-pg-migrate": "^6.0.0",
"rollup": "^2.30.0",
"rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0",
"sapper": "^0.28.10",
"shelljs": "^0.8.3", "shelljs": "^0.8.3",
"svelte": "^3.39.0" "svelte": "^3.39.0",
}, "uvu": "^0.5.2"
"engines": {
"node": ">=10.0.0"
} }
} }

@ -1,122 +0,0 @@
import 'dotenv/config';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import replace from '@rollup/plugin-replace';
import resolve from '@rollup/plugin-node-resolve';
import svelte from 'rollup-plugin-svelte';
import { terser } from 'rollup-plugin-terser';
import config from 'sapper/config/rollup.js';
import pkg from './package.json';
const mode = process.env.NODE_ENV;
const dev = mode === 'development';
const legacy = !!process.env.SAPPER_LEGACY_BUILD;
if (!dev && !process.env.MAPBOX_ACCESS_TOKEN) {
throw new Error('MAPBOX_ACCESS_TOKEN is missing. Please add the token in the .env file before generating the production build.');
}
const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning);
const dedupe = importee => importee === 'svelte' || importee.startsWith('svelte/');
export default {
client: {
input: config.client.input(),
output: config.client.output(),
plugins: [
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN)
}),
svelte({
compilerOptions: {
dev,
hydratable: true
}
}),
resolve({
browser: true,
dedupe
}),
commonjs(),
json(),
legacy && babel({
extensions: ['.js', '.mjs', '.html', '.svelte'],
babelHelpers: 'runtime',
exclude: ['node_modules/@babel/**'],
presets: [
['@babel/preset-env', {
targets: '> 0.25%, not dead'
}]
],
plugins: [
'@babel/plugin-syntax-dynamic-import',
['@babel/plugin-transform-runtime', {
useESModules: true
}]
]
}),
!dev && terser({
module: true
})
],
preserveEntrySignatures: false,
onwarn
},
server: {
input: config.server.input(),
output: config.server.output(),
plugins: [
replace({
'process.browser': false,
'process.env.NODE_ENV': JSON.stringify(mode)
}),
svelte({
compilerOptions: {
dev,
generate: 'ssr',
hydratable: true
},
emitCss: false
}),
resolve({
dedupe
}),
commonjs(),
json()
],
external: [
'yootils',
'codemirror',
...Object.keys(pkg.dependencies || {}).concat(
require('module').builtinModules || Object.keys(process.binding('natives'))
)
],
preserveEntrySignatures: 'strict',
onwarn
},
serviceworker: {
input: config.serviceworker.input(),
output: config.serviceworker.output(),
plugins: [
resolve(),
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode)
}),
commonjs(),
!dev && terser()
],
preserveEntrySignatures: false,
onwarn
}
};

@ -1,4 +1,4 @@
const sh = require('shelljs'); import sh from 'shelljs';
sh.rm('-rf', 'static/workers'); sh.rm('-rf', 'static/workers');
sh.cp('-r', 'node_modules/@sveltejs/svelte-repl/workers', 'static'); sh.cp('-r', 'node_modules/@sveltejs/svelte-repl/workers', 'static');

@ -1,7 +1,7 @@
const fs = require('fs'); import fs from 'fs';
const puppeteer = require('puppeteer'); import puppeteer from 'puppeteer';
const Jimp = require('jimp'); import Jimp from 'jimp';
const c = require('kleur'); import c from 'kleur';
const slugs = []; const slugs = [];

@ -1,5 +1,8 @@
const sander = require('sander'); import sander from 'sander';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(`${__dirname}/../..`); process.chdir(`${__dirname}/../..`);
function extract_frontmatter(markdown) { function extract_frontmatter(markdown) {

@ -1,10 +1,14 @@
require('dotenv/config'); import 'dotenv/config';
const fs = require('fs'); import fs from 'fs';
const fetch = require('node-fetch'); import fetch from 'node-fetch';
const Jimp = require('jimp'); import Jimp from 'jimp';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const force = process.env.FORCE_UPDATE === 'true'; const force = process.env.FORCE_UPDATE === 'true';
const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(__dirname); process.chdir(__dirname);
const outputFile = `../src/routes/_contributors.js`; const outputFile = `../src/routes/_contributors.js`;

@ -0,0 +1,63 @@
import 'dotenv/config';
import fs from 'fs';
import fetch from 'node-fetch';
import Jimp from 'jimp';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const force = process.env.FORCE_UPDATE === 'true';
const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(__dirname);
const outputFile = `../src/routes/_donors.js`;
if (!force && fs.existsSync(outputFile)) {
console.info(`[update/donors] ${outputFile} exists. Skipping`);
process.exit(0);
}
const SIZE = 64;
async function main() {
const res = await fetch('https://opencollective.com/svelte/members/all.json');
const donors = await res.json();
const unique = new Map();
donors.forEach(d => unique.set(d.profile, d));
let backers = [...unique.values()]
.filter(({ role }) => role === 'BACKER')
.sort((a, b) => b.totalAmountDonated - a.totalAmountDonated);
const included = [];
for (let i = 0; i < backers.length; i += 1) {
const backer = backers[i];
console.log(`${i} / ${backers.length}: ${backer.name}`);
try {
const image_data = await fetch(backer.image);
const buffer = await image_data.arrayBuffer();
const image = await Jimp.read(buffer);
image.resize(SIZE, SIZE);
included.push({ backer, image });
} catch( err) {
console.log(`Skipping ${backer.name}: no image data`);
}
}
const sprite = new Jimp(SIZE * included.length, SIZE);
for (let i = 0; i < included.length; i += 1) {
sprite.composite(included[i].image, i * SIZE, 0);
}
await sprite.quality(80).write(`../static/donors.jpg`);
// TODO: Optimizing the static/donors.jpg image should probably get automated as well
console.log('remember to additionally optimize the resulting /static/donors.jpg image file via e.g. https://squoosh.app ');
const str = `[\n\t${included.map(a => `${JSON.stringify(a.backer.name)}`).join(',\n\t')}\n]`;
fs.writeFileSync(outputFile, `export default ${str};`);
}
main();

@ -1,8 +1,9 @@
const sh = require('shelljs'); import sh from 'shelljs';
sh.env['FORCE_UPDATE'] = process.argv.includes('--force=true'); sh.env['FORCE_UPDATE'] = process.argv.includes('--force=true');
Promise.all([ Promise.all([
sh.exec('node ./scripts/get_contributors.js'), sh.exec('node ./scripts/get_contributors.js'),
sh.exec('node ./scripts/get_donors.js'),
sh.exec('node ./scripts/update_template.js') sh.exec('node ./scripts/update_template.js')
]); ]);

@ -1,9 +1,11 @@
const sh = require('shelljs'); import sh from 'shelljs';
const fs = require('fs'); import fs from 'fs';
const path = require('path'); import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
const force = process.env.FORCE_UPDATE === 'true'; const force = process.env.FORCE_UPDATE === 'true';
const __dirname = dirname(fileURLToPath(import.meta.url));
sh.cd(path.join(__dirname, '..')); sh.cd(path.join(__dirname, '..'));
const outputFile = 'static/svelte-app.json'; const outputFile = 'static/svelte-app.json';

@ -0,0 +1,26 @@
<!doctype html>
<html lang='en' class="theme-default typo-default">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<meta name='theme-color' content='#ff3e00'>
<base href='/'>
<link rel='stylesheet' href='global.css'>
<link rel='stylesheet' href='prism.css'>
<link rel='manifest' href='manifest.json'>
<link rel='icon' type='image/png' href='favicon.png'>
<meta name='twitter:card' content='summary_large_image'>
<meta name='twitter:site' content='@sveltejs'>
<meta name='twitter:creator' content='@sveltejs'>
<meta name='twitter:image' content='https://svelte.dev/images/twitter-card.png'>
<meta name='og:image' content='https://svelte.dev/images/twitter-card.png'>
%svelte.head%
</head>
<body>
<div id='svelte'>%svelte.body%</div>
</body>
</html>

@ -1,6 +0,0 @@
import '@sveltejs/site-kit/base.css';
import * as sapper from '@sapper/app';
sapper.start({
target: document.querySelector('#sapper')
});

@ -1,6 +1,7 @@
<script> <script>
import Repl from '@sveltejs/svelte-repl'; import Repl from '@sveltejs/svelte-repl';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { browser } from '$app/env';
import { process_example } from '../../utils/examples'; import { process_example } from '../../utils/examples';
import InputOutputToggle from './InputOutputToggle.svelte'; import InputOutputToggle from './InputOutputToggle.svelte';
@ -12,7 +13,7 @@
let repl; let repl;
let name = 'loading...'; let name = 'loading...';
let width = process.browser let width = browser
? window.innerWidth - 32 ? window.innerWidth - 32
: 1000; : 1000;
@ -73,7 +74,7 @@
$: if (embedded) document.title = `${name} • Svelte REPL`; $: if (embedded) document.title = `${name} • Svelte REPL`;
$: svelteUrl = process.browser && version === 'local' ? $: svelteUrl = browser && version === 'local' ?
`${location.origin}/repl/local` : `${location.origin}/repl/local` :
`https://unpkg.com/svelte@${version}`; `https://unpkg.com/svelte@${version}`;
@ -116,7 +117,7 @@
<div class="repl-outer" bind:clientWidth={width} class:mobile> <div class="repl-outer" bind:clientWidth={width} class:mobile>
<div class="viewport" class:offset={checked}> <div class="viewport" class:offset={checked}>
{#if process.browser} {#if browser}
<Repl <Repl
bind:this={repl} bind:this={repl}
workersUrl="workers" workersUrl="workers"

@ -2,4 +2,4 @@
export const svelteUrl = `https://unpkg.com/svelte@3`; export const svelteUrl = `https://unpkg.com/svelte@3`;
export const rollupUrl = `https://unpkg.com/rollup@1/dist/rollup.browser.js`; export const rollupUrl = `https://unpkg.com/rollup@1/dist/rollup.browser.js`;
export const mapbox_setup = `window.MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;`; export const mapbox_setup = `window.MAPBOX_ACCESS_TOKEN = '${import.meta.env.VITE_MAPBOX_ACCESS_TOKEN}';`;

@ -0,0 +1,31 @@
// need to do this first before importing database, etc.
import dotenv from 'dotenv';
dotenv.config();
import * as cookie from 'cookie';
import { get_user, sanitize_user } from './utils/auth';
import { query } from './utils/db';
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ request, resolve }) {
if (process.env['PGHOST']) {
// this is a convenient time to clear out expired sessions
query('delete from sessions where expiry < now()');
request.locals.cookies = cookie.parse(request.headers.cookie || '');
request.locals.user = await get_user(request.locals.cookies.sid);
}
const response = await resolve(request);
return response;
}
/** @type {import('@sveltejs/kit').GetSession} */
export function getSession(request) {
return request.locals.user
? {
user: sanitize_user(request.locals.user)
}
: {};
}

@ -1,6 +1,13 @@
<script> <script context="module">
const dev = process.env.NODE_ENV === 'development'; /** @type {import('@sveltejs/kit').ErrorLoad} */
export function load({ error, status }) {
return {
props: { error, status }
};
}
</script>
<script>
export let status; export let status;
export let error; export let error;
@ -54,7 +61,7 @@
<p class="error">Encountered a {status} error</p> <p class="error">Encountered a {status} error</p>
{/if} {/if}
{#if dev && error.stack} {#if import.meta.env.DEV && error.stack}
<pre>{error.stack}</pre> <pre>{error.stack}</pre>
{:else} {:else}
{#if status >= 500} {#if status >= 500}

@ -1,13 +1,12 @@
<script> <script>
import '@sveltejs/site-kit/base.css';
import { setContext } from 'svelte'; import { setContext } from 'svelte';
import { stores } from '@sapper/app'; import { page, navigating, session } from '$app/stores';
import { Icon, Icons, Nav, NavItem } from '@sveltejs/site-kit'; import { Icon, Icons, Nav, NavItem } from '@sveltejs/site-kit';
import PreloadingIndicator from '../components/PreloadingIndicator.svelte'; import PreloadingIndicator from '../components/PreloadingIndicator.svelte';
export let segment; export let segment;
const { page, preloading, session } = stores();
setContext('app', { setContext('app', {
login: () => { login: () => {
const login_window = window.open(`${window.location.origin}/auth/login`, 'login', 'width=600,height=400'); const login_window = window.open(`${window.location.origin}/auth/login`, 'login', 'width=600,height=400');
@ -31,7 +30,7 @@
<Icons/> <Icons/>
{#if $preloading} {#if $navigating && $navigating.to}
<PreloadingIndicator/> <PreloadingIndicator/>
{/if} {/if}

@ -0,0 +1,27 @@
<script>
import donors from '../_donors.js';
</script>
<style>
.donor {
width: 2.4em;
height: 2.4em;
border-radius: 50%;
text-indent: -9999px;
display: inline-block;
background: no-repeat url(/donors.jpg);
background-size: auto 102%;
margin: 0 0.5em 0.5em 0;
border: 2px solid var(--second);
}
</style>
{#each donors as donor, i}
<a
class="donor"
style="background-position: {(100 * i) / (donors.length - 1)}% 0"
alt="{donor}"
href="https://opencollective.com/svelte">
{donor}
</a>
{/each}

@ -1,10 +1,30 @@
<script> <script>
import { companies } from './WhosUsingSvelte.js'; import { companies } from './WhosUsingSvelte.js';
const randomizer = ({prominent}) => Math.random(); const randomizer = ({ prominent }) => Math.random();
const doSort = (a, b) => randomizer(b) - randomizer(a); const doSort = (a, b) => randomizer(b) - randomizer(a);
const sortedCompanies = companies.sort(doSort); const sortedCompanies = companies.sort(doSort);
</script> </script>
<div class="logos">
{#each sortedCompanies as { href, filename, alt, style, picture, span }, index}
<a target="_blank" rel="noopener" {href} style={style || ""}>
{#if picture}
<picture>
{#each picture as { type, srcset }}
<source {type} {srcset} />
{/each}
<img src="/whos-using-svelte/{filename}" {alt} loading="lazy" />
</picture>
{:else}
<img src="/whos-using-svelte/{filename}" {alt} loading="lazy" />
{#if span}
<span>{span}</span>
{/if}
{/if}
</a>
{/each}
</div>
<style> <style>
.logos { .logos {
margin: 1em 0 0 0; margin: 1em 0 0 0;
@ -17,44 +37,30 @@
display: flex; display: flex;
align-items: center; align-items: center;
border: 2px solid var(--second); border: 2px solid var(--second);
padding: 5px 10px; padding: 0;
border-radius: 20px; border-radius: 20px;
color: var(--text); color: var(--text);
} }
picture, picture,
img { img {
height: 100%; height: 100%;
padding: 5px 10px;
transition: transform 0.2s;
min-width: 0; /* Avoid image overflow in Safari */
}
picture:hover,
img:hover {
transform: scale(1.2);
} }
@media (min-width: 540px) { @media (min-width: 540px) {
a { a {
height: 60px; height: 60px;
padding: 10px 20px;
border-radius: 30px; border-radius: 30px;
} }
picture,
img {
padding: 10px 20px;
}
} }
</style> </style>
<div class="logos">
{#each sortedCompanies as {href, filename, alt, style, picture, span}, index}
<a
target="_blank"
rel="noopener"
{href}
style="{style || ''}"
>
{#if picture}
<picture>
{#each picture as {type, srcset}}
<source {type} {srcset}>
{/each}
<img src="/whos-using-svelte/{filename}" {alt} loading="lazy">
</picture>
{:else}
<img src="/whos-using-svelte/{filename}" {alt} loading="lazy">
{#if span}
<span>{span}</span>
{/if}
{/if}
</a>
{/each}
</div>

@ -1,26 +1,25 @@
import send from '@polka/send'; import { query as db_query } from '../../utils/db';
import { query } from '../../utils/db';
export async function get(req, res) { export async function get({ query, locals }) {
if (req.user) { if (locals.user) {
const page_size = 100; const page_size = 100;
const offset = req.query.offset ? parseInt(req.query.offset) : 0; const offset = query.get('offset') ? parseInt(query.get('offset')) : 0;
const rows = await query(` const rows = await db_query(`
select g.uid, g.name, coalesce(g.updated_at, g.created_at) as updated_at select g.uid, g.name, coalesce(g.updated_at, g.created_at) as updated_at
from gists g from gists g
where g.user_id = $1 where g.user_id = $1
order by id desc order by id desc
limit ${page_size + 1} limit ${page_size + 1}
offset $2 offset $2
`, [req.user.id, offset]); `, [locals.user.id, offset]);
rows.forEach(row => { rows.forEach(row => {
row.uid = row.uid.replace(/-/g, ''); row.uid = row.uid.replace(/-/g, '');
}); });
const more = rows.length > page_size; const more = rows.length > page_size;
send(res, 200, { apps: rows.slice(0, page_size), offset: more ? offset + page_size : null }); return { body: { apps: rows.slice(0, page_size), offset: more ? offset + page_size : null }};
} else { } else {
send(res, 401); return { status: 401 };
} }
} }

@ -1,22 +1,22 @@
<script context="module"> <script context="module">
export async function preload(page, { user }) { export async function load({ fetch, page, session: { user }}) {
let apps = []; let apps = [];
let offset = null; let offset = null;
if (user) { if (user) {
let url = 'apps.json'; let url = 'apps.json';
if (page.query.offset) { if (page.query.get('offset')) {
url += `?offset=${encodeURIComponent(page.query.offset)}`; url += `?offset=${encodeURIComponent(page.query.get('offset'))}`;
} }
const r = await this.fetch(url, { const r = await fetch(url, {
credentials: 'include' credentials: 'include'
}); });
if (!r.ok) return this.error(r.status, await r.text()); if (!r.ok) return { status: r.status, body: await r.text() };
({ apps, offset } = await r.json()); ({ apps, offset } = await r.json());
} }
return { user, apps, offset }; return { props: { user, apps, offset }};
} }
</script> </script>

@ -1,6 +1,6 @@
export const oauth = 'https://github.com/login/oauth'; export const oauth = 'https://github.com/login/oauth';
export const baseurl = process.env.BASEURL; export const baseurl = process.env['BASEURL'];
export const secure = baseurl && baseurl.startsWith('https:'); export const secure = baseurl && baseurl.startsWith('https:');
export const client_id = process.env.GITHUB_CLIENT_ID; export const client_id = process.env['GITHUB_CLIENT_ID'];
export const client_secret = process.env.GITHUB_CLIENT_SECRET; export const client_secret = process.env['GITHUB_CLIENT_SECRET'];

@ -1,4 +1,3 @@
import send from '@polka/send';
import devalue from 'devalue'; import devalue from 'devalue';
import * as cookie from 'cookie'; import * as cookie from 'cookie';
import * as httpie from 'httpie'; import * as httpie from 'httpie';
@ -6,11 +5,11 @@ import { parse, stringify } from 'querystring';
import { sanitize_user, create_user, create_session } from '../../utils/auth'; import { sanitize_user, create_user, create_session } from '../../utils/auth';
import { oauth, secure, client_id, client_secret } from './_config.js'; import { oauth, secure, client_id, client_secret } from './_config.js';
export async function get(req, res) { export async function get({ query }) {
try { try {
// Trade "code" for "access_token" // Trade "code" for "access_token"
const r1 = await httpie.post(`${oauth}/access_token?` + stringify({ const r1 = await httpie.post(`${oauth}/access_token?` + stringify({
code: req.query.code, code: query.get('code'),
client_id, client_id,
client_secret, client_secret,
})); }));
@ -27,7 +26,8 @@ export async function get(req, res) {
const user = await create_user(r2.data, access_token); const user = await create_user(r2.data, access_token);
const session = await create_session(user); const session = await create_session(user);
res.writeHead(200, { return {
headers: {
'Set-Cookie': cookie.serialize('sid', session.uid, { 'Set-Cookie': cookie.serialize('sid', session.uid, {
maxAge: 31536000, maxAge: 31536000,
path: '/', path: '/',
@ -35,20 +35,20 @@ export async function get(req, res) {
secure secure
}), }),
'Content-Type': 'text/html; charset=utf-8' 'Content-Type': 'text/html; charset=utf-8'
}); },
body: `
res.end(`
<script> <script>
window.opener.postMessage({ window.opener.postMessage({
user: ${devalue(sanitize_user(user))} user: ${devalue(sanitize_user(user))}
}, window.location.origin); }, window.location.origin);
</script> </script>
`); `
};
} catch (err) { } catch (err) {
console.error('GET /auth/callback', err); console.error('GET /auth/callback', err);
send(res, 500, err.data, { return {
'Content-Type': err.headers['content-type'], status: 500,
'Content-Length': err.headers['content-length'] body: err.data
}); };
} }
} }

@ -1,19 +1,28 @@
import send from '@polka/send';
import { stringify } from 'querystring'; import { stringify } from 'querystring';
import { oauth, baseurl, client_id } from './_config.js'; import { oauth, baseurl, client_id } from './_config.js';
export const get = client_id export const get = client_id
? (req, res) => { ? () => {
const Location = `${oauth}/authorize?` + stringify({ const Location = `${oauth}/authorize?` + stringify({
scope: 'read:user', scope: 'read:user',
client_id, client_id,
redirect_uri: `${baseurl}/auth/callback`, redirect_uri: `${baseurl}/auth/callback`,
}); });
send(res, 302, Location, { Location }); return {
status: 302,
headers: {
Location
} }
: (req, res) => { };
send(res, 500, ` }
: () => {
return {
status: 500,
headers: {
'Content-Type': 'text/html; charset=utf-8'
},
body: `
<body style="font-family: sans-serif; background: rgb(255,215,215); border: 2px solid red; margin: 0; padding: 1em;"> <body style="font-family: sans-serif; background: rgb(255,215,215); border: 2px solid red; margin: 0; padding: 1em;">
<h1>Missing .env file</h1> <h1>Missing .env file</h1>
<p>In order to use GitHub authentication, you will need to <a target="_blank" href="https://github.com/settings/developers">register an OAuth application</a> and create a local .env file:</p> <p>In order to use GitHub authentication, you will need to <a target="_blank" href="https://github.com/settings/developers">register an OAuth application</a> and create a local .env file:</p>
@ -21,7 +30,6 @@ export const get = client_id
<p>The <code>BASEURL</code> variable should match the callback URL specified for your app.</p> <p>The <code>BASEURL</code> variable should match the callback URL specified for your app.</p>
<p>See also <a target="_blank" href="https://github.com/sveltejs/svelte/tree/master/site#repl-github-integration">here</a></p> <p>See also <a target="_blank" href="https://github.com/sveltejs/svelte/tree/master/site#repl-github-integration">here</a></p>
</body> </body>
`, { `
'Content-Type': 'text/html; charset=utf-8' };
});
}; };

@ -1,17 +1,18 @@
import send from '@polka/send';
import * as cookie from 'cookie'; import * as cookie from 'cookie';
import { secure } from './_config.js'; import { secure } from './_config.js';
import { delete_session } from '../../utils/auth.js'; import { delete_session } from '../../utils/auth.js';
export async function get(req, res) { export async function get(request) {
await delete_session(req.cookies.sid); await delete_session(request.locals.cookies.sid);
send(res, 200, '', { return {
headers: {
'Set-Cookie': cookie.serialize('sid', '', { 'Set-Cookie': cookie.serialize('sid', '', {
maxAge: -1, maxAge: -1,
path: '/', path: '/',
httpOnly: true, httpOnly: true,
secure secure
}) })
}); }
};
} }

@ -1,9 +1,8 @@
import send from '@polka/send';
import get_posts from './_posts.js'; import get_posts from './_posts.js';
let lookup; let lookup;
export function get(req, res) { export function get({ params }) {
if (!lookup || process.env.NODE_ENV !== 'production') { if (!lookup || process.env.NODE_ENV !== 'production') {
lookup = new Map(); lookup = new Map();
get_posts().forEach(post => { get_posts().forEach(post => {
@ -11,12 +10,14 @@ export function get(req, res) {
}); });
} }
const post = lookup.get(req.params.slug); const post = lookup.get(params.slug);
if (post) { if (post) {
res.setHeader('Cache-Control', `max-age=${5 * 60 * 1e3}`); // 5 minutes return {
send(res, 200, post); body: post,
} else { headers: {
send(res, 404, { message: 'not found' }); 'Cache-Control': `max-age=${5 * 60 * 1e3}` // 5 minutes
}
};
} }
} }

@ -1,7 +1,9 @@
<script context="module"> <script context="module">
export async function preload({ params }) { export async function load({ fetch, page: { params } }) {
const res = await this.fetch(`blog/${params.slug}.json`); const res = await fetch(`/blog/${params.slug}.json`);
return res.ok ? { post: await res.json() } : this.error(404, 'Not found'); if (res.ok) {
return { props: { post: await res.json() }};
}
} }
</script> </script>

@ -1,9 +1,8 @@
import send from '@polka/send';
import get_posts from './_posts.js'; import get_posts from './_posts.js';
let json; let json;
export function get(req, res) { export function get() {
if (!json || process.env.NODE_ENV !== 'production') { if (!json || process.env.NODE_ENV !== 'production') {
const posts = get_posts() const posts = get_posts()
.filter(post => !post.metadata.draft) .filter(post => !post.metadata.draft)
@ -17,8 +16,11 @@ export function get(req, res) {
json = JSON.stringify(posts); json = JSON.stringify(posts);
} }
send(res, 200, json, { return {
body: json,
headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Cache-Control': `max-age=${5 * 60 * 1e3}` // 5 minutes 'Cache-Control': `max-age=${5 * 60 * 1e3}` // 5 minutes
}); }
}
} }

@ -1,7 +1,11 @@
<script context="module"> <script context="module">
export async function preload() { export async function load({ fetch }) {
const posts = await this.fetch(`blog.json`).then(r => r.json()); const posts = await fetch(`blog.json`).then(r => r.json());
return { posts }; return {
props: {
posts
}
};
} }
</script> </script>
@ -22,7 +26,7 @@
<div class='posts stretch'> <div class='posts stretch'>
{#each posts as post} {#each posts as post}
<article class='post' data-pubdate={post.metadata.dateString}> <article class='post' data-pubdate={post.metadata.dateString}>
<a class="no-underline" rel='prefetch' href='blog/{post.slug}' title='Read the article »'> <a class="no-underline" sveltekit:prefetch href='blog/{post.slug}' title='Read the article »'>
<h2>{post.metadata.title}</h2> <h2>{post.metadata.title}</h2>
<p>{post.metadata.description}</p> <p>{post.metadata.description}</p>
</a> </a>

@ -1,4 +1,3 @@
import send from '@polka/send';
import get_posts from '../blog/_posts.js'; import get_posts from '../blog/_posts.js';
const months = ',Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','); const months = ',Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(',');
@ -46,9 +45,12 @@ const rss = `
</rss> </rss>
`.replace(/>[^\S]+/gm, '>').replace(/[^\S]+</gm, '<').trim(); `.replace(/>[^\S]+/gm, '>').replace(/[^\S]+</gm, '<').trim();
export function get(req, res) { export function get() {
send(res, 200, rss, { return {
body: rss,
headers: {
'Cache-Control': `max-age=${30 * 60 * 1e3}`, 'Cache-Control': `max-age=${30 * 60 * 1e3}`,
'Content-Type': 'application/rss+xml' 'Content-Type': 'application/rss+xml'
}); }
};
} }

@ -1,4 +1,6 @@
export function get(req, res) { export function get() {
res.writeHead(302, { Location: 'https://discord.gg/yy75DKs' }); return {
res.end(); status: 302,
headers: { Location: 'https://discord.gg/yy75DKs' },
};
} }

@ -1,12 +1,13 @@
import send from '@polka/send';
import get_sections from './_sections.js'; import get_sections from './_sections.js';
let json; let json;
export function get(req, res) { export function get() {
if (!json || process.env.NODE_ENV !== 'production') { if (!json || process.env.NODE_ENV !== 'production') {
json = get_sections(); json = get_sections();
} }
send(res, 200, json); return {
body: json
};
} }

@ -6,8 +6,8 @@
'4_Prefix_stores_with_$_to_access_their_values': 'accessing stores ($)' '4_Prefix_stores_with_$_to_access_their_values': 'accessing stores ($)'
}; };
export async function preload() { export async function load({ fetch }) {
const sections = await this.fetch(`docs.json`).then(r => r.json()); const sections = await fetch(`docs.json`).then(r => r.json());
for (const section of sections) { for (const section of sections) {
for (const subsection of section.subsections) { for (const subsection of section.subsections) {
const { slug } = subsection; const { slug } = subsection;
@ -18,7 +18,11 @@
} }
} }
return { sections }; return {
props: {
sections
}
};
} }
</script> </script>

@ -1,10 +1,9 @@
import send from '@polka/send';
import { get_example } from './_examples.js'; import { get_example } from './_examples.js';
const cache = new Map(); const cache = new Map();
export function get(req, res) { export function get({ params }) {
const { slug } = req.params; const { slug } = params;
let example = cache.get(slug); let example = cache.get(slug);
@ -14,10 +13,8 @@ export function get(req, res) {
} }
if (example) { if (example) {
send(res, 200, example); return {
} else { body: example
send(res, 404, { };
error: 'not found'
});
} }
} }

@ -1,18 +1,22 @@
import send from '@polka/send';
import { get_examples } from './_examples.js'; import { get_examples } from './_examples.js';
let cached; let cached;
export function get(req, res) { export function get() {
try {
if (!cached || process.env.NODE_ENV !== 'production') { if (!cached || process.env.NODE_ENV !== 'production') {
cached = get_examples().filter(section => section.title); cached = get_examples().filter(section => section.title);
} }
send(res, 200, cached); try {
} catch (e) { return {
send(res, e.status || 500, { body: cached
};
} catch(err) {
return {
status: e.status || 500,
body: {
message: e.message message: e.message
}); }
};
} }
} }

@ -1,7 +1,7 @@
<!-- FIXME sometimes it adds a trailing slash when landing --> <!-- FIXME sometimes it adds a trailing slash when landing -->
<script context="module"> <script context="module">
export async function preload() { export async function load({ fetch }) {
const sections = await this.fetch(`examples.json`).then(r => r.json()); const sections = await fetch(`examples.json`).then(r => r.json());
const title_by_slug = sections.reduce((acc, {examples}) => { const title_by_slug = sections.reduce((acc, {examples}) => {
examples.forEach(({slug, title}) => { examples.forEach(({slug, title}) => {
acc[slug] = title; acc[slug] = title;
@ -10,13 +10,18 @@
return acc; return acc;
}, {}); }, {});
return {sections, title_by_slug}; return {
props: {
sections,
title_by_slug
}
};
} }
</script> </script>
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { goto } from '@sapper/app'; import { goto } from '$app/navigation';
import Repl from '@sveltejs/svelte-repl'; import Repl from '@sveltejs/svelte-repl';
import ScreenToggle from '../../components/ScreenToggle.svelte'; import ScreenToggle from '../../components/ScreenToggle.svelte';

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

Loading…
Cancel
Save