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 ed2a319d5843..2f52d9993f71 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,6 +11,5 @@ trim_trailing_whitespace = true
[test/**/expected.css]
insert_final_newline = false
-[{package.json,.travis.yml,.eslintrc.json}]
+[package.json]
indent_style = space
-indent_size = 2
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index a0ca1e55c847..000000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,14 +0,0 @@
-**/_actual.js
-**/expected.js
-test/*/samples/*/output.js
-node_modules
-
-# output files
-animate/*.js
-esing/*.js
-internal/*.js
-motion/*.js
-store/*.js
-transition/*.js
-index.js
-compiler.js
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 722b0e906749..000000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,80 +0,0 @@
-{
- "root": true,
- "rules": {
- "indent": "off",
- "no-unused-vars": "off",
- "semi": [2, "always"],
- "keyword-spacing": [2, { "before": true, "after": true }],
- "space-before-blocks": [2, "always"],
- "no-mixed-spaces-and-tabs": [2, "smart-tabs"],
- "no-cond-assign": 0,
- "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,
- "require-atomic-updates": "off",
- "@typescript-eslint/indent": ["error", "tab", {
- "SwitchCase": 1,
- "ignoredNodes": ["TemplateLiteral"]
- }],
- "@typescript-eslint/camelcase": "off",
- "@typescript-eslint/no-use-before-define": "off",
- "@typescript-eslint/array-type": ["error", "array-simple"],
- "@typescript-eslint/explicit-function-return-type": "off",
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/explicit-member-accessibility": "off",
- "@typescript-eslint/no-unused-vars": ["error", {
- "argsIgnorePattern": "^_"
- }],
- "@typescript-eslint/no-object-literal-type-assertion": ["error", {
- "allowAsParameter": true
- }],
- "@typescript-eslint/no-unused-vars": "off"
- },
- "globals": {
- "globalThis": false
- },
- "env": {
- "es6": true,
- "browser": true,
- "node": true,
- "mocha": true
- },
- "extends": [
- "eslint:recommended",
- "plugin:import/errors",
- "plugin:import/warnings",
- "plugin:import/typescript",
- "plugin:@typescript-eslint/recommended"
- ],
- "parserOptions": {
- "ecmaVersion": 9,
- "sourceType": "module"
- },
- "settings": {
- "import/core-modules": [
- "svelte",
- "svelte/internal",
- "svelte/store",
- "svelte/easing",
- "estree"
- ]
- },
- "overrides": [
- {
- "files": ["*.js"],
- "rules": {
- "@typescript-eslint/no-var-requires": "off"
- }
- }
- ]
-}
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 e7bd60d3f410..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..90d219faae6a
--- /dev/null
+++ b/.github/workflows/pkg.pr.new.yml
@@ -0,0 +1,47 @@
+name: Publish Any Commit
+on: [push, pull_request]
+
+jobs:
+ build:
+ permissions: {}
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: install corepack
+ run: npm i -g corepack@0.31.0
+
+ - run: corepack enable
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 18.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 590bd1d88e01..d50343766485 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,35 +1,26 @@
+# Dependency directories
+node_modules/
+
+# IDE related
.idea
+
+# Test coverage
+coverage
+*.lcov
+
+# Optional eslint cache
+.eslintcache
+
+# dotenv environment variables file
+.env
+.env.test
+
+# build output
+.vercel
+
+# OS-specific
.DS_Store
-.nyc_output
-node_modules
-*.map
-/src/compiler/compile/internal_exports.ts
-/compiler.d.ts
-/compiler.*js
-/index.*js
-/internal
-/store
-/easing
-/motion
-/transition
-/animate
-/scratch/
-/coverage/
-/coverage.lcov/
-/test/sourcemaps/samples/*/output.js
-/test/sourcemaps/samples/*/output.js.map
-/test/sourcemaps/samples/*/output.css
-/test/sourcemaps/samples/*/output.css.map
-/yarn-error.log
-_actual*.*
-/types
-
-/site/cypress/screenshots/
-/site/__sapper__/
-/site/.env
-/site/.sessions
-/site/static/svelte-app.json
-/site/static/contributors.jpg
-/site/static/workers
-/site/scripts/svelte-app
-/site/src/routes/_contributors.js
+
+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
index 81451039faf5..c4fd5d9f2f73 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,3 +1,28 @@
-useTabs: true
-singleQuote: true
-trailingComma: es5
+{
+ "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 a4603a26e2cc..000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-language: node_js
-node_js:
- - "8"
- - "10"
- - "12"
-env:
- global:
- - BUILD_TIMEOUT=20000
-
-addons:
- apt:
- packages:
- - xvfb
-
-install:
- - export DISPLAY=':99.0'
- - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- - npm ci || 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 340ef8c17633..000000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,1568 +0,0 @@
-# Svelte changelog
-
-## 3.6.4
-
-* Run `onMount` functions in correct order, and before initial `afterUpdate` functions ([#2281](https://github.com/sveltejs/svelte/issues/2281))
-* Fix code transformation for shorthand methods ([#2906](https://github.com/sveltejs/svelte/issues/2906))
-* Fix assignments in inline functions ([#3038](https://github.com/sveltejs/svelte/issues/3038))
-
-## 3.6.3
-
-* Fix await block mounting inside removed if block ([#1496](https://github.com/sveltejs/svelte/issues/1496))
-* Update when element references are removed ([#2034](https://github.com/sveltejs/svelte/issues/2034))
-* Don't attempt to serialize non-string values in server-rendered bindings ([#2135](https://github.com/sveltejs/svelte/issues/2135))
-* Recognise dependencies in function expressions ([#2693](https://github.com/sveltejs/svelte/issues/2693))
-* Scope pseudo-class selectors without class/type ([#1705](https://github.com/sveltejs/svelte/issues/1705))
-* Allow nested at-rules ([#3135](https://github.com/sveltejs/svelte/issues/3135))
-* Allow attributes to contain `=` characters ([#3149](https://github.com/sveltejs/svelte/pull/3149))
-
-## 3.6.2
-
-* Fix placement of each-else block ([#2917](https://github.com/sveltejs/svelte/issues/2917))
-* Make context accessible to `bind:this` ([#2806](https://github.com/sveltejs/svelte/issues/2806))
-* Pass hoisted values to slots ([#2586](https://github.com/sveltejs/svelte/issues/2586))
-
-## 3.6.1
-
-* Fix escaping of `@` in dev mode debug filename ([#3114](https://github.com/sveltejs/svelte/pull/3114))
-
-## 3.6.0
-
-* Add `innerHTML` and `textContent` bindings for `contenteditable` elements ([#2996](https://github.com/sveltejs/svelte/pull/2996))
-* Fix destructuring assignments where targets are member expressions ([#3092](https://github.com/sveltejs/svelte/issues/3092))
-* Deconflict with used globals ([#2963](https://github.com/sveltejs/svelte/pull/2963))
-* Always run `onDestroy` functions, not just for detaching components ([#3058](https://github.com/sveltejs/svelte/issues/3058))
-* Fix scope analysis around catch clauses ([#3064](https://github.com/sveltejs/svelte/issues/3064))
-* Add error constructors to known globals ([#3064](https://github.com/sveltejs/svelte/issues/3064))
-* Always bail out of hoisting on encountering local state in function definition ([#3044](https://github.com/sveltejs/svelte/issues/3044))
-* Fix incorrect merging of top-level text nodes ([#3027](https://github.com/sveltejs/svelte/issues/3027))
-* Handle removal of components in each blocks without props ([#3035](https://github.com/sveltejs/svelte/issues/3035))
-* Only call subscriber once when resubscribing to a store ([#3022](https://github.com/sveltejs/svelte/issues/3022))
-* Check for existence of dynamic component before introing ([#3054](https://github.com/sveltejs/svelte/issues/3054))
-* Sanitize names of bubbled event handlers ([#2923](https://github.com/sveltejs/svelte/issues/2923))
-
-
-## 3.5.4
-
-* Preserve whitespace at the boundaries of `{#each}` blocks ([#713](https://github.com/sveltejs/svelte/issues/713))
-* Fix dynamic `bind:this` on components ([#2333](https://github.com/sveltejs/svelte/issues/2333))
-* Fix binding to values in a component when it uses `$$props` ([#2725](https://github.com/sveltejs/svelte/issues/2725))
-* Fix parsing ambiguous HTML entities ([#3071](https://github.com/sveltejs/svelte/pull/3071))
-
-## 3.5.3
-
-* Don't double-destroy keyed each blocks with outros ([#3055](https://github.com/sveltejs/svelte/issues/3055))
-
-## 3.5.2
-
-* Prevent duplicated outros causing errors ([#3001](https://github.com/sveltejs/svelte/issues/3001))
-* Fix automatic name generation ([#2843](https://github.com/sveltejs/svelte/issues/2843))
-* Fix .d.ts stubs ([#3009](https://github.com/sveltejs/svelte/pull/3009))
-* Don't strip non-breaking spaces ([#3014](https://github.com/sveltejs/svelte/issues/3014))
-* Fix `requestAnimationFrame` context ([#2933](https://github.com/sveltejs/svelte/issues/2933))
-* Allow space before attribute value ([#3026](https://github.com/sveltejs/svelte/issues/3026))
-* Remove null/undefined attributes ([#1434](https://github.com/sveltejs/svelte/issues/1434))
-* Fix whitespace in static markup ([#3030](https://github.com/sveltejs/svelte/pull/3030))
-
-## 3.5.1
-
-* Accommodate webpack idiosyncracies
-
-## 3.5.0
-
-* Update package folder structure ([#2887](https://github.com/sveltejs/svelte/pull/2887))
-* Support `once` modifier on component events ([#2654](https://github.com/sveltejs/svelte/issues/2654))
-* Allow empty `
` tags ([#2980](https://github.com/sveltejs/svelte/issues/2980))
-* Render textarea binding values inside element ([#2975](https://github.com/sveltejs/svelte/pull/2975))
-* Fix delayed animation glitch ([#2871](https://github.com/sveltejs/svelte/issues/2871))
-* Solve diamond dependencies problem with stores ([#2660](https://github.com/sveltejs/svelte/issues/2660))
-* Fix missing outros inside each blocks ([#2689](https://github.com/sveltejs/svelte/issues/2689))
-* Support animations without transitions ([#2908](https://github.com/sveltejs/svelte/issues/2908))
-* Add missing transition events ([#2912](https://github.com/sveltejs/svelte/pull/2912))
-
-
-## 3.4.4
-
-* Publish type declaration files ([#2874](https://github.com/sveltejs/svelte/issues/2874))
-* Don't trigger updates for unreferenced values ([#2865](https://github.com/sveltejs/svelte/pull/2865))
-* Omit readonly bindings from SSR output ([#2339](https://github.com/sveltejs/svelte/issues/2339))
-* Prevent outdated animation CSS ([#2871](https://github.com/sveltejs/svelte/issues/2871))
-* Repair dynamic `{@html ...}` in head ([#2880](https://github.com/sveltejs/svelte/pull/2880))
-* Don't create unknown prop warnings for internal props, or if component has `$$props` ([#2881](https://github.com/sveltejs/svelte/pull/2881))
-
-
-## 3.4.3
-
-* Add type declaration files for everything ([#2842](https://github.com/sveltejs/svelte/pull/2842))
-* Prevent `svelte/store` being bundled ([#2786](https://github.com/sveltejs/svelte/issues/2786))
-* Warn on unknown props in dev mode ([#2840](https://github.com/sveltejs/svelte/pull/2840))
-* Treat `requestAnimationFrame` as a no-op on the server ([#2856](https://github.com/sveltejs/svelte/pull/2856))
-* Add `raw` property to AST's `Text` nodes ([#2714](https://github.com/sveltejs/svelte/issues/2714))
-* Add `` ([#2854](https://github.com/sveltejs/svelte/issues/2854))
-
-## 3.4.2
-
-* Use empty string for empty data attributes ([#2804](https://github.com/sveltejs/svelte/pull/2804))
-* Support `customElement: true` with no `` ([#2821](https://github.com/sveltejs/svelte/issues/2821))
-* Add docstrings to `svelte/store` ([#2795](https://github.com/sveltejs/svelte/pull/2795))
-
-## 3.4.1
-
-* Handle non-falsy non-function return values from derivers ([#2780](https://github.com/sveltejs/svelte/issues/2780))
-* Allow `spring` to work server-side ([#2773](https://github.com/sveltejs/svelte/issues/2773))
-
-## 3.4.0
-
-* Allow custom element to be defined without a `tag` ([#2417](https://github.com/sveltejs/svelte/issues/2417))
-* Fix parsing of quote marks inside attribute values ([#2715](https://github.com/sveltejs/svelte/pull/2754))
-* Convert `svelte/store` to TypeScript ([#2733](https://github.com/sveltejs/svelte/pull/2733))
-* Allow `debug` tags to include hoisted values ([#2764](https://github.com/sveltejs/svelte/issues/2764))
-* Parse error if attribute name is missing `=` ([#1513](https://github.com/sveltejs/svelte/pull/2770))
-* Allow reactive declarations to depend on mutated `const` values ([#2728](https://github.com/sveltejs/svelte/issues/2728))
-
-## 3.3.0
-
-* Allow multiple event listeners on a single node ([#2688](https://github.com/sveltejs/svelte/issues/2688))
-* Allow derivers to return a cleanup function ([#2553](https://github.com/sveltejs/svelte/issues/2553))
-* Support namespaced components (``) ([#2743](https://github.com/sveltejs/svelte/pull/2743))
-
-## 3.2.2
-
-* Add `window` and `document` to expected globals ([#2722](https://github.com/sveltejs/svelte/pull/2722))
-* Prevent hoisting of functions that depend on reactive state ([#2703](https://github.com/sveltejs/svelte/pull/2703))
-* Generate correct code when slot has no changes ([#2697](https://github.com/sveltejs/svelte/issues/2697))
-* Prevent `Object.prototype`-related bugs ([#2696](https://github.com/sveltejs/svelte/pull/2696))
-
-## 3.2.1
-
-* Use same comparison logic for `derived` as for other stores ([#2644](https://github.com/sveltejs/svelte/issues/2644))
-* Invalidate dependencies of reactive declarations ([#2444](https://github.com/sveltejs/svelte/issues/2444))
-* Fix instrumentation of auto-subscription self-assignments ([#2681](https://github.com/sveltejs/svelte/issues/2681))
-* Warn on non-top-level or module-context statements labeled with `$:` ([#2176](https://github.com/sveltejs/svelte/issues/2176))
-
-## 3.2.0
-
-* Improve `spring` animations, and add `hard`/`soft` options ([#2627](https://github.com/sveltejs/svelte/pull/2627))
-* Expose `parse` and `walk` functions ([#2661](https://github.com/sveltejs/svelte/issues/2661), [#2534](https://github.com/sveltejs/svelte/pull/2534))
-* Support array/object rest in `each` block destructuring patterns ([#2647](https://github.com/sveltejs/svelte/issues/2647), [#2658](https://github.com/sveltejs/svelte/pull/2658))
-* Use `setAttribute` to change `form` property on form elements ([#1742](https://github.com/sveltejs/svelte/issues/1742))
-* Fix a11y warning when `` is non-direct descendant of `
` ([#2582](https://github.com/sveltejs/svelte/issues/2582))
-* Squelch erroneous 'empty block' warnings ([#1716](https://github.com/sveltejs/svelte/issues/1716))
-* Fix IE9/10 error with `insertBefore` ([#2573](https://github.com/sveltejs/svelte/issues/2573))
-* Prevent `$$scope` from being spread onto an element ([#2520](https://github.com/sveltejs/svelte/issues/2520))
-* Resubscribe to stores that are assigned to in `'` 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 `
+```
+
+You can specify a fallback value for a prop. It will be used if the component's consumer doesn't specify the prop on the component when instantiating the component, or if the passed value is `undefined` at some point.
+
+```svelte
+
+```
+
+To get all properties, use rest syntax:
+
+```svelte
+
+```
+
+You can use reserved words as prop names.
+
+```svelte
+
+```
+
+If you're using TypeScript, you can declare the prop types:
+
+```svelte
+
+```
+
+If you're using JavaScript, you can declare the prop types using JSDoc:
+
+```svelte
+
+```
+
+If you export a `const`, `class` or `function`, it is readonly from outside the component.
+
+```svelte
+
+```
+
+Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](bindings#bind:this).
+
+### Reactive variables
+
+To change component state and trigger a re-render, just assign to a locally declared variable that was declared using the `$state` rune.
+
+Update expressions (`count += 1`) and property assignments (`obj.x = y`) have the same effect.
+
+```svelte
+
+```
+
+Svelte's `
+```
+
+If you'd like to react to changes to a prop, use the `$derived` or `$effect` runes instead.
+
+```svelte
+
+```
+
+For more information on reactivity, read the documentation around runes.
diff --git a/documentation/docs/01-introduction/xx-reactivity-fundamentals.md b/documentation/docs/01-introduction/xx-reactivity-fundamentals.md
new file mode 100644
index 000000000000..d5e67ada71c8
--- /dev/null
+++ b/documentation/docs/01-introduction/xx-reactivity-fundamentals.md
@@ -0,0 +1,144 @@
+---
+title: Reactivity fundamentals
+---
+
+Reactivity is at the heart of interactive UIs. When you click a button, you expect some kind of response. It's your job as a developer to make this happen. It's Svelte's job to make your job as intuitive as possible, by providing a good API to express reactive systems.
+
+## Runes
+
+Svelte 5 uses _runes_, a powerful set of primitives for controlling reactivity inside your Svelte components and inside `.svelte.js` and `.svelte.ts` modules.
+
+Runes are function-like symbols that provide instructions to the Svelte compiler. You don't need to import them from anywhere — when you use Svelte, they're part of the language.
+
+The following sections introduce the most important runes for declare state, derived state and side effects at a high level. For more details refer to the later sections on [state](state) and [side effects](side-effects).
+
+## `$state`
+
+Reactive state is declared with the `$state` rune:
+
+```svelte
+
+
+
+```
+
+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;
+ }
+}
+```
+
+> [!LEGACY]
+> In Svelte 4, state was implicitly reactive if the variable was declared at the top level
+>
+> ```svelte
+>
+>
+>
+> ```
+
+## `$derived`
+
+Derived state is declared with the `$derived` rune:
+
+```svelte
+
+
+
+
+
{count} doubled is {doubled}
+```
+
+The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions.
+
+As with `$state`, you can mark class fields as `$derived`.
+
+> [!LEGACY]
+> In Svelte 4, you could use reactive statements for this.
+>
+> ```svelte
+>
+>
+>
+>
+>
{count} doubled is {doubled}
+> ```
+>
+> This only worked at the top level of a component.
+
+## `$effect`
+
+To run _side-effects_ when the component is mounted to the DOM, and when values change, we can use the `$effect` rune ([demo](/playground/untitled#H4sIAAAAAAAAE31T24rbMBD9lUG7kAQ2sbdlX7xOYNk_aB_rQhRpbAsU2UiTW0P-vbrYubSlYGzmzMzROTPymdVKo2PFjzMzfIusYB99z14YnfoQuD1qQh-7bmdFQEonrOppVZmKNBI49QthCc-OOOH0LZ-9jxnR6c7eUpOnuv6KeT5JFdcqbvbcBcgDz1jXKGg6ncFyBedYR6IzLrAZwiN5vtSxaJA-EzadfJEjKw11C6GR22-BLH8B_wxdByWpvUYtqqal2XB6RVkG1CoHB6U1WJzbnYFDiwb3aGEdDa3Bm1oH12sQLTcNPp7r56m_00mHocSG97_zd7ICUXonA5fwKbPbkE2ZtMJGGVkEdctzQi4QzSwr9prnFYNk5hpmqVuqPQjNnfOJoMF22lUsrq_UfIN6lfSVyvQ7grB3X2mjMZYO3XO9w-U5iLx42qg29md3BP_ni5P4gy9ikTBlHxjLzAtPDlyYZmRdjAbGq7HprEQ7p64v4LU_guu0kvAkhBim3nMplWl8FreQD-CW20aZR0wq12t-KqDWeBywhvexKC3memmDwlHAv9q4Vo2ZK8KtK0CgX7u9J8wXbzdKv-nRnfF_2baTqlYoWUF2h5efl9-n0O6koAMAAA==)):
+
+```svelte
+
+
+
+```
+
+The function passed to `$effect` will run when the component mounts, and will re-run after any changes to the values it reads that were declared with `$state` or `$derived` (including those passed in with `$props`). Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied.
+
+> [!LEGACY]
+> In Svelte 4, you could use reactive statements for this.
+>
+> ```svelte
+>
+>
+>
+> ```
+>
+> This only worked at the top level of a component.
diff --git a/documentation/docs/02-runes/01-what-are-runes.md b/documentation/docs/02-runes/01-what-are-runes.md
new file mode 100644
index 000000000000..59c371eb4909
--- /dev/null
+++ b/documentation/docs/02-runes/01-what-are-runes.md
@@ -0,0 +1,24 @@
+---
+title: What are runes?
+---
+
+> [!NOTE] **rune** /ruːn/ _noun_
+>
+> A letter or mark used as a mystical or magic symbol.
+
+Runes are symbols that you use in `.svelte` and `.svelte.js`/`.svelte.ts` files to control the Svelte compiler. If you think of Svelte as a language, runes are part of the syntax — they are _keywords_.
+
+Runes have a `$` prefix and look like functions:
+
+```js
+let message = $state('hello');
+```
+
+They differ from normal JavaScript functions in important ways, however:
+
+- You don't need to import them — they are part of the language
+- They're not values — you can't assign them to a variable or pass them as arguments to a function
+- Just like JavaScript keywords, they are only valid in certain positions (the compiler will help you if you put them in the wrong place)
+
+> [!LEGACY]
+> Runes didn't exist prior to Svelte 5.
diff --git a/documentation/docs/02-runes/02-$state.md b/documentation/docs/02-runes/02-$state.md
new file mode 100644
index 000000000000..49e17cd08ff3
--- /dev/null
+++ b/documentation/docs/02-runes/02-$state.md
@@ -0,0 +1,252 @@
+---
+title: $state
+---
+
+The `$state` rune allows you to create _reactive state_, which means that your UI _reacts_ when it changes.
+
+```svelte
+
+
+
+```
+
+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 `