diff --git a/.changeset/README.md b/.changeset/README.md
new file mode 100644
index 000000000000..e5b6d8d6a67a
--- /dev/null
+++ b/.changeset/README.md
@@ -0,0 +1,8 @@
+# Changesets
+
+Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
+with multi-package repos, or single-package repos to help you version and publish your code. You can
+find the full documentation for it [in our repository](https://github.com/changesets/changesets)
+
+We have a quick list of common questions to get you started engaging with this project in
+[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
diff --git a/.changeset/config.json b/.changeset/config.json
new file mode 100644
index 000000000000..b56077a9220c
--- /dev/null
+++ b/.changeset/config.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
+ "changelog": ["@svitejs/changesets-changelog-github-compact", { "repo": "sveltejs/svelte" }],
+ "commit": false,
+ "fixed": [],
+ "linked": [],
+ "access": "public",
+ "baseBranch": "main",
+ "bumpVersionsWithWorkspaceProtocolOnly": true,
+ "ignore": ["!(@sveltejs/*|svelte)"]
+}
diff --git a/.editorconfig b/.editorconfig
index 854167bbedb2..2f52d9993f71 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,6 +8,8 @@ indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
-[{package.json,.travis.yml,.eslintrc.json}]
+[test/**/expected.css]
+insert_final_newline = false
+
+[package.json]
indent_style = space
-indent_size = 2
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index a84efdafe36f..000000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,3 +0,0 @@
-src/shared
-shared.js
-test/test.js
\ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 8140b7cd9187..000000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "root": true,
- "rules": {
- "indent": [ 2, "tab", { "SwitchCase": 1 } ],
- "semi": [ 2, "always" ],
- "keyword-spacing": [ 2, { "before": true, "after": true } ],
- "space-before-blocks": [ 2, "always" ],
- "space-before-function-paren": [ 2, "always" ],
- "no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ],
- "no-cond-assign": 0,
- "no-unused-vars": 2,
- "object-shorthand": [ 2, "always" ],
- "no-const-assign": 2,
- "no-class-assign": 2,
- "no-this-before-super": 2,
- "no-var": 2,
- "no-unreachable": 2,
- "valid-typeof": 2,
- "quote-props": [ 2, "as-needed" ],
- "one-var": [ 2, "never" ],
- "prefer-arrow-callback": 2,
- "prefer-const": [ 2, { "destructuring": "all" } ],
- "arrow-spacing": 2,
- "no-inner-declarations": 0
- },
- "env": {
- "es6": true,
- "browser": true,
- "node": true,
- "mocha": true
- },
- "extends": [
- "eslint:recommended",
- "plugin:import/errors",
- "plugin:import/warnings"
- ],
- "parserOptions": {
- "ecmaVersion": 6,
- "sourceType": "module"
- },
- "settings": {
- "import/core-modules": [ "svelte" ]
- }
-}
diff --git a/.flowconfig b/.flowconfig
deleted file mode 100644
index 2ed2b0c713bf..000000000000
--- a/.flowconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-[ignore]
-/dist/.*
-
-[include]
-
-[libs]
-
-[options]
-strip_root=true
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000000..a299a4435ae8
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,3 @@
+/site/** -linguist-detectable
+/test/**/samples/** -linguist-detectable
+/**/*.svelte linguist-detectable
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000000..d632634540e5
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+open_collective: svelte
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 5e43e5ca1dbe..220af118345e 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,21 +1,28 @@
-
+- _Repeatable steps to reproduce the issue_
+
+## Thanks for being part of Svelte!
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 000000000000..2e484e5ca26d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,50 @@
+name: "\U0001F41E Bug report"
+description: Report an issue with Svelte
+labels: ['triage: bug']
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+ - type: textarea
+ id: bug-description
+ attributes:
+ label: Describe the bug
+ description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
+ placeholder: Bug description
+ validations:
+ required: true
+ - type: textarea
+ id: reproduction
+ attributes:
+ label: Reproduction
+ description: Please provide a link to a repo or REPL that can reproduce the problem you ran into. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "need reproduction" label. If no reproduction is provided within a reasonable time-frame, the issue will be closed.
+ placeholder: Reproduction
+ validations:
+ required: true
+ - type: textarea
+ id: logs
+ attributes:
+ label: Logs
+ description: 'Please include browser console and server logs around the time this bug occurred. Optional if provided reproduction. Please try not to insert an image but copy paste the log text.'
+ render: shell
+ - type: textarea
+ id: system-info
+ attributes:
+ label: System Info
+ description: Output of `npx envinfo --system --npmPackages svelte,rollup,webpack --binaries --browsers`
+ render: shell
+ placeholder: System, Binaries, Browsers
+ validations:
+ required: true
+ - type: dropdown
+ id: severity
+ attributes:
+ label: Severity
+ description: Select the severity of this issue
+ options:
+ - annoyance
+ - blocking an upgrade
+ - blocking all usage of svelte
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000000..ee3e5a41b982
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Discord Chat
+ url: https://svelte.dev/chat
+ about: Ask questions and discuss with other Svelte users in real time.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 000000000000..d79e8b2e21f3
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,35 @@
+name: 'Feature Request'
+description: Request a new Svelte feature
+labels: [enhancement]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to request this feature! If your feature request is complex or substantial enough to warrant in-depth discussion, maintainers may close the issue and ask you to open an [RFC](https://github.com/sveltejs/rfcs).
+ - type: textarea
+ id: problem
+ attributes:
+ label: Describe the problem
+ description: Please provide a clear and concise description the problem this feature would solve. The more information you can provide here, the better.
+ placeholder: I'm always frustrated when...
+ validations:
+ required: true
+ - type: textarea
+ id: solution
+ attributes:
+ label: Describe the proposed solution
+ description: Please provide a clear and concise description of what you would like to happen.
+ placeholder: I would like to see...
+ validations:
+ required: true
+ - type: dropdown
+ id: importance
+ attributes:
+ label: Importance
+ description: How important is this feature to you?
+ options:
+ - nice to have
+ - would make my life easier
+ - i cannot use svelte without it
+ validations:
+ required: true
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index d2882acf4ac2..aa5f9732b6d3 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,7 +1,11 @@
-
+- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
+- [ ] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`.
+- [ ] This message body should clearly illustrate what problems it solves.
+- [ ] Ideally, include a test that fails without this PR but passes with it.
+- [ ] If this PR changes code within `packages/svelte/src`, add a changeset (`npx changeset`).
+
+### Tests and linting
+
+- [ ] Run the tests with `pnpm test` and lint the project with `pnpm lint`
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 000000000000..cf73a1f6cb02
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,79 @@
+name: CI
+on:
+ push:
+ branches: [main]
+ pull_request:
+permissions:
+ contents: read # to fetch code (actions/checkout)
+
+env:
+ # We only install Chromium manually
+ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'
+
+jobs:
+ Tests:
+ permissions: {}
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 15
+ strategy:
+ matrix:
+ include:
+ - node-version: 18
+ os: windows-latest
+ - node-version: 18
+ os: macOS-latest
+ - node-version: 18
+ os: ubuntu-latest
+ - node-version: 20
+ os: ubuntu-latest
+ - node-version: 22
+ os: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: pnpm
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm playwright install chromium
+ - run: pnpm test
+ env:
+ CI: true
+ Lint:
+ permissions: {}
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 18
+ cache: pnpm
+ - name: install
+ run: pnpm install --frozen-lockfile
+ - name: type check
+ run: pnpm check
+ - name: lint
+ if: (${{ success() }} || ${{ failure() }}) # ensures this step runs even if previous steps fail (avoids multiple runs uncovering different issues at different steps)
+ run: pnpm lint
+ - name: build and check generated types
+ if: (${{ success() }} || ${{ failure() }}) # ensures this step runs even if previous steps fail
+ run: pnpm build && { [ "`git status --porcelain=v1`" == "" ] || (echo "Generated types have changed — please regenerate types locally with `cd packages/svelte && pnpm generate:types` and commit the changes after you have reviewed them"; git diff; exit 1); }
+ Benchmarks:
+ permissions: {}
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 18
+ cache: pnpm
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm bench
+ env:
+ CI: true
diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml
new file mode 100644
index 000000000000..71df3242e8f1
--- /dev/null
+++ b/.github/workflows/ecosystem-ci-trigger.yml
@@ -0,0 +1,94 @@
+name: ecosystem-ci trigger
+
+on:
+ issue_comment:
+ types: [created]
+
+jobs:
+ trigger:
+ runs-on: ubuntu-latest
+ if: github.repository == 'sveltejs/svelte' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run')
+ steps:
+ - uses: GitHubSecurityLab/actions-permissions/monitor@v1
+ - uses: actions/github-script@v6
+ with:
+ script: |
+ const user = context.payload.sender.login
+ console.log(`Validate user: ${user}`)
+
+ let hasTriagePermission = false
+ try {
+ const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ username: user,
+ });
+ hasTriagePermission = data.user.permissions.triage
+ } catch (e) {
+ console.warn(e)
+ }
+
+ if (hasTriagePermission) {
+ console.log('Allowed')
+ await github.rest.reactions.createForIssueComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: context.payload.comment.id,
+ content: '+1',
+ })
+ } else {
+ console.log('Not allowed')
+ await github.rest.reactions.createForIssueComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: context.payload.comment.id,
+ content: '-1',
+ })
+ throw new Error('not allowed')
+ }
+ - uses: actions/github-script@v6
+ id: get-pr-data
+ with:
+ script: |
+ console.log(`Get PR info: ${context.repo.owner}/${context.repo.repo}#${context.issue.number}`)
+ const { data: pr } = await github.rest.pulls.get({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: context.issue.number
+ })
+ return {
+ num: context.issue.number,
+ branchName: pr.head.ref,
+ repo: pr.head.repo.full_name
+ }
+ - id: generate-token
+ uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 #keep pinned for security reasons, currently 1.8.0
+ with:
+ app_id: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_ID }}
+ private_key: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_PRIVATE_KEY }}
+ repository: '${{ github.repository_owner }}/svelte-ecosystem-ci'
+ - uses: actions/github-script@v6
+ id: trigger
+ env:
+ COMMENT: ${{ github.event.comment.body }}
+ with:
+ github-token: ${{ steps.generate-token.outputs.token }}
+ result-encoding: string
+ script: |
+ const comment = process.env.COMMENT.trim()
+ const prData = ${{ steps.get-pr-data.outputs.result }}
+
+ const suite = comment.split('\n')[0].replace(/^\/ecosystem-ci run/, '').trim()
+
+ await github.rest.actions.createWorkflowDispatch({
+ owner: context.repo.owner,
+ repo: 'svelte-ecosystem-ci',
+ workflow_id: 'ecosystem-ci-from-pr.yml',
+ ref: 'main',
+ inputs: {
+ prNumber: '' + prData.num,
+ branchName: prData.branchName,
+ repo: prData.repo,
+ suite: suite === '' ? '-' : suite
+ }
+ })
diff --git a/.github/workflows/pkg.pr.new-comment.yml b/.github/workflows/pkg.pr.new-comment.yml
new file mode 100644
index 000000000000..3f1fca5a0bea
--- /dev/null
+++ b/.github/workflows/pkg.pr.new-comment.yml
@@ -0,0 +1,116 @@
+name: Update pkg.pr.new comment
+
+on:
+ workflow_run:
+ workflows: ['Publish Any Commit']
+ types:
+ - completed
+
+permissions:
+ pull-requests: write
+
+jobs:
+ build:
+ name: 'Update comment'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: GitHubSecurityLab/actions-permissions/monitor@v1
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: output
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ run-id: ${{ github.event.workflow_run.id }}
+
+ - run: ls -R .
+ - name: 'Post or update comment'
+ uses: actions/github-script@v6
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const fs = require('fs');
+ const output = JSON.parse(fs.readFileSync('output.json', 'utf8'));
+
+ const bot_comment_identifier = ``;
+
+ const body = (number) => `${bot_comment_identifier}
+
+ [Playground](https://svelte.dev/playground?version=pr-${number})
+
+ \`\`\`
+ ${output.packages.map((p) => `pnpm add https://pkg.pr.new/${p.name}@${number}`).join('\n')}
+ \`\`\`
+ `;
+
+ async function find_bot_comment(issue_number) {
+ if (!issue_number) return null;
+ const comments = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: issue_number,
+ });
+ return comments.data.find((comment) =>
+ comment.body.includes(bot_comment_identifier)
+ );
+ }
+
+ async function create_or_update_comment(issue_number) {
+ if (!issue_number) {
+ console.log('No issue number provided. Cannot post or update comment.');
+ return;
+ }
+
+ const existing_comment = await find_bot_comment(issue_number);
+ if (existing_comment) {
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: existing_comment.id,
+ body: body(issue_number),
+ });
+ } else {
+ await github.rest.issues.createComment({
+ issue_number: issue_number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: body(issue_number),
+ });
+ }
+ }
+
+ async function log_publish_info() {
+ const svelte_package = output.packages.find(p => p.name === 'svelte');
+ const svelte_sha = svelte_package.url.replace(/^.+@([^@]+)$/, '$1');
+ console.log('\n' + '='.repeat(50));
+ console.log('Publish Information');
+ console.log('='.repeat(50));
+ console.log('\nPublished Packages:');
+ console.log(output.packages.map((p) => `${p.name} - pnpm add https://pkg.pr.new/${p.name}@${p.url.replace(/^.+@([^@]+)$/, '$1')}`).join('\n'));
+ if(svelte_sha){
+ console.log('\nPlayground URL:');
+ console.log(`\nhttps://svelte.dev/playground?version=commit-${svelte_sha}`)
+ }
+ console.log('\n' + '='.repeat(50));
+ }
+
+ if (output.event_name === 'pull_request') {
+ if (output.number) {
+ await create_or_update_comment(output.number);
+ }
+ } else if (output.event_name === 'push') {
+ const pull_requests = await github.rest.pulls.list({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: 'open',
+ head: `${context.repo.owner}:${output.ref.replace('refs/heads/', '')}`,
+ });
+
+ if (pull_requests.data.length > 0) {
+ await create_or_update_comment(pull_requests.data[0].number);
+ } else {
+ console.log(
+ 'No open pull request found for this push. Logging publish information to console:'
+ );
+ await log_publish_info();
+ }
+ }
diff --git a/.github/workflows/pkg.pr.new.yml b/.github/workflows/pkg.pr.new.yml
new file mode 100644
index 000000000000..b1ba217e5a0f
--- /dev/null
+++ b/.github/workflows/pkg.pr.new.yml
@@ -0,0 +1,42 @@
+name: Publish Any Commit
+on: [push, pull_request]
+
+jobs:
+ build:
+ permissions: {}
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22.x
+ cache: pnpm
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build
+ run: pnpm build
+
+ - run: pnpx pkg-pr-new publish --comment=off --json output.json --compact --no-template './packages/svelte'
+ - name: Add metadata to output
+ uses: actions/github-script@v6
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const fs = require('fs');
+ const output = JSON.parse(fs.readFileSync('output.json', 'utf8'));
+ output.number = context.issue.number;
+ output.event_name = context.eventName;
+ output.ref = context.ref;
+ fs.writeFileSync('output.json', JSON.stringify(output), 'utf8');
+ - name: Upload output
+ uses: actions/upload-artifact@v4
+ with:
+ name: output
+ path: ./output.json
+
+ - run: ls -R .
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000000..6debe5662a88
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,48 @@
+name: Release
+
+on:
+ push:
+ branches:
+ - main
+
+permissions: {}
+jobs:
+ release:
+ # prevents this action from running on forks
+ if: github.repository == 'sveltejs/svelte'
+ permissions:
+ contents: write # to create release (changesets/action)
+ id-token: write # OpenID Connect token needed for provenance
+ pull-requests: write # to create pull request (changesets/action)
+ name: Release
+ runs-on: ubuntu-latest
+ steps:
+ - uses: GitHubSecurityLab/actions-permissions/monitor@v1
+ - name: Checkout Repo
+ uses: actions/checkout@v4
+ with:
+ # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
+ fetch-depth: 0
+ - uses: pnpm/action-setup@v4
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 18.x
+ cache: pnpm
+
+ - name: Install
+ run: pnpm install --frozen-lockfile
+
+ - name: Build
+ run: pnpm build && { [ "`git status --porcelain=v1`" == "" ] || (echo "Generated types have changed — please regenerate types locally with `cd packages/svelte && pnpm generate:types` and commit the changes after you have reviewed them"; git diff; exit 1); }
+
+ - name: Create Release Pull Request or Publish to npm
+ id: changesets
+ uses: changesets/action@v1
+ with:
+ version: pnpm changeset:version
+ publish: pnpm changeset:publish
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NPM_CONFIG_PROVENANCE: true
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 9115b3d274ce..d50343766485 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,14 +1,26 @@
-.DS_Store
-node_modules
-compiler
-ssr
-shared.js
-scratch
-!test/compiler
-!test/ssr
-.nyc_output
+# Dependency directories
+node_modules/
+
+# IDE related
+.idea
+
+# Test coverage
coverage
-coverage.lcov
-test/sourcemaps/samples/*/output.js
-test/sourcemaps/samples/*/output.js.map
-_actual.json
+*.lcov
+
+# Optional eslint cache
+.eslintcache
+
+# dotenv environment variables file
+.env
+.env.test
+
+# build output
+.vercel
+
+# OS-specific
+.DS_Store
+
+tmp
+
+benchmarking/compare/.results
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 000000000000..33484750d05a
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+playwright_skip_browser_download=1
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 000000000000..d5c124353c37
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,47 @@
+documentation/docs/
+
+packages/**/dist/*.js
+packages/**/build/*.js
+packages/**/npm/**/*
+packages/**/config/*.js
+
+# packages/svelte
+packages/svelte/messages/**/*.md
+packages/svelte/src/compiler/errors.js
+packages/svelte/src/compiler/warnings.js
+packages/svelte/src/internal/client/errors.js
+packages/svelte/src/internal/client/warnings.js
+packages/svelte/src/internal/shared/errors.js
+packages/svelte/src/internal/shared/warnings.js
+packages/svelte/src/internal/server/errors.js
+packages/svelte/tests/migrate/samples/*/output.svelte
+packages/svelte/tests/**/*.svelte
+packages/svelte/tests/**/_expected*
+packages/svelte/tests/**/_actual*
+packages/svelte/tests/**/expected*
+packages/svelte/tests/**/_output
+packages/svelte/tests/**/shards/*.test.js
+packages/svelte/tests/hydration/samples/*/_expected.html
+packages/svelte/tests/hydration/samples/*/_override.html
+packages/svelte/types
+packages/svelte/compiler/index.js
+playgrounds/sandbox/input/**.svelte
+playgrounds/sandbox/output
+
+# sites/svelte.dev
+sites/svelte.dev/static/svelte-app.json
+sites/svelte.dev/scripts/svelte-app/
+sites/svelte.dev/src/routes/_components/Supporters/contributors.jpg
+sites/svelte.dev/src/routes/_components/Supporters/contributors.js
+sites/svelte.dev/src/routes/_components/Supporters/donors.jpg
+sites/svelte.dev/src/routes/_components/Supporters/donors.js
+sites/svelte.dev/src/lib/generated
+
+**/node_modules
+**/.svelte-kit
+**/.vercel
+.github/CODEOWNERS
+.prettierignore
+.changeset
+pnpm-lock.yaml
+pnpm-workspace.yaml
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000000..c4fd5d9f2f73
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,28 @@
+{
+ "useTabs": true,
+ "singleQuote": true,
+ "trailingComma": "none",
+ "printWidth": 100,
+ "plugins": ["prettier-plugin-svelte"],
+ "overrides": [
+ {
+ "files": ["*.svelte"],
+ "options": {
+ "bracketSameLine": false
+ }
+ },
+ {
+ "files": ["README.md", "packages/*/README.md", "**/package.json"],
+ "options": {
+ "useTabs": false,
+ "tabWidth": 2
+ }
+ },
+ {
+ "files": ["sites/svelte-5-preview/src/routes/docs/content/**/*.md"],
+ "options": {
+ "printWidth": 60
+ }
+ }
+ ]
+}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 9eb0f073979a..000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-language: node_js
-node_js:
- - "4"
- - "6"
- - "node"
-env:
- global:
- - BUILD_TIMEOUT=10000
-install: npm install
-after_success: npm run codecov
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 000000000000..142965ada292
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,14 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Run sandbox",
+ "program": "${workspaceFolder}/playgrounds/sandbox/run.js",
+ "env": {
+ "NODE_OPTIONS": "--stack-trace-limit=10000"
+ }
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000000..21a2a11c84e3
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "search.exclude": {
+ "sites/svelte-5-preview/static/*": true
+ },
+ "typescript.tsdk": "node_modules/typescript/lib"
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 23de078b116f..000000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,332 +0,0 @@
-# Svelte changelog
-
-## 1.13.0
-
-* Add `<:Window>` meta tag with event listeners, and a handful of bindings ([#371](https://github.com/sveltejs/svelte/issues/371))
-* Don't uncheck radios incorrectly ([#399](https://github.com/sveltejs/svelte/issues/399))
-
-## 1.12.1
-
-* Deconflict non-helper functions (`addCss` etc) ([#388](https://github.com/sveltejs/svelte/issues/388))
-* Allow reserved words in tags, e.g. `{{class}}` ([#383](https://github.com/sveltejs/svelte/issues/383))
-
-## 1.12.0
-
-* Shorthand attributes — `` is equivalent to `` ([#384](https://github.com/sveltejs/svelte/pull/384))
-* Support `bind:group` for radio and checkbox inputs ([#311](https://github.com/sveltejs/svelte/issues/311), [#312](https://github.com/sveltejs/svelte/issues/312))
-* Better sourcemap support for two-way bindings
-
-## 1.11.4
-
-* Dev mode warning for bad `component.observe` arguments ([#369](https://github.com/sveltejs/svelte/issues/369))
-* Translate `component.on('teardown', ...)` to `component.on('destroy', ...)` and add dev warning ([#365](https://github.com/sveltejs/svelte/issues/365))
-* Use shared prototype to save bytes ([#378](https://github.com/sveltejs/svelte/pull/378))
-
-## 1.11.3
-
-* Undo CSS behaviour change in 1.11.2 ([#372](https://github.com/sveltejs/svelte/issues/372))
-* Pin version of css-tree ([#370](https://github.com/sveltejs/svelte/pull/370))
-
-## 1.11.2
-
-* Add component CSS to each document a component is rendered to ([#331](https://github.com/sveltejs/svelte/issues/331))
-
-## 1.11.1
-
-* Fix two-way binding for components inside `each` blocks ([#356](https://github.com/sveltejs/svelte/issues/356))
-
-## 1.11.0
-
-* Add `format: 'eval'` and `svelte.create`, to create components directly from source code ([#345](https://github.com/sveltejs/svelte/issues/345))
-* Node 4 compatibility ([#109](https://github.com/sveltejs/svelte/issues/109))
-
-## 1.10.3
-
-* Prevent `''` string occurence 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))
-* Don't remove ` ` incorrectly ([#348](https://github.com/sveltejs/svelte/issues/348))
-* `let` -> `var` in `addCss` block ([#351](https://github.com/sveltejs/svelte/pull/351))
-
-## 1.10.2
-
-* Accept any case for doctype declarations ([#336](https://github.com/sveltejs/svelte/issues/336))
-* Allow non-top-level `
+
+
+ {#each tiles as { x, y }}
+
+ {/each}
+
diff --git a/benchmarking/benchmarks/ssr/wrapper/wrapper_bench.js b/benchmarking/benchmarks/ssr/wrapper/wrapper_bench.js
new file mode 100644
index 000000000000..ba0457b80ea7
--- /dev/null
+++ b/benchmarking/benchmarks/ssr/wrapper/wrapper_bench.js
@@ -0,0 +1,36 @@
+import { render } from 'svelte/server';
+import { fastest_test, read_file, write } from '../../../utils.js';
+import { compile } from 'svelte/compiler';
+
+const dir = `${process.cwd()}/benchmarking/benchmarks/ssr/wrapper`;
+
+async function compile_svelte() {
+ const output = compile(read_file(`${dir}/App.svelte`), {
+ generate: 'server'
+ });
+ write(`${dir}/output/App.js`, output.js.code);
+
+ const module = await import(`${dir}/output/App.js`);
+
+ return module.default;
+}
+
+export async function wrapper_bench() {
+ const App = await compile_svelte();
+ // Do 3 loops to warm up JIT
+ for (let i = 0; i < 3; i++) {
+ render(App);
+ }
+
+ const { timing } = await fastest_test(10, () => {
+ for (let i = 0; i < 100; i++) {
+ render(App);
+ }
+ });
+
+ return {
+ benchmark: 'wrapper_bench',
+ time: timing.time.toFixed(2),
+ gc_time: timing.gc_time.toFixed(2)
+ };
+}
diff --git a/benchmarking/compare/index.js b/benchmarking/compare/index.js
new file mode 100644
index 000000000000..9d8d279c353a
--- /dev/null
+++ b/benchmarking/compare/index.js
@@ -0,0 +1,89 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import { execSync, fork } from 'node:child_process';
+import { fileURLToPath } from 'node:url';
+
+// if (execSync('git status --porcelain').toString().trim()) {
+// console.error('Working directory is not clean');
+// process.exit(1);
+// }
+
+const filename = fileURLToPath(import.meta.url);
+const runner = path.resolve(filename, '../runner.js');
+const outdir = path.resolve(filename, '../.results');
+
+if (fs.existsSync(outdir)) fs.rmSync(outdir, { recursive: true });
+fs.mkdirSync(outdir);
+
+const branches = [];
+
+for (const arg of process.argv.slice(2)) {
+ if (arg.startsWith('--')) continue;
+ if (arg === filename) continue;
+
+ branches.push(arg);
+}
+
+if (branches.length === 0) {
+ branches.push(
+ execSync('git symbolic-ref --short -q HEAD || git rev-parse --short HEAD').toString().trim()
+ );
+}
+
+if (branches.length === 1) {
+ branches.push('main');
+}
+
+process.on('exit', () => {
+ execSync(`git checkout ${branches[0]}`);
+});
+
+for (const branch of branches) {
+ console.group(`Benchmarking ${branch}`);
+
+ execSync(`git checkout ${branch}`);
+
+ await new Promise((fulfil, reject) => {
+ const child = fork(runner);
+
+ child.on('message', (results) => {
+ fs.writeFileSync(`${outdir}/${branch}.json`, JSON.stringify(results, null, ' '));
+ fulfil();
+ });
+
+ child.on('error', reject);
+ });
+
+ console.groupEnd();
+}
+
+const results = branches.map((branch) => {
+ return JSON.parse(fs.readFileSync(`${outdir}/${branch}.json`, 'utf-8'));
+});
+
+for (let i = 0; i < results[0].length; i += 1) {
+ console.group(`${results[0][i].benchmark}`);
+
+ for (const metric of ['time', 'gc_time']) {
+ const times = results.map((result) => +result[i][metric]);
+ let min = Infinity;
+ let min_index = -1;
+
+ for (let b = 0; b < times.length; b += 1) {
+ if (times[b] < min) {
+ min = times[b];
+ min_index = b;
+ }
+ }
+
+ if (min !== 0) {
+ console.group(`${metric}: fastest is ${branches[min_index]}`);
+ times.forEach((time, b) => {
+ console.log(`${branches[b]}: ${time.toFixed(2)}ms (${((time / min) * 100).toFixed(2)}%)`);
+ });
+ console.groupEnd();
+ }
+ }
+
+ console.groupEnd();
+}
diff --git a/benchmarking/compare/runner.js b/benchmarking/compare/runner.js
new file mode 100644
index 000000000000..a2e864637969
--- /dev/null
+++ b/benchmarking/compare/runner.js
@@ -0,0 +1,10 @@
+import { reactivity_benchmarks } from '../benchmarks/reactivity/index.js';
+
+const results = [];
+for (const benchmark of reactivity_benchmarks) {
+ const result = await benchmark();
+ console.error(result.benchmark);
+ results.push(result);
+}
+
+process.send(results);
diff --git a/benchmarking/run.js b/benchmarking/run.js
new file mode 100644
index 000000000000..bd96b9c2dc5a
--- /dev/null
+++ b/benchmarking/run.js
@@ -0,0 +1,55 @@
+import * as $ from '../packages/svelte/src/internal/client/index.js';
+import { reactivity_benchmarks } from './benchmarks/reactivity/index.js';
+import { ssr_benchmarks } from './benchmarks/ssr/index.js';
+
+let total_time = 0;
+let total_gc_time = 0;
+
+const suites = [
+ { benchmarks: reactivity_benchmarks, name: 'reactivity benchmarks' },
+ { benchmarks: ssr_benchmarks, name: 'server-side rendering benchmarks' }
+];
+
+// eslint-disable-next-line no-console
+console.log('\x1b[1m', '-- Benchmarking Started --', '\x1b[0m');
+$.push({}, true);
+try {
+ for (const { benchmarks, name } of suites) {
+ let suite_time = 0;
+ let suite_gc_time = 0;
+ // eslint-disable-next-line no-console
+ console.log(`\nRunning ${name}...\n`);
+
+ for (const benchmark of benchmarks) {
+ const results = await benchmark();
+ // eslint-disable-next-line no-console
+ console.log(results);
+ total_time += Number(results.time);
+ total_gc_time += Number(results.gc_time);
+ suite_time += Number(results.time);
+ suite_gc_time += Number(results.gc_time);
+ }
+
+ console.log(`\nFinished ${name}.\n`);
+
+ // eslint-disable-next-line no-console
+ console.log({
+ suite_time: suite_time.toFixed(2),
+ suite_gc_time: suite_gc_time.toFixed(2)
+ });
+ }
+} catch (e) {
+ // eslint-disable-next-line no-console
+ console.log('\x1b[1m', '\n-- Benchmarking Failed --\n', '\x1b[0m');
+ // eslint-disable-next-line no-console
+ console.error(e);
+ process.exit(1);
+}
+$.pop();
+// eslint-disable-next-line no-console
+console.log('\x1b[1m', '\n-- Benchmarking Complete --\n', '\x1b[0m');
+// eslint-disable-next-line no-console
+console.log({
+ total_time: total_time.toFixed(2),
+ total_gc_time: total_gc_time.toFixed(2)
+});
diff --git a/benchmarking/tsconfig.json b/benchmarking/tsconfig.json
new file mode 100644
index 000000000000..81fe19744ac3
--- /dev/null
+++ b/benchmarking/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "moduleResolution": "Bundler",
+ "target": "ESNext",
+ "module": "ESNext",
+ "verbatimModuleSyntax": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true,
+ "sourceMap": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowJs": true,
+ "checkJs": true
+ },
+ "include": ["./run.js", "./utils.js", "./benchmarks"]
+}
diff --git a/benchmarking/utils.js b/benchmarking/utils.js
new file mode 100644
index 000000000000..684d2ee02b4d
--- /dev/null
+++ b/benchmarking/utils.js
@@ -0,0 +1,119 @@
+import { performance, PerformanceObserver } from 'node:perf_hooks';
+import v8 from 'v8-natives';
+import * as fs from 'node:fs';
+import * as path from 'node:path';
+
+// Credit to https://github.com/milomg/js-reactivity-benchmark for the logic for timing + GC tracking.
+
+class GarbageTrack {
+ track_id = 0;
+ observer = new PerformanceObserver((list) => this.perf_entries.push(...list.getEntries()));
+ perf_entries = [];
+ periods = [];
+
+ watch(fn) {
+ this.track_id++;
+ const start = performance.now();
+ const result = fn();
+ const end = performance.now();
+ this.periods.push({ track_id: this.track_id, start, end });
+
+ return { result, track_id: this.track_id };
+ }
+
+ /**
+ * @param {number} track_id
+ */
+ async gcDuration(track_id) {
+ await promise_delay(10);
+
+ const period = this.periods.find((period) => period.track_id === track_id);
+ if (!period) {
+ // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
+ return Promise.reject('no period found');
+ }
+
+ const entries = this.perf_entries.filter(
+ (e) => e.startTime >= period.start && e.startTime < period.end
+ );
+ return entries.reduce((t, e) => e.duration + t, 0);
+ }
+
+ destroy() {
+ this.observer.disconnect();
+ }
+
+ constructor() {
+ this.observer.observe({ entryTypes: ['gc'] });
+ }
+}
+
+function promise_delay(timeout = 0) {
+ return new Promise((resolve) => setTimeout(resolve, timeout));
+}
+
+/**
+ * @param {{ (): void; (): any; }} fn
+ */
+function run_timed(fn) {
+ const start = performance.now();
+ const result = fn();
+ const time = performance.now() - start;
+ return { result, time };
+}
+
+/**
+ * @param {() => void} fn
+ */
+async function run_tracked(fn) {
+ v8.collectGarbage();
+ const gc_track = new GarbageTrack();
+ const { result: wrappedResult, track_id } = gc_track.watch(() => run_timed(fn));
+ const gc_time = await gc_track.gcDuration(track_id);
+ const { result, time } = wrappedResult;
+ gc_track.destroy();
+ return { result, timing: { time, gc_time } };
+}
+
+/**
+ * @param {number} times
+ * @param {() => void} fn
+ */
+export async function fastest_test(times, fn) {
+ const results = [];
+ for (let i = 0; i < times; i++) {
+ const run = await run_tracked(fn);
+ results.push(run);
+ }
+ const fastest = results.reduce((a, b) => (a.timing.time < b.timing.time ? a : b));
+
+ return fastest;
+}
+
+/**
+ * @param {boolean} a
+ */
+export function assert(a) {
+ if (!a) {
+ throw new Error('Assertion failed');
+ }
+}
+
+/**
+ * @param {string} file
+ */
+export function read_file(file) {
+ return fs.readFileSync(file, 'utf-8').replace(/\r\n/g, '\n');
+}
+
+/**
+ * @param {string} file
+ * @param {string} contents
+ */
+export function write(file, contents) {
+ try {
+ fs.mkdirSync(path.dirname(file), { recursive: true });
+ } catch {}
+
+ fs.writeFileSync(file, contents);
+}
diff --git a/documentation/docs/01-introduction/01-overview.md b/documentation/docs/01-introduction/01-overview.md
new file mode 100644
index 000000000000..5acbe4897bf5
--- /dev/null
+++ b/documentation/docs/01-introduction/01-overview.md
@@ -0,0 +1,30 @@
+---
+title: Overview
+---
+
+Svelte is a framework for building user interfaces on the web. It uses a compiler to turn declarative components written in HTML, CSS and JavaScript...
+
+```svelte
+
+
+
+
+
+
+```
+
+...into lean, tightly optimized JavaScript.
+
+You can use it to build anything on the web, from standalone components to ambitious full stack apps (using Svelte's companion application framework, [SvelteKit](../kit)) and everything in between.
+
+These pages serve as reference documentation. If you're new to Svelte, we recommend starting with the [interactive tutorial](/tutorial) and coming back here when you have questions.
+
+You can also try Svelte online in the [playground](/playground) or, if you need a more fully-featured environment, on [StackBlitz](https://sveltekit.new).
diff --git a/documentation/docs/01-introduction/02-getting-started.md b/documentation/docs/01-introduction/02-getting-started.md
new file mode 100644
index 000000000000..c7351729ff17
--- /dev/null
+++ b/documentation/docs/01-introduction/02-getting-started.md
@@ -0,0 +1,32 @@
+---
+title: Getting started
+---
+
+We recommend using [SvelteKit](../kit), which lets you [build almost anything](../kit/project-types). It's the official application framework from the Svelte team and powered by [Vite](https://vite.dev/). Create a new project with:
+
+```bash
+npx sv create myapp
+cd myapp
+npm install
+npm run dev
+```
+
+Don't worry if you don't know Svelte yet! You can ignore all the nice features SvelteKit brings on top for now and dive into it later.
+
+## Alternatives to SvelteKit
+
+You can also use Svelte directly with Vite by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS, and CSS files inside the `dist` directory using [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). In most cases, you will probably need to [choose a routing library](faq#Is-there-a-router) as well.
+
+>[!NOTE] Vite is often used in standalone mode to build [single page apps (SPAs)](../kit/glossary#SPA), which you can also [build with SvelteKit](../kit/single-page-apps).
+
+There are also plugins for [Rollup](https://github.com/sveltejs/rollup-plugin-svelte), [Webpack](https://github.com/sveltejs/svelte-loader) [and a few others](https://sveltesociety.dev/packages?category=build-plugins), but we recommend Vite.
+
+## Editor tooling
+
+The Svelte team maintains a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), and there are integrations with various other [editors](https://sveltesociety.dev/resources#editor-support) and tools as well.
+
+You can also check your code from the command line using [sv check](https://github.com/sveltejs/cli).
+
+## Getting help
+
+Don't be shy about asking for help in the [Discord chatroom](/chat)! You can also find answers on [Stack Overflow](https://stackoverflow.com/questions/tagged/svelte).
diff --git a/documentation/docs/01-introduction/03-svelte-files.md b/documentation/docs/01-introduction/03-svelte-files.md
new file mode 100644
index 000000000000..cd98652370f3
--- /dev/null
+++ b/documentation/docs/01-introduction/03-svelte-files.md
@@ -0,0 +1,71 @@
+---
+title: .svelte files
+---
+
+Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML.
+
+All three sections — script, styles and markup — are optional.
+
+
+```svelte
+/// file: MyComponent.svelte
+
+
+
+
+
+
+
+```
+
+## `
+
+
+```
+
+You can `export` bindings from this block, and they will become exports of the compiled module. You cannot `export default`, since the default export is the component itself.
+
+> [!NOTE] If you are using TypeScript and import such exports from a `module` block into a `.ts` file, make sure to have your editor setup so that TypeScript knows about them. This is the case for our VS Code extension and the IntelliJ plugin, but in other cases you might need to setup our [TypeScript editor plugin](https://www.npmjs.com/package/typescript-svelte-plugin).
+
+> [!LEGACY]
+> In Svelte 4, this script tag was created using `
+
+
+```
+
+Unlike other frameworks you may have encountered, there is no API for interacting with state — `count` is just a number, rather than an object or a function, and you can update it like you would update any other variable.
+
+### Deep state
+
+If `$state` is used with an array or a simple object, the result is a deeply reactive _state proxy_. [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates.
+
+> [!NOTE] Classes like `Set` and `Map` will not be proxied, but Svelte provides reactive implementations for various built-ins like these that can be imported from [`svelte/reactivity`](./svelte-reactivity).
+
+State is proxified recursively until Svelte finds something other than an array or simple object. In a case like this...
+
+```js
+let todos = $state([
+ {
+ done: false,
+ text: 'add more todos'
+ }
+]);
+```
+
+...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property:
+
+```js
+let todos = [{ done: false, text: 'add more todos' }];
+// ---cut---
+todos[0].done = !todos[0].done;
+```
+
+If you push a new object to the array, it will also be proxified:
+
+```js
+let todos = [{ done: false, text: 'add more todos' }];
+// ---cut---
+todos.push({
+ done: false,
+ text: 'eat lunch'
+});
+```
+
+> [!NOTE] When you update properties of proxies, the original object is _not_ mutated.
+
+Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring:
+
+```js
+let todos = [{ done: false, text: 'add more todos' }];
+// ---cut---
+let { done, text } = todos[0];
+
+// this will not affect the value of `done`
+todos[0].done = !todos[0].done;
+```
+
+### Classes
+
+You can also use `$state` in class fields (whether public or private):
+
+```js
+// @errors: 7006 2554
+class Todo {
+ done = $state(false);
+ text = $state();
+
+ constructor(text) {
+ this.text = text;
+ }
+
+ reset() {
+ this.text = '';
+ this.done = false;
+ }
+}
+```
+
+> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. This means the properties are not enumerable.
+
+When calling methods in JavaScript, the value of [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) matters. This won't work, because `this` inside the `reset` method will be the `
` will result in `
hello
world
` (the `
` autoclosed the `
` because `
` cannot contain block-level elements)
+- `` will result in `` (the `
` is removed)
+- `
cell
` will result in `
cell
` (a `` is auto-inserted)
+
+This code will work when the component is rendered on the client (which is why this is a warning rather than an error), but if you use server rendering it will cause hydration to fail.
+
+### non_reactive_update
+
+```
+`%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
+```
+
+This warning is thrown when the compiler detects the following:
+- a variable was declared without `$state` or `$state.raw`
+- the variable is reassigned
+- the variable is read in a reactive context
+
+In this case, changing the value will not correctly trigger updates. Example:
+
+```svelte
+
+
+
This value updates: {reactive}
+
This value does not update: {stale}
+
+ {
+ stale = 'updated';
+ reactive = 'updated';
+}}>update
+```
+
+To fix this, wrap your variable declaration with `$state`.
+
+### options_deprecated_accessors
+
+```
+The `accessors` option has been deprecated. It will have no effect in runes mode
+```
+
+### options_deprecated_immutable
+
+```
+The `immutable` option has been deprecated. It will have no effect in runes mode
+```
+
+### options_missing_custom_element
+
+```
+The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?
+```
+
+### options_removed_enable_sourcemap
+
+```
+The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them
+```
+
+### options_removed_hydratable
+
+```
+The `hydratable` option has been removed. Svelte components are always hydratable now
+```
+
+### options_removed_loop_guard_timeout
+
+```
+The `loopGuardTimeout` option has been removed
+```
+
+### options_renamed_ssr_dom
+
+```
+`generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively
+```
+
+### perf_avoid_inline_class
+
+```
+Avoid 'new class' — instead, declare the class at the top level scope
+```
+
+### perf_avoid_nested_class
+
+```
+Avoid declaring classes below the top level scope
+```
+
+### reactive_declaration_invalid_placement
+
+```
+Reactive declarations only exist at the top level of the instance script
+```
+
+### reactive_declaration_module_script_dependency
+
+```
+Reassignments of module-level declarations will not cause reactive statements to update
+```
+
+### script_context_deprecated
+
+```
+`context="module"` is deprecated, use the `module` attribute instead
+```
+
+```svelte
+
+```
+
+### script_unknown_attribute
+
+```
+Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it
+```
+
+### slot_element_deprecated
+
+```
+Using `` to render parent content is deprecated. Use `{@render ...}` tags instead
+```
+
+See [the migration guide](v5-migration-guide#Snippets-instead-of-slots) for more info.
+
+### state_referenced_locally
+
+```
+This reference only captures the initial value of `%name%`. Did you mean to reference it inside a %type% instead?
+```
+
+This warning is thrown when the compiler detects the following:
+
+- A reactive variable is declared
+- ...and later reassigned...
+- ...and referenced in the same scope
+
+This 'breaks the link' to the original state declaration. For example, if you pass the state to a function, the function loses access to the state once it is reassigned:
+
+```svelte
+
+
+
+ count++}>
+ increment
+
+```
+
+```svelte
+
+
+
+
+
The count is {count}
+```
+
+To fix this, reference the variable such that it is lazily evaluated. For the above example, this can be achieved by wrapping `count` in a function:
+
+```svelte
+
+
+
+ count++}>
+ increment
+
+```
+
+```svelte
+
+
+
+
+
The count is {+++count()+++}
+```
+
+For more info, see [Passing state into functions]($state#Passing-state-into-functions).
+
+### store_rune_conflict
+
+```
+It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity
+```
+
+### svelte_component_deprecated
+
+```
+`` is deprecated in runes mode — components are dynamic by default
+```
+
+In previous versions of Svelte, the component constructor was fixed when the component was rendered. In other words, if you wanted `` to re-render when `X` changed, you would either have to use `` or put the component inside a `{#key X}...{/key}` block.
+
+In Svelte 5 this is no longer true — if `X` changes, `` re-renders.
+
+In some cases `` syntax can be used as a replacement; a lowercased variable with property access is recognized as a component in Svelte 5.
+
+For complex component resolution logic, an intermediary, capitalized variable may be necessary. E.g. in places where `@const` can be used:
+
+
+```svelte
+{#each items as item}
+ ------
+ +++{@const Component = item.condition ? Y : Z}+++
+ ++++++
+{/each}
+```
+
+A derived value may be used in other contexts:
+
+
+```svelte
+
+
+------
+++++++
+```
+
+### svelte_element_invalid_this
+
+```
+`this` should be an `{expression}`. Using a string attribute value will cause an error in future versions of Svelte
+```
+
+### svelte_self_deprecated
+
+```
+`` is deprecated — use self-imports (e.g. `import %name% from './%basename%'`) instead
+```
+
+See [the note in the docs](legacy-svelte-self) for more info.
+
+### unknown_code
+
+```
+`%code%` is not a recognised code
+```
+
+```
+`%code%` is not a recognised code (did you mean `%suggestion%`?)
+```
diff --git a/documentation/docs/98-reference/.generated/server-errors.md b/documentation/docs/98-reference/.generated/server-errors.md
new file mode 100644
index 000000000000..c3e8b53c3145
--- /dev/null
+++ b/documentation/docs/98-reference/.generated/server-errors.md
@@ -0,0 +1,9 @@
+
+
+### lifecycle_function_unavailable
+
+```
+`%name%(...)` is not available on the server
+```
+
+Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render.
diff --git a/documentation/docs/98-reference/.generated/shared-errors.md b/documentation/docs/98-reference/.generated/shared-errors.md
new file mode 100644
index 000000000000..4c81d7b89452
--- /dev/null
+++ b/documentation/docs/98-reference/.generated/shared-errors.md
@@ -0,0 +1,73 @@
+
+
+### invalid_default_snippet
+
+```
+Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead
+```
+
+This error would be thrown in a setup like this:
+
+```svelte
+
+
+ {entry}
+
+```
+
+```svelte
+
+
+
+
+ {#each items as item}
+
{@render children(item)}
+ {/each}
+
+```
+
+Here, `List.svelte` is using `{@render children(item)` which means it expects `Parent.svelte` to use snippets. Instead, `Parent.svelte` uses the deprecated `let:` directive. This combination of APIs is incompatible, hence the error.
+
+### invalid_snippet_arguments
+
+```
+A snippet function was passed invalid arguments. Snippets should only be instantiated via `{@render ...}`
+```
+
+### lifecycle_outside_component
+
+```
+`%name%(...)` can only be used during component initialisation
+```
+
+Certain lifecycle methods can only be used during component initialisation. To fix this, make sure you're invoking the method inside the _top level of the instance script_ of your component.
+
+```svelte
+
+
+click me
+```
+
+### store_invalid_shape
+
+```
+`%name%` is not a store with a `subscribe` method
+```
+
+### svelte_element_invalid_this_value
+
+```
+The `this` prop on `` must be a string, if defined
+```
diff --git a/documentation/docs/98-reference/.generated/shared-warnings.md b/documentation/docs/98-reference/.generated/shared-warnings.md
new file mode 100644
index 000000000000..f449a4031ebf
--- /dev/null
+++ b/documentation/docs/98-reference/.generated/shared-warnings.md
@@ -0,0 +1,28 @@
+
+
+### dynamic_void_element_content
+
+```
+`` is a void element — it cannot have content
+```
+
+Elements such as `` cannot have content, any children passed to these elements will be ignored.
+
+### state_snapshot_uncloneable
+
+```
+Value cannot be cloned with `$state.snapshot` — the original value was returned
+```
+
+```
+The following properties cannot be cloned with `$state.snapshot` — the return value contains the originals:
+
+%properties%
+```
+
+`$state.snapshot` tries to clone the given value in order to return a reference that no longer changes. Certain objects may not be cloneable, in which case the original value is returned. In the following example, `property` is cloned, but `window` is not, because DOM elements are uncloneable:
+
+```js
+const object = $state({ property: 'this is cloneable', window })
+const snapshot = $state.snapshot(object);
+```
diff --git a/documentation/docs/98-reference/20-svelte.md b/documentation/docs/98-reference/20-svelte.md
new file mode 100644
index 000000000000..3295ab68de65
--- /dev/null
+++ b/documentation/docs/98-reference/20-svelte.md
@@ -0,0 +1,5 @@
+---
+title: svelte
+---
+
+> MODULE: svelte
diff --git a/documentation/docs/98-reference/21-svelte-action.md b/documentation/docs/98-reference/21-svelte-action.md
new file mode 100644
index 000000000000..53423ec4090e
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-action.md
@@ -0,0 +1,5 @@
+---
+title: svelte/action
+---
+
+> MODULE: svelte/action
diff --git a/documentation/docs/98-reference/21-svelte-animate.md b/documentation/docs/98-reference/21-svelte-animate.md
new file mode 100644
index 000000000000..e8f135d07de0
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-animate.md
@@ -0,0 +1,5 @@
+---
+title: svelte/animate
+---
+
+> MODULE: svelte/animate
diff --git a/documentation/docs/98-reference/21-svelte-compiler.md b/documentation/docs/98-reference/21-svelte-compiler.md
new file mode 100644
index 000000000000..a6cc99d3b155
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-compiler.md
@@ -0,0 +1,5 @@
+---
+title: svelte/compiler
+---
+
+> MODULE: svelte/compiler
diff --git a/documentation/docs/98-reference/21-svelte-easing.md b/documentation/docs/98-reference/21-svelte-easing.md
new file mode 100644
index 000000000000..3f47963cde9a
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-easing.md
@@ -0,0 +1,5 @@
+---
+title: svelte/easing
+---
+
+> MODULE: svelte/easing
diff --git a/documentation/docs/98-reference/21-svelte-events.md b/documentation/docs/98-reference/21-svelte-events.md
new file mode 100644
index 000000000000..00c7a14ee203
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-events.md
@@ -0,0 +1,5 @@
+---
+title: svelte/events
+---
+
+> MODULE: svelte/events
diff --git a/documentation/docs/98-reference/21-svelte-legacy.md b/documentation/docs/98-reference/21-svelte-legacy.md
new file mode 100644
index 000000000000..f313baca0b45
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-legacy.md
@@ -0,0 +1,7 @@
+---
+title: svelte/legacy
+---
+
+This module provides various functions for use during the migration, since some features can't be replaced one to one with new features. All imports are marked as deprecated and should be migrated away from over time.
+
+> MODULE: svelte/legacy
diff --git a/documentation/docs/98-reference/21-svelte-motion.md b/documentation/docs/98-reference/21-svelte-motion.md
new file mode 100644
index 000000000000..f1d5a6ce5757
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-motion.md
@@ -0,0 +1,5 @@
+---
+title: svelte/motion
+---
+
+> MODULE: svelte/motion
diff --git a/documentation/docs/98-reference/21-svelte-reactivity-window.md b/documentation/docs/98-reference/21-svelte-reactivity-window.md
new file mode 100644
index 000000000000..cc544dc5ba3f
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-reactivity-window.md
@@ -0,0 +1,15 @@
+---
+title: svelte/reactivity/window
+---
+
+This module exports reactive versions of various `window` values, each of which has a reactive `current` property that you can reference in reactive contexts (templates, [deriveds]($derived) and [effects]($effect)) without using [``](svelte-window) bindings or manually creating your own event listeners.
+
+```svelte
+
+
+
{innerWidth.current}x{innerHeight.current}
+```
+
+> MODULE: svelte/reactivity/window
diff --git a/documentation/docs/98-reference/21-svelte-reactivity.md b/documentation/docs/98-reference/21-svelte-reactivity.md
new file mode 100644
index 000000000000..6857c1dba80d
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-reactivity.md
@@ -0,0 +1,25 @@
+---
+title: svelte/reactivity
+---
+
+Svelte provides reactive versions of various built-ins like `SvelteMap`, `SvelteSet` and `SvelteURL`. These can be imported from `svelte/reactivity` and used just like their native counterparts.
+
+```svelte
+
+
+
+
+
+
+
+
+
+
+
+```
+
+> MODULE: svelte/reactivity
diff --git a/documentation/docs/98-reference/21-svelte-server.md b/documentation/docs/98-reference/21-svelte-server.md
new file mode 100644
index 000000000000..7a3fc3c6a2ba
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-server.md
@@ -0,0 +1,5 @@
+---
+title: svelte/server
+---
+
+> MODULE: svelte/server
diff --git a/documentation/docs/98-reference/21-svelte-store.md b/documentation/docs/98-reference/21-svelte-store.md
new file mode 100644
index 000000000000..23ff6c5e376f
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-store.md
@@ -0,0 +1,5 @@
+---
+title: svelte/store
+---
+
+> MODULE: svelte/store
diff --git a/documentation/docs/98-reference/21-svelte-transition.md b/documentation/docs/98-reference/21-svelte-transition.md
new file mode 100644
index 000000000000..396bc0aebf69
--- /dev/null
+++ b/documentation/docs/98-reference/21-svelte-transition.md
@@ -0,0 +1,5 @@
+---
+title: svelte/transition
+---
+
+> MODULE: svelte/transition
diff --git a/documentation/docs/98-reference/30-compiler-errors.md b/documentation/docs/98-reference/30-compiler-errors.md
new file mode 100644
index 000000000000..ae22029155d3
--- /dev/null
+++ b/documentation/docs/98-reference/30-compiler-errors.md
@@ -0,0 +1,5 @@
+---
+title: 'Compiler errors'
+---
+
+@include .generated/compile-errors.md
diff --git a/documentation/docs/98-reference/30-compiler-warnings.md b/documentation/docs/98-reference/30-compiler-warnings.md
new file mode 100644
index 000000000000..43ba71250f5b
--- /dev/null
+++ b/documentation/docs/98-reference/30-compiler-warnings.md
@@ -0,0 +1,21 @@
+---
+title: 'Compiler warnings'
+---
+
+Svelte warns you at compile time if it catches potential mistakes, such as writing inaccessible markup.
+
+Some warnings may be incorrect in your concrete use case. You can disable such false positives by placing a `` comment above the line that causes the warning. Example:
+
+```svelte
+
+
+```
+
+You can list multiple rules in a single comment (separated by commas), and add an explanatory note (in parentheses) alongside them:
+
+```svelte
+
+
...
+```
+
+@include .generated/compile-warnings.md
diff --git a/documentation/docs/98-reference/30-runtime-errors.md b/documentation/docs/98-reference/30-runtime-errors.md
new file mode 100644
index 000000000000..43ce98958751
--- /dev/null
+++ b/documentation/docs/98-reference/30-runtime-errors.md
@@ -0,0 +1,15 @@
+---
+title: 'Runtime errors'
+---
+
+## Client errors
+
+@include .generated/client-errors.md
+
+## Server errors
+
+@include .generated/server-errors.md
+
+## Shared errors
+
+@include .generated/shared-errors.md
diff --git a/documentation/docs/98-reference/30-runtime-warnings.md b/documentation/docs/98-reference/30-runtime-warnings.md
new file mode 100644
index 000000000000..edc5890ac0fa
--- /dev/null
+++ b/documentation/docs/98-reference/30-runtime-warnings.md
@@ -0,0 +1,11 @@
+---
+title: 'Runtime warnings'
+---
+
+## Client warnings
+
+@include .generated/client-warnings.md
+
+## Shared warnings
+
+@include .generated/shared-warnings.md
diff --git a/documentation/docs/98-reference/index.md b/documentation/docs/98-reference/index.md
new file mode 100644
index 000000000000..b98302768eb0
--- /dev/null
+++ b/documentation/docs/98-reference/index.md
@@ -0,0 +1,3 @@
+---
+title: Reference
+---
diff --git a/documentation/docs/99-legacy/00-legacy-overview.md b/documentation/docs/99-legacy/00-legacy-overview.md
new file mode 100644
index 000000000000..638a77ec1a76
--- /dev/null
+++ b/documentation/docs/99-legacy/00-legacy-overview.md
@@ -0,0 +1,14 @@
+---
+title: Overview
+---
+
+Svelte 5 introduced some significant changes to Svelte's API, including [runes](what-are-runes), [snippets](snippet) and event attributes. As a result, some Svelte 3/4 features are deprecated (though supported for now, unless otherwise specified) and will eventually be removed. We recommend that you incrementally [migrate your existing code](v5-migration-guide).
+
+The following pages document these features for
+
+- people still using Svelte 3/4
+- people using Svelte 5, but with components that haven't yet been migrated
+
+Since Svelte 3/4 syntax still works in Svelte 5, we will distinguish between _legacy mode_ and _runes mode_. Once a component is in runes mode (which you can opt into by using runes, or by explicitly setting the `runes: true` compiler option), legacy mode features are no longer available.
+
+If you're exclusively interested in the Svelte 3/4 syntax, you can browse its documentation at [v4.svelte.dev](https://v4.svelte.dev).
diff --git a/documentation/docs/99-legacy/01-legacy-let.md b/documentation/docs/99-legacy/01-legacy-let.md
new file mode 100644
index 000000000000..0d1a0a72bf11
--- /dev/null
+++ b/documentation/docs/99-legacy/01-legacy-let.md
@@ -0,0 +1,34 @@
+---
+title: Reactive let/var declarations
+---
+
+In runes mode, reactive state is explicitly declared with the [`$state` rune]($state).
+
+In legacy mode, variables declared at the top level of a component are automatically considered _reactive_. Reassigning or mutating these variables (`count += 1` or `object.x = y`) will cause the UI to update.
+
+```svelte
+
+
+ count += 1}>
+ clicks: {count}
+
+```
+
+Because Svelte's legacy mode reactivity is based on _assignments_, using array methods like `.push()` and `.splice()` won't automatically trigger updates. A subsequent assignment is required to 'tell' the compiler to update the UI:
+
+```svelte
+
+```
diff --git a/documentation/docs/99-legacy/02-legacy-reactive-assignments.md b/documentation/docs/99-legacy/02-legacy-reactive-assignments.md
new file mode 100644
index 000000000000..5abd481bfc74
--- /dev/null
+++ b/documentation/docs/99-legacy/02-legacy-reactive-assignments.md
@@ -0,0 +1,87 @@
+---
+title: Reactive $: statements
+---
+
+In runes mode, reactions to state updates are handled with the [`$derived`]($derived) and [`$effect`]($effect) runes.
+
+In legacy mode, any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with a `$:` [label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). These statements run after other code in the `
+```
+
+Statements are ordered _topologically_ by their dependencies and their assignments: since the `console.log` statement depends on `sum`, `sum` is calculated first even though it appears later in the source.
+
+Multiple statements can be combined by putting them in a block:
+
+```js
+// @noErrors
+$: {
+ // recalculate `total` when `items` changes
+ total = 0;
+
+ for (const item of items) {
+ total += item.value;
+ }
+}
+```
+
+The left-hand side of a reactive assignments can be an identifier, or it can be a destructuring assignment:
+
+```js
+// @noErrors
+$: ({ larry, moe, curly } = stooges);
+```
+
+## Understanding dependencies
+
+The dependencies of a `$:` statement are determined at compile time — they are whichever variables are referenced (but not assigned to) inside the statement.
+
+In other words, a statement like this will _not_ re-run when `count` changes, because the compiler cannot 'see' the dependency:
+
+```js
+// @noErrors
+let count = 0;
+let double = () => count * 2;
+
+$: doubled = double();
+```
+
+Similarly, topological ordering will fail if dependencies are referenced indirectly: `z` will never update, because `y` is not considered 'dirty' when the update occurs. Moving `$: z = y` below `$: setY(x)` will fix it:
+
+```svelte
+
+```
+
+## Browser-only code
+
+Reactive statements run during server-side rendering as well as in the browser. This means that any code that should only run in the browser must be wrapped in an `if` block:
+
+```js
+// @noErrors
+$: if (browser) {
+ document.title = title;
+}
+```
diff --git a/documentation/docs/99-legacy/03-legacy-export-let.md b/documentation/docs/99-legacy/03-legacy-export-let.md
new file mode 100644
index 000000000000..877e105b1fa2
--- /dev/null
+++ b/documentation/docs/99-legacy/03-legacy-export-let.md
@@ -0,0 +1,72 @@
+---
+title: export let
+---
+
+In runes mode, [component props](basic-markup#Component-props) are declared with the [`$props`]($props) rune, allowing parent components to pass in data.
+
+In legacy mode, props are marked with the `export` keyword, and can have a default value:
+
+```svelte
+
+```
+
+The default value is used if it would otherwise be `undefined` when the component is created.
+
+> [!NOTE] Unlike in runes mode, if the parent component changes a prop from a defined value to `undefined`, it does not revert to the initial value.
+
+Props without default values are considered _required_, and Svelte will print a warning during development if no value is provided, which you can squelch by specifying `undefined` as the default value:
+
+```js
+export let foo +++= undefined;+++
+```
+
+## Component exports
+
+An exported `const`, `class` or `function` declaration is _not_ considered a prop — instead, it becomes part of the component's API:
+
+```svelte
+
+
+```
+
+```svelte
+
+
+
+
+
+ greeter.greet('world')}>
+ greet
+
+```
+
+## Renaming props
+
+The `export` keyword can appear separately from the declaration. This is useful for renaming props, for example in the case of a reserved word:
+
+```svelte
+
+
+```
diff --git a/documentation/docs/99-legacy/04-legacy-$$props-and-$$restProps.md b/documentation/docs/99-legacy/04-legacy-$$props-and-$$restProps.md
new file mode 100644
index 000000000000..33cac97035af
--- /dev/null
+++ b/documentation/docs/99-legacy/04-legacy-$$props-and-$$restProps.md
@@ -0,0 +1,30 @@
+---
+title: $$props and $$restProps
+---
+
+In runes mode, getting an object containing all the props that were passed in is easy, using the [`$props`]($props) rune.
+
+In legacy mode, we use `$$props` and `$$restProps`:
+
+- `$$props` contains all the props that were passed in, including ones that are not individually declared with the `export` keyword
+- `$$restProps` contains all the props that were passed in _except_ the ones that were individually declared
+
+For example, a `` component might need to pass along all its props to its own `` element, except the `variant` prop:
+
+```svelte
+
+
+
+ click me
+
+
+
+```
+
+In Svelte 3/4 using `$$props` and `$$restProps` creates a modest performance penalty, so they should only be used when needed.
diff --git a/documentation/docs/99-legacy/10-legacy-on.md b/documentation/docs/99-legacy/10-legacy-on.md
new file mode 100644
index 000000000000..f2ee694cc1e0
--- /dev/null
+++ b/documentation/docs/99-legacy/10-legacy-on.md
@@ -0,0 +1,136 @@
+---
+title: on:
+---
+
+In runes mode, event handlers are just like any other attribute or prop.
+
+In legacy mode, we use the `on:` directive:
+
+```svelte
+
+
+
+
+ count: {count}
+
+```
+
+Handlers can be declared inline with no performance penalty:
+
+```svelte
+ (count += 1)}>
+ count: {count}
+
+```
+
+Add _modifiers_ to element event handlers with the `|` character.
+
+```svelte
+
+```
+
+The following modifiers are available:
+
+- `preventDefault` — calls `event.preventDefault()` before running the handler
+- `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
+- `stopImmediatePropagation` - calls `event.stopImmediatePropagation()`, preventing other listeners of the same event from being fired.
+- `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
+- `nonpassive` — explicitly set `passive: false`
+- `capture` — fires the handler during the _capture_ phase instead of the _bubbling_ phase
+- `once` — remove the handler after the first time it runs
+- `self` — only trigger handler if `event.target` is the element itself
+- `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={...}`.
+
+If the `on:` directive is used without a value, the component will _forward_ the event, meaning that a consumer of the component can listen for it.
+
+```svelte
+
+ The component itself will emit the click event
+
+```
+
+It's possible to have multiple event listeners for the same event:
+
+```svelte
+
+
+
+
+ clicks: {count}
+
+```
+
+## Component events
+
+Components can dispatch events by creating a _dispatcher_ when they are initialised:
+
+```svelte
+
+
+
+ dispatch('decrement')}>decrement
+ dispatch('increment')}>increment
+```
+
+`dispatch` creates a [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). If a second argument is provided, it becomes the `detail` property of the event object.
+
+A consumer of this component can listen for the dispatched events:
+
+```svelte
+
+
+ n -= 1}
+ on:increment={() => n += 1}
+/>
+
+
n: {n}
+```
+
+Component events do not bubble — a parent component can only listen for events on its immediate children.
+
+Other than `once`, modifiers are not valid on component event handlers.
+
+> [!NOTE]
+> If you're planning an eventual migration to Svelte 5, use callback props instead. This will make upgrading easier as `createEventDispatcher` is deprecated:
+>
+> ```svelte
+>
+>
+>
+> decrement
+> increment
+> ```
diff --git a/documentation/docs/99-legacy/20-legacy-slots.md b/documentation/docs/99-legacy/20-legacy-slots.md
new file mode 100644
index 000000000000..3474782e93ae
--- /dev/null
+++ b/documentation/docs/99-legacy/20-legacy-slots.md
@@ -0,0 +1,122 @@
+---
+title:
+---
+
+In Svelte 5, content can be passed to components in the form of [snippets](snippet) and rendered using [render tags](@render).
+
+In legacy mode, content inside component tags is considered _slotted content_, which can be rendered by the component using a `` element:
+
+```svelte
+
+
+
+This is some slotted content
+```
+
+```svelte
+
+
+
+
+```
+
+> [!NOTE] If you want to render a regular `` element, you can use ``.
+
+## Named slots
+
+A component can have _named_ slots in addition to the default slot. On the parent side, add a `slot="..."` attribute to an element, component or [``](legacy-svelte-fragment) directly inside the component tags.
+
+```svelte
+
+
+
+{#if open}
+
+ This is some slotted content
+
+ +++
+++
+ open = false}>
+ close
+
+ +++
+++
+
+{/if}
+```
+
+On the child side, add a corresponding `` element:
+
+```svelte
+
+
+
+
+ ++++++
+
+```
+
+## Fallback content
+
+If no slotted content is provided, a component can define fallback content by putting it inside the `` element:
+
+```svelte
+
+ This will be rendered if no slotted content is provided
+
+```
+
+## Passing data to slotted content
+
+Slots can be rendered zero or more times and can pass values _back_ to the parent using props. The parent exposes the values to the slot template using the `let:` directive.
+
+```svelte
+
+
+ {#each items as data}
+
+
+
+
+ {/each}
+
+```
+
+```svelte
+
+
+
+
{processed.text}
+
+```
+
+The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `` is equivalent to ``.
+
+Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute.
+
+```svelte
+
+
+ {#each items as item}
+
+
+
+ {/each}
+
+
+
+```
+
+```svelte
+
+
+
{item.text}
+
Copyright (c) 2019 Svelte Industries
+
+```
+
+
diff --git a/documentation/docs/99-legacy/21-legacy-$$slots.md b/documentation/docs/99-legacy/21-legacy-$$slots.md
new file mode 100644
index 000000000000..7ca1cef8445a
--- /dev/null
+++ b/documentation/docs/99-legacy/21-legacy-$$slots.md
@@ -0,0 +1,27 @@
+---
+title: $$slots
+---
+
+In runes mode, we know which [snippets](snippet) were provided to a component, as they're just normal props.
+
+In legacy mode, the way to know if content was provided for a given slot is with the `$$slots` object, whose keys are the names of the slots passed into the component by the parent.
+
+```svelte
+
+
+
+ {#if $$slots.description}
+
+
+
+ {/if}
+
+```
+
+```svelte
+
+
+
Blog Post Title
+
+
+```
diff --git a/documentation/docs/99-legacy/22-legacy-svelte-fragment.md b/documentation/docs/99-legacy/22-legacy-svelte-fragment.md
new file mode 100644
index 000000000000..779931f94753
--- /dev/null
+++ b/documentation/docs/99-legacy/22-legacy-svelte-fragment.md
@@ -0,0 +1,32 @@
+---
+title:
+---
+
+The `` element allows you to place content in a [named slot](legacy-slots) without wrapping it in a container DOM element. This keeps the flow layout of your document intact.
+
+```svelte
+
+
+ No header was provided
+
Some content between header and footer
+
+
+```
+
+```svelte
+
+
+
+
+
Hello
+
+
All rights reserved.
+
Copyright (c) 2019 Svelte Industries
+
+
+```
+
+> [!NOTE]
+> In Svelte 5+, this concept is obsolete, as snippets don't create a wrapping element
diff --git a/documentation/docs/99-legacy/30-legacy-svelte-component.md b/documentation/docs/99-legacy/30-legacy-svelte-component.md
new file mode 100644
index 000000000000..a0407e58bfbf
--- /dev/null
+++ b/documentation/docs/99-legacy/30-legacy-svelte-component.md
@@ -0,0 +1,13 @@
+---
+title:
+---
+
+In runes mode, `` will re-render if the value of `MyComponent` changes. See the [Svelte 5 migration guide](/docs/svelte/v5-migration-guide#svelte:component-is-no-longer-necessary) for an example.
+
+In legacy mode, it won't — we must use ``, which destroys and recreates the component instance when the value of its `this` expression changes:
+
+```svelte
+
+```
+
+If `this` is falsy, no component is rendered.
diff --git a/documentation/docs/99-legacy/31-legacy-svelte-self.md b/documentation/docs/99-legacy/31-legacy-svelte-self.md
new file mode 100644
index 000000000000..bfd140ac49dc
--- /dev/null
+++ b/documentation/docs/99-legacy/31-legacy-svelte-self.md
@@ -0,0 +1,37 @@
+---
+title:
+---
+
+The `` element allows a component to include itself, recursively.
+
+It cannot appear at the top level of your markup; it must be inside an if or each block or passed to a component's slot to prevent an infinite loop.
+
+```svelte
+
+
+{#if count > 0}
+
counting down... {count}
+
+{:else}
+
lift-off!
+{/if}
+```
+
+> [!NOTE]
+> This concept is obsolete, as components can import themselves:
+> ```svelte
+>
+>
+>
+> {#if count > 0}
+>
counting down... {count}
+>
+> {:else}
+>
lift-off!
+> {/if}
+> ```
diff --git a/documentation/docs/99-legacy/40-legacy-component-api.md b/documentation/docs/99-legacy/40-legacy-component-api.md
new file mode 100644
index 000000000000..a08f53951c20
--- /dev/null
+++ b/documentation/docs/99-legacy/40-legacy-component-api.md
@@ -0,0 +1,200 @@
+---
+title: Imperative component API
+---
+
+In Svelte 3 and 4, the API for interacting with a component is different than in Svelte 5. Note that this page does _not_ apply to legacy mode components in a Svelte 5 application.
+
+## Creating a component
+
+```ts
+// @noErrors
+const component = new Component(options);
+```
+
+A client-side component — that is, a component compiled with `generate: 'dom'` (or the `generate` option left unspecified) is a JavaScript class.
+
+```ts
+// @noErrors
+import App from './App.svelte';
+
+const app = new App({
+ target: document.body,
+ props: {
+ // assuming App.svelte contains something like
+ // `export let answer`:
+ answer: 42
+ }
+});
+```
+
+The following initialisation options can be provided:
+
+| option | default | description |
+| --------- | ----------- | ---------------------------------------------------------------------------------------------------- |
+| `target` | **none** | An `HTMLElement` or `ShadowRoot` to render to. This option is required |
+| `anchor` | `null` | A child of `target` to render the component immediately before |
+| `props` | `{}` | An object of properties to supply to the component |
+| `context` | `new Map()` | A `Map` of root-level context key-value pairs to supply to the component |
+| `hydrate` | `false` | See below |
+| `intro` | `false` | If `true`, will play transitions on initial render, rather than waiting for subsequent state changes |
+
+Existing children of `target` are left where they are.
+
+The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](/docs/svelte-compiler#compile). Hydration of `` elements only works properly if the server-side rendering code was also compiled with `hydratable: true`, which adds a marker to each element in the `` so that the component knows which elements it's responsible for removing during hydration.
+
+Whereas children of `target` are normally left alone, `hydrate: true` will cause any children to be removed. For that reason, the `anchor` option cannot be used alongside `hydrate: true`.
+
+The existing DOM doesn't need to match the component — Svelte will 'repair' the DOM as it goes.
+
+```ts
+/// file: index.js
+// @noErrors
+import App from './App.svelte';
+
+const app = new App({
+ target: document.querySelector('#server-rendered-html'),
+ hydrate: true
+});
+```
+
+> [!NOTE]
+> In Svelte 5+, use [`mount`](svelte#mount) instead
+
+## `$set`
+
+```ts
+// @noErrors
+component.$set(props);
+```
+
+Programmatically sets props on an instance. `component.$set({ x: 1 })` is equivalent to `x = 1` inside the component's `'` 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))
+- Don't remove ` ` incorrectly ([#348](https://github.com/sveltejs/svelte/issues/348))
+- `let` -> `var` in `addCss` block ([#351](https://github.com/sveltejs/svelte/pull/351))
+
+## 1.10.2
+
+- Accept any case for doctype declarations ([#336](https://github.com/sveltejs/svelte/issues/336))
+- Allow non-top-level `
+
+ count++}>{count}
+
+
{count} is even: {even}
+
{count} is odd: {odd}
+```
+
+This is forbidden because it introduces instability: if `
{count} is even: {even}
` is updated before `odd` is recalculated, `even` will be stale. In most cases the solution is to make everything derived:
+
+```js
+let count = 0;
+// ---cut---
+let even = $derived(count % 2 === 0);
+let odd = $derived(!even);
+```
+
+If side-effects are unavoidable, use [`$effect`]($effect) instead.
diff --git a/packages/svelte/messages/client-warnings/warnings.md b/packages/svelte/messages/client-warnings/warnings.md
new file mode 100644
index 000000000000..f8e9ebd8a047
--- /dev/null
+++ b/packages/svelte/messages/client-warnings/warnings.md
@@ -0,0 +1,196 @@
+## assignment_value_stale
+
+> Assignment to `%property%` property (%location%) will evaluate to the right-hand side, not the value of `%property%` following the assignment. This may result in unexpected behaviour.
+
+Given a case like this...
+
+```svelte
+
+
+add
+
items: {JSON.stringify(object.items)}
+```
+
+...the array being pushed to when the button is first clicked is the `[]` on the right-hand side of the assignment, but the resulting value of `object.array` is an empty state proxy. As a result, the pushed value will be discarded.
+
+You can fix this by separating it into two statements:
+
+```js
+let object = { array: [0] };
+// ---cut---
+function add() {
+ object.array ??= [];
+ object.array.push(object.array.length);
+}
+```
+
+## binding_property_non_reactive
+
+> `%binding%` is binding to a non-reactive property
+
+> `%binding%` (%location%) is binding to a non-reactive property
+
+## console_log_state
+
+> Your `console.%method%` contained `$state` proxies. Consider using `$inspect(...)` or `$state.snapshot(...)` instead
+
+When logging a [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), browser devtools will log the proxy itself rather than the value it represents. In the case of Svelte, the 'target' of a `$state` proxy might not resemble its current value, which can be confusing.
+
+The easiest way to log a value as it changes over time is to use the [`$inspect`](/docs/svelte/$inspect) rune. Alternatively, to log things on a one-off basis (for example, inside an event handler) you can use [`$state.snapshot`](/docs/svelte/$state#$state.snapshot) to take a snapshot of the current value.
+
+## event_handler_invalid
+
+> %handler% should be a function. Did you mean to %suggestion%?
+
+## hydration_attribute_changed
+
+> The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value
+
+Certain attributes like `src` on an `` element will not be repaired during hydration, i.e. the server value will be kept. That's because updating these attributes can cause the image to be refetched (or in the case of an `