diff --git a/.changeset/config.json b/.changeset/config.json index 58e5f01c7d97..fc418611aeac 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -4,7 +4,7 @@ "commit": false, "linked": [], "access": "public", - "baseBranch": "master", + "baseBranch": "main", "bumpVersionsWithWorkspaceProtocolOnly": true, - "ignore": ["!(@sveltejs/*|create-svelte|svelte-migrate)"] + "ignore": ["!(@sveltejs/*|create-svelte)"] } diff --git a/.changeset/moody-baboons-drum.md b/.changeset/moody-baboons-drum.md new file mode 100644 index 000000000000..b224830500b6 --- /dev/null +++ b/.changeset/moody-baboons-drum.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-cloudflare': patch +--- + +fix: deprecate `platform.context` in favor of `platform.ctx` to align with Cloudflare's naming convention diff --git a/.changeset/spotty-ideas-clap.md b/.changeset/spotty-ideas-clap.md new file mode 100644 index 000000000000..38b3f28cd9c8 --- /dev/null +++ b/.changeset/spotty-ideas-clap.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-node': patch +--- + +fix: remove unnecessary static directory serving middleware diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 9501511a710b..000000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "root": true, - "extends": "@sveltejs", - "env": { - "es2022": true - }, - "ignorePatterns": [ - "packages/create-svelte/shared/", - "packages/kit/test/prerendering/*/build", - "packages/adapter-static/test/apps/*/build", - "packages/adapter-cloudflare/files", - "packages/adapter-netlify/files", - "packages/adapter-node/files" - ], - "rules": { - "no-undef": "off" - } -} diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b077e088fb94..3eaabfa5d71e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,7 @@ + + +--- + ### Please don't delete this checklist! Before submitting the PR, please make sure you do the following: - [ ] 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 - [ ] This message body should clearly illustrate what problems it solves. @@ -8,3 +12,7 @@ ### Changesets - [ ] If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpm changeset` and following the prompts. Changesets that add features should be `minor` and those that fix bugs should be `patch`. Please prefix changeset messages with `feat:`, `fix:`, or `chore:`. + +### Edits + +- [ ] Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed. diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 049ebc7508c9..121456fc6de4 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -13,13 +13,15 @@ permissions: jobs: Audit: + # prevents this action from running on forks + if: github.repository == 'sveltejs/kit' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2.4.0 - - uses: actions/setup-node@v3 + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '22.x' cache: pnpm - run: pnpm install --frozen-lockfile # check prod dependencies as these would affect users diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c6bd814714b..515930f7a528 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: CI on: push: branches: - - master + - main pull_request: env: @@ -19,87 +19,102 @@ permissions: contents: read # to fetch code (actions/checkout) jobs: - Lint: + pkg-pr-new: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2.4.0 - - uses: actions/setup-node@v3 + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm build + - run: pnpx pkg-pr-new publish --comment=off ./packages/* + lint-all: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4 + with: + node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm run lint - - run: cd packages/kit && pnpm prepublishOnly + - run: cd packages/kit && pnpm prepublishOnly && { [ "`git status --porcelain=v1`" == "" ] || (echo "Generated types have changed — please run prepublishOnly locally and commit the changes after you have reviewed them"; git diff; exit 1); } - run: pnpm run check - Tests: + test-kit: runs-on: ${{ matrix.os }} timeout-minutes: 30 strategy: fail-fast: false matrix: include: - - node-version: 16 - os: ubuntu-latest - e2e-browser: 'chromium' - node-version: 18 os: ubuntu-latest e2e-browser: 'chromium' - node-version: 20 os: ubuntu-latest e2e-browser: 'chromium' + - node-version: 22 + os: ubuntu-latest + e2e-browser: 'chromium' env: KIT_E2E_BROWSER: ${{matrix.e2e-browser}} steps: - run: git config --global core.autocrlf false - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2.4.0 - - uses: actions/setup-node@v3 + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm playwright install ${{ matrix.e2e-browser }} - - run: pnpm test + - run: pnpm run sync-all + - run: pnpm test:kit + - name: Print flaky test report + run: node scripts/print-flaky-test-report.js - name: Archive test results if: failure() shell: bash run: find packages -type d -name test-results -not -empty | tar -czf test-results.tar.gz --files-from=- - name: Upload test results if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: retention-days: 3 name: test-failure-${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.e2e-browser }} path: test-results.tar.gz - Cross-browser-test: + test-kit-cross-browser: runs-on: ${{ matrix.os }} timeout-minutes: 30 strategy: fail-fast: false matrix: include: - - node-version: 16 - os: windows-2019 # slowness reported on newer versions https://github.com/actions/runner-images/issues/5166 + - node-version: 18 + os: windows-latest e2e-browser: 'chromium' mode: 'dev' - - node-version: 16 + - node-version: 18 os: ubuntu-latest e2e-browser: 'firefox' mode: 'dev' - - node-version: 16 + - node-version: 18 os: macOS-latest e2e-browser: 'webkit' mode: 'dev' - - node-version: 16 - os: windows-2019 # slowness reported on newer versions https://github.com/actions/runner-images/issues/5166 + - node-version: 18 + os: windows-latest e2e-browser: 'chromium' mode: 'build' - - node-version: 16 + - node-version: 18 os: ubuntu-latest e2e-browser: 'firefox' mode: 'build' - - node-version: 16 + - node-version: 18 os: macOS-latest e2e-browser: 'webkit' mode: 'build' @@ -108,34 +123,72 @@ jobs: steps: - run: git config --global core.autocrlf false - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2.4.0 - - uses: actions/setup-node@v3 + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm playwright install ${{ matrix.e2e-browser }} + - run: pnpm run sync-all - run: pnpm test:cross-platform:${{ matrix.mode }} + - name: Print flaky test report + run: node scripts/print-flaky-test-report.js - name: Archive test results if: failure() shell: bash run: find packages -type d -name test-results -not -empty | tar -czf test-results-cross-platform-${{ matrix.mode }}.tar.gz --files-from=- - name: Upload test results if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: retention-days: 3 name: test-failure-cross-platform-${{ matrix.mode }}-${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.e2e-browser }} path: test-results-cross-platform-${{ matrix.mode }}.tar.gz - Test-create-svelte: + test-kit-server-side-route-resolution: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - mode: 'dev' + - mode: 'build' + steps: + - run: git config --global core.autocrlf false + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm playwright install chromium + - run: pnpm run sync-all + - run: pnpm test:server-side-route-resolution:${{ matrix.mode }} + - name: Print flaky test report + run: node scripts/print-flaky-test-report.js + - name: Archive test results + if: failure() + shell: bash + run: find packages -type d -name test-results -not -empty | tar -czf test-results-server-side-route-resolution-${{ matrix.mode }}.tar.gz --files-from=- + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + retention-days: 3 + name: test-failure-server-side-route-resolution-${{ matrix.mode }}-${{ github.run_id }} + path: test-results-server-side-route-resolution-${{ matrix.mode }}.tar.gz + test-others: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2.4.0 - - uses: actions/setup-node@v3 + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 18 cache: pnpm - run: pnpm install --frozen-lockfile + - run: pnpm playwright install chromium - run: cd packages/kit && pnpm prepublishOnly - - run: pnpm run test:create-svelte + - run: pnpm run test:others diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c8960ce40a9..9349b5099432 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Release on: push: branches: - - master + - main permissions: {} jobs: @@ -12,6 +12,7 @@ jobs: if: github.repository == 'sveltejs/kit' 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 @@ -21,11 +22,11 @@ jobs: 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@v2.4.0 + - uses: pnpm/action-setup@v4.1.0 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 16.x + node-version: 22.x cache: pnpm - run: pnpm install --frozen-lockfile @@ -39,8 +40,8 @@ jobs: version: pnpm changeset:version env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_CONFIG_PROVENANCE: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - UPDATE_TEMPLATE_SSH_KEY: ${{ secrets.UPDATE_TEMPLATE_SSH_KEY }} # TODO alert discord # - name: Send a Slack notification if a publish happens diff --git a/.npmrc b/.npmrc index d7445a115f87..3d5d238fe463 100644 --- a/.npmrc +++ b/.npmrc @@ -1,2 +1 @@ link-workspace-packages = true -engine-strict = true diff --git a/.prettierrc b/.prettierrc index 72264f51e616..fc699c71d960 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,6 +3,7 @@ "singleQuote": true, "trailingComma": "none", "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], "overrides": [ { "files": ["*.svelte"], @@ -20,16 +21,21 @@ { "files": [ "**/CHANGELOG.md", + "**/vite.config.js.timestamp-*", "**/.svelte-kit/**", + "**/.custom-out-dir/**", + "**/build/**", + "**/test-results/**", + "**/.wrangler/**", "documentation/**/*.md", "packages/package/test/fixtures/**/expected/**/*", "packages/package/test/watch/expected/**/*", "packages/package/test/watch/package/**/*", "packages/kit/src/core/postbuild/fixtures/**/*", - "packages/migrate/migrations/routes/*/samples.md" + "packages/adapter-cloudflare/test/apps/workers/dist/**/*" ], "options": { - "requirePragma": true + "rangeEnd": 0 } } ] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5fc83158606b..df548cfa14bc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,34 +22,42 @@ pnpm install You can use the playground at [`playgrounds/basic`](./playgrounds/basic/) to experiment with your changes to SvelteKit locally. -### Linking +### Linking local changes If you want to test against an existing project, you can use [pnpm `overrides`](https://pnpm.io/package_json#pnpmoverrides) in that project: ```jsonc { - // ... - "pnpm": { - "overrides": { - "@sveltejs/kit": "link:../path/to/svelte-kit/packages/kit", - // additionally/optional the adapter you're using - "@sveltejs/adapter-auto": "link:../path/to/svelte-kit/packages/adapter-auto" - } - } + // ... + "pnpm": { + "overrides": { + "@sveltejs/kit": "link:../path/to/svelte-kit/packages/kit", + // additionally/optional the adapter you're using + "@sveltejs/adapter-auto": "link:../path/to/svelte-kit/packages/adapter-auto" + } + } } ``` +### Testing PR changes + +Each pull request will be built and published via [pkg.pr.new/](https://pkg.pr.new/). You can test the change by installing the package with your PR number: + +``` +npm add https://pkg.pr.new/sveltejs/kit/@sveltejs/kit@YOUR_PR_NUMBER_GOES_HERE +``` + ## Code structure Entry points to be aware of are: -- [`packages/create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte) - code that's run when you create a new project with `npm create svelte@latest` -- [`packages/package`](https://github.com/sveltejs/kit/tree/master/packages/package) - for the `svelte-package` command -- [`packages/kit/src/core`](https://github.com/sveltejs/kit/tree/master/packages/kit/src/core) - code that's called at dev/build-time -- [`packages/kit/src/core/sync`](https://github.com/sveltejs/kit/tree/master/packages/kit/src/core/sync) - for `svelte-kit sync`, which regenerates routing info and type definitions -- [`packages/kit/src/runtime`](https://github.com/sveltejs/kit/tree/master/packages/kit/src/runtime) - code that's called at runtime -- [`packages/kit/src/exports/vite`](https://github.com/sveltejs/kit/tree/master/packages/kit/src/exports/vite) - for all the Vite plugin related stuff -- [`packages/adapter-[platform]`](https://github.com/sveltejs/kit/tree/master/packages) - for the various SvelteKit-provided adapters +- [`packages/create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte) - code that's run when you create a new project with `npx sv create` +- [`packages/package`](https://github.com/sveltejs/kit/tree/main/packages/package) - for the `svelte-package` command +- [`packages/kit/src/core`](https://github.com/sveltejs/kit/tree/main/packages/kit/src/core) - code that's called at dev/build-time +- [`packages/kit/src/core/sync`](https://github.com/sveltejs/kit/tree/main/packages/kit/src/core/sync) - for `svelte-kit sync`, which regenerates routing info and type definitions +- [`packages/kit/src/runtime`](https://github.com/sveltejs/kit/tree/main/packages/kit/src/runtime) - code that's called at runtime +- [`packages/kit/src/exports/vite`](https://github.com/sveltejs/kit/tree/main/packages/kit/src/exports/vite) - for all the Vite plugin related stuff +- [`packages/adapter-[platform]`](https://github.com/sveltejs/kit/tree/main/packages) - for the various SvelteKit-provided adapters ## Good first issues @@ -87,21 +95,21 @@ If you would like to test local changes to Vite or another dependency, you can b ```jsonc { - // ... - "dependencies": { - "vite": "^4.0.0" - }, - "pnpm": { - "overrides": { - "vite": "link:../path/to/vite/packages/vite" - } - } + // ... + "dependencies": { + "vite": "^4.0.0" + }, + "pnpm": { + "overrides": { + "vite": "link:../path/to/vite/packages/vite" + } + } } ``` ## Documentation changes -All documentation for SvelteKit is in the [`documentation` directory](https://github.com/sveltejs/kit/tree/master/documentation), and any improvements should be made as a Pull Request to this repository. The site itself is located in the [`sites/kit.svelte.dev` directory](https://github.com/sveltejs/kit/tree/master/sites/kit.svelte.dev) and can be run locally to preview changes. +All documentation for SvelteKit is in the [`documentation` directory](https://github.com/sveltejs/kit/tree/main/documentation), and any improvements should be made as a Pull Request to this repository. The site itself is located in the [`sveltejs/svelte.dev` repo](https://github.com/sveltejs/svelte.dev) and can be run locally to preview changes. ## Sending PRs @@ -124,6 +132,10 @@ git config core.hookspath .githooks For changes to be reflected in package changelogs, run `pnpm changeset` and follow the prompts. +### Type changes + +If your PR changes the generated types of SvelteKit, run `pnpm generate:types` inside `packages/kit` and commit the new output (don't format it with Prettier!). Review the changes carefully to ensure there are no unwanted changes. If you don't commit type changes, CI will fail. + ## Releases The [Changesets GitHub action](https://github.com/changesets/action#with-publishing) will create and update a PR that applies changesets and publishes new versions of changed packages to npm. diff --git a/FUNDING.json b/FUNDING.json new file mode 100644 index 000000000000..7ed51db691e6 --- /dev/null +++ b/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0xCE08E02c37d90d75C2bf7D9e55f7606C8DB80E70" + } + } +} diff --git a/README.md b/README.md index 65ff09b6b9b1..23b1395bd036 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # SvelteKit -Web development, streamlined. Read the [documentation](https://kit.svelte.dev/docs) to get started. +Web development, streamlined. Read the [documentation](https://svelte.dev/docs/kit) to get started. ### Packages @@ -11,17 +11,16 @@ Web development, streamlined. Read the [documentation](https://kit.svelte.dev/do | [@sveltejs/kit](packages/kit) | [Changelog](packages/kit/CHANGELOG.md) | | [@sveltejs/adapter-auto](packages/adapter-auto) | [Changelog](packages/adapter-auto/CHANGELOG.md) | | [@sveltejs/adapter-cloudflare](packages/adapter-cloudflare) | [Changelog](packages/adapter-cloudflare/CHANGELOG.md) | -| [@sveltejs/adapter-cloudflare-workers](packages/adapter-cloudflare-workers) | [Changelog](packages/adapter-cloudflare-workers/CHANGELOG.md) | | [@sveltejs/adapter-netlify](packages/adapter-netlify) | [Changelog](packages/adapter-netlify/CHANGELOG.md) | | [@sveltejs/adapter-node](packages/adapter-node) | [Changelog](packages/adapter-node/CHANGELOG.md) | | [@sveltejs/adapter-static](packages/adapter-static) | [Changelog](packages/adapter-static/CHANGELOG.md) | | [@sveltejs/adapter-vercel](packages/adapter-vercel) | [Changelog](packages/adapter-vercel/CHANGELOG.md) | | [@sveltejs/amp](packages/amp) | [Changelog](packages/amp/CHANGELOG.md) | +| [@sveltejs/enhanced-img](packages/enhanced-img) | [Changelog](packages/enhanced-img/CHANGELOG.md) | | [@sveltejs/package](packages/package) | [Changelog](packages/package/CHANGELOG.md) | | [create-svelte](packages/create-svelte) | [Changelog](packages/create-svelte/CHANGELOG.md) | -| [svelte-migrate](packages/migrate) | [Changelog](packages/migrate/CHANGELOG.md) | -[Additional adapters](<(https://sveltesociety.dev/components#adapters)>) are maintained by the community. +[Additional adapters](https://sveltesociety.dev/packages?category=sveltekit-adapters) are maintained by the community. ## Bug reporting @@ -43,4 +42,4 @@ Funds donated via Open Collective will be used for compensating expenses related ## License -[MIT](https://github.com/sveltejs/kit/blob/master/LICENSE) +[MIT](https://github.com/sveltejs/kit/blob/main/LICENSE) diff --git a/documentation/docs/10-getting-started/10-introduction.md b/documentation/docs/10-getting-started/10-introduction.md index 189fcb3bcc7d..dd093ff5abea 100644 --- a/documentation/docs/10-getting-started/10-introduction.md +++ b/documentation/docs/10-getting-started/10-introduction.md @@ -4,24 +4,24 @@ title: Introduction ## Before we begin -> If you're new to Svelte or SvelteKit we recommend checking out the [interactive tutorial](https://learn.svelte.dev). +> [!NOTE] If you're new to Svelte or SvelteKit we recommend checking out the [interactive tutorial](/tutorial/kit). > -> If you get stuck, reach out for help in the [Discord chatroom](https://svelte.dev/chat). +> If you get stuck, reach out for help in the [Discord chatroom](/chat). ## What is SvelteKit? -SvelteKit is a framework for rapidly developing robust, performant web applications using [Svelte](https://svelte.dev/). If you're coming from React, SvelteKit is similar to Next. If you're coming from Vue, SvelteKit is similar to Nuxt. +SvelteKit is a framework for rapidly developing robust, performant web applications using [Svelte](../svelte). If you're coming from React, SvelteKit is similar to Next. If you're coming from Vue, SvelteKit is similar to Nuxt. -To learn more about the kinds of applications you can build with SvelteKit, see the [FAQ](/docs/faq#what-can-i-make-with-sveltekit). +To learn more about the kinds of applications you can build with SvelteKit, see the [documentation regarding project types](project-types). ## What is Svelte? -In short, Svelte is a way of writing user interface components — like a navigation bar, comment section, or contact form — that users see and interact with in their browsers. The Svelte compiler converts your components to JavaScript that can be run to render the HTML for the page and to CSS that styles the page. You don't need to know Svelte to understand the rest of this guide, but it will help. If you'd like to learn more, check out [the Svelte tutorial](https://svelte.dev/tutorial). +In short, Svelte is a way of writing user interface components — like a navigation bar, comment section, or contact form — that users see and interact with in their browsers. The Svelte compiler converts your components to JavaScript that can be run to render the HTML for the page and to CSS that styles the page. You don't need to know Svelte to understand the rest of this guide, but it will help. If you'd like to learn more, check out [the Svelte tutorial](/tutorial). ## SvelteKit vs Svelte Svelte renders UI components. You can compose these components and render an entire page with just Svelte, but you need more than just Svelte to write an entire app. -SvelteKit helps you build web apps while following modern best practices and providing solutions to common development challenges. It offers everything from basic functionalities — like a [router](glossary#routing) that updates your UI when a link is clicked — to more advanced capabilities. Its extensive list of features includes [build optimizations](https://vitejs.dev/guide/features.html#build-optimizations) to load only the minimal required code; [offline support](service-workers); [preloading](link-options#data-sveltekit-preload-data) pages before user navigation; [configurable rendering](page-options) to handle different parts of your app on the server via [SSR](glossary#ssr), in the browser through [client-side rendering](glossary#csr), or at build-time with [prerendering](glossary#prerendering); and much more. Building an app with all the modern best practices is fiendishly complicated, but SvelteKit does all the boring stuff for you so that you can get on with the creative part. +SvelteKit helps you build web apps while following modern best practices and providing solutions to common development challenges. It offers everything from basic functionalities — like a [router](glossary#Routing) that updates your UI when a link is clicked — to more advanced capabilities. Its extensive list of features includes [build optimizations](https://vitejs.dev/guide/features.html#build-optimizations) to load only the minimal required code; [offline support](service-workers); [preloading](link-options#data-sveltekit-preload-data) pages before user navigation; [configurable rendering](page-options) to handle different parts of your app on the server via [SSR](glossary#SSR), in the browser through [client-side rendering](glossary#CSR), or at build-time with [prerendering](glossary#Prerendering); [image optimization](images); and much more. Building an app with all the modern best practices is fiendishly complicated, but SvelteKit does all the boring stuff for you so that you can get on with the creative part. It reflects changes to your code in the browser instantly to provide a lightning-fast and feature-rich development experience by leveraging [Vite](https://vitejs.dev/) with a [Svelte plugin](https://github.com/sveltejs/vite-plugin-svelte) to do [Hot Module Replacement (HMR)](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md#hot). diff --git a/documentation/docs/10-getting-started/20-creating-a-project.md b/documentation/docs/10-getting-started/20-creating-a-project.md index a65814e9a50f..4219449d1f1a 100644 --- a/documentation/docs/10-getting-started/20-creating-a-project.md +++ b/documentation/docs/10-getting-started/20-creating-a-project.md @@ -2,10 +2,10 @@ title: Creating a project --- -The easiest way to start building a SvelteKit app is to run `npm create`: +The easiest way to start building a SvelteKit app is to run `npx sv create`: ```bash -npm create svelte@latest my-app +npx sv create my-app cd my-app npm install npm run dev @@ -15,11 +15,11 @@ The first command will scaffold a new project in the `my-app` directory asking y There are two basic concepts: -- Each page of your app is a [Svelte](https://svelte.dev) component +- Each page of your app is a [Svelte](../svelte) component - You create pages by adding files to the `src/routes` directory of your project. These will be server-rendered so that a user's first visit to your app is as fast as possible, then a client-side app takes over Try editing the files to get a feel for how everything works. ## Editor setup -We recommend using [Visual Studio Code (aka VS Code)](https://code.visualstudio.com/download) with [the Svelte extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), but [support also exists for numerous other editors](https://sveltesociety.dev/tools#editor-support). +We recommend using [Visual Studio Code (aka VS Code)](https://code.visualstudio.com/download) with [the Svelte extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), but [support also exists for numerous other editors](https://sveltesociety.dev/resources#editor-support). diff --git a/documentation/docs/10-getting-started/25-project-types.md b/documentation/docs/10-getting-started/25-project-types.md new file mode 100644 index 000000000000..51a32deae4a8 --- /dev/null +++ b/documentation/docs/10-getting-started/25-project-types.md @@ -0,0 +1,69 @@ +--- +title: Project types +--- + +SvelteKit offers configurable rendering, which allows you to build and deploy your project in several different ways. You can build all of the below types of applications and more with SvelteKit. Rendering settings are not mutually exclusive and you may choose the optimal manner with which to render different parts of your application. + +If you don't have a particular way you'd like to build your application in mind, don't worry! The way your application is built, deployed, and rendered is controlled by which adapter you've chosen and a small amount of configuration and these can always be changed later. The [project structure](project-structure) and [routing](glossary#Routing) will be the same regardless of the project type that you choose. + +## Default rendering + +By default, when a user visits a site, SvelteKit will render the first page with [server-side rendering (SSR)](glossary#SSR) and subsequent pages with [client-side rendering (CSR)](glossary#CSR). Using SSR for the initial render improves SEO and perceived performance of the initial page load. Client-side rendering then takes over and updates the page without having to rerender common components, which is typically faster and eliminates a flash when navigating between pages. Apps built with this hybrid rendering approach have also been called [transitional apps](https://www.youtube.com/watch?v=860d8usGC0o). + +## Static site generation + +You can use SvelteKit as a [static site generator (SSG)](glossary#SSG) that fully [prerenders](glossary#Prerendering) your site with static rendering using [`adapter-static`](adapter-static). You may also use [the prerender option](page-options#prerender) to prerender only some pages and then choose a different adapter with which to dynamically server-render other pages. + +Tools built solely to do static site generation may scale the prerendering process more efficiently during build when rendering a very large number of pages. When working with very large statically generated sites, you can avoid long build times with [Incremental Static Regeneration (ISR) if using `adapter-vercel`](adapter-vercel#Incremental-Static-Regeneration). And in contrast to purpose-built SSGs, SvelteKit allows for nicely mixing and matching different rendering types on different pages. + +## Single-page app + +[Single-page apps (SPAs)](glossary#SPA) exclusively use [client-side rendering (CSR)](glossary#CSR). You can [build single-page apps (SPAs)](single-page-apps) with SvelteKit. As with all types of SvelteKit applications, you can write your backend in SvelteKit or [another language or framework](#Separate-backend). If you are building an application with no backend or a [separate backend](#Separate-backend), you can simply skip over and ignore the parts of the docs talking about `server` files. + +## Multi-page app + +SvelteKit isn't typically used to build [traditional multi-page apps](glossary#MPA). However, in SvelteKit you can remove all JavaScript on a page with [`csr = false`](page-options#csr), which will render subsequent links on the server, or you can use [`data-sveltekit-reload`](link-options#data-sveltekit-reload) to render specific links on the server. + +## Separate backend + +If your backend is written in another language such as Go, Java, PHP, Ruby, Rust, or C#, there are a couple of ways that you can deploy your application. The most recommended way would be to deploy your SvelteKit frontend separately from your backend utilizing `adapter-node` or a serverless adapter. Some users prefer not to have a separate process to manage and decide to deploy their application as a [single-page app (SPA)](single-page-apps) served by their backend server, but note that single-page apps have worse SEO and performance characteristics. + +If you are using an external backend, you can simply skip over and ignore the parts of the docs talking about `server` files. You may also want to reference [the FAQ about how to make calls to a separate backend](faq#How-do-I-use-a-different-backend-API-server). + +## Serverless app + +SvelteKit apps are simple to run on serverless platforms. [The default zero config adapter](adapter-auto) will automatically run your app on a number of supported platforms or you can use [`adapter-vercel`](adapter-vercel), [`adapter-netlify`](adapter-netlify), or [`adapter-cloudflare`](adapter-cloudflare) to provide platform-specific configuration. And [community adapters](https://sveltesociety.dev/packages?category=sveltekit-adapters) allow you to deploy your application to almost any serverless environment. Some of these adapters such as [`adapter-vercel`](adapter-vercel) and [`adapter-netlify`](adapter-netlify) offer an `edge` option, to support [edge rendering](glossary#Edge) for improved latency. + +## Your own server + +You can deploy to your own server or VPS using [`adapter-node`](adapter-node). + +## Container + +You can use [`adapter-node`](adapter-node) to run a SvelteKit app within a container such as Docker or LXC. + +## Library + +You can create a library to be used by other Svelte apps with the [`@sveltejs/package`](packaging) add-on to SvelteKit by choosing the library option when running [`sv create`](/docs/cli/sv-create). + +## Offline app + +SvelteKit has full support for [service workers](service-workers) allowing you to build many types of applications such as offline apps and [progressive web apps](glossary#PWA). + +## Mobile app + +You can turn a [SvelteKit SPA](single-page-apps) into a mobile app with [Tauri](https://v2.tauri.app/start/frontend/sveltekit/) or [Capacitor](https://capacitorjs.com/solution/svelte). Mobile features like the camera, geolocation, and push notifications are available via plugins for both platforms. + +These mobile development platforms work by starting a local web server and then serving your application like a static host on your phone. You may find [`bundleStrategy: 'single'`](configuration#output) to be a helpful option to limit the number of requests made. E.g. at the time of writing, the Capacitor local server uses HTTP/1, which limits the number of concurrent connections. + +## Desktop app + +You can turn a [SvelteKit SPA](single-page-apps) into a desktop app with [Tauri](https://v2.tauri.app/start/frontend/sveltekit/), [Wails](https://wails.io/docs/guides/sveltekit/), or [Electron](https://www.electronjs.org/). + +## Browser extension + +You can build browser extensions using either [`adapter-static`](adapter-static) or [community adapters](https://sveltesociety.dev/packages?category=sveltekit-adapters) specifically tailored towards browser extensions. + +## Embedded device + +Because of its efficient rendering, Svelte can be run on low power devices. Embedded devices like microcontrollers and TVs may limit the number of concurrent connections. In order to reduce the number of concurrent requests, you may find [`bundleStrategy: 'single'`](configuration#output) to be a helpful option in this deployment configuration. diff --git a/documentation/docs/10-getting-started/30-project-structure.md b/documentation/docs/10-getting-started/30-project-structure.md index e9a63473b0d9..64bae0a695c1 100644 --- a/documentation/docs/10-getting-started/30-project-structure.md +++ b/documentation/docs/10-getting-started/30-project-structure.md @@ -4,7 +4,7 @@ title: Project structure A typical SvelteKit project looks like this: -```bash +```tree my-project/ ├ src/ │ ├ lib/ @@ -30,7 +30,7 @@ my-project/ └ vite.config.js ``` -You'll also find common files like `.gitignore` and `.npmrc` (and `.prettierrc` and `.eslintrc.cjs` and so on, if you chose those options when running `npm create svelte@latest`). +You'll also find common files like `.gitignore` and `.npmrc` (and `.prettierrc` and `eslint.config.js` and so on, if you chose those options when running `npx sv create`). ## Project files @@ -38,9 +38,9 @@ You'll also find common files like `.gitignore` and `.npmrc` (and `.prettierrc` The `src` directory contains the meat of your project. Everything except `src/routes` and `src/app.html` is optional. -- `lib` contains your library code (utilities and components), which can be imported via the [`$lib`](modules#$lib) alias, or packaged up for distribution using [`svelte-package`](packaging) +- `lib` contains your library code (utilities and components), which can be imported via the [`$lib`]($lib) alias, or packaged up for distribution using [`svelte-package`](packaging) - `server` contains your server-only library code. It can be imported by using the [`$lib/server`](server-only-modules) alias. SvelteKit will prevent you from importing these in client code. -- `params` contains any [param matchers](advanced-routing#matching) your app needs +- `params` contains any [param matchers](advanced-routing#Matching) your app needs - `routes` contains the [routes](routing) of your application. You can also colocate other components that are only used within a single route here - `app.html` is your page template — an HTML document containing the following placeholders: - `%sveltekit.head%` — `` and `
Next post: {next.title}
-+{/if} ++++{#if next} +Next post: {next.title}
+{/if}+++ ``` -> If multiple `load` functions return data with the same key, the last one 'wins' — the result of a layout `load` returning `{ a: 1, b: 2 }` and a page `load` returning `{ b: 3, c: 4 }` would be `{ a: 1, b: 3, c: 4 }`. +> [!NOTE] If multiple `load` functions return data with the same key, the last one 'wins' — the result of a layout `load` returning `{ a: 1, b: 2 }` and a page `load` returning `{ b: 3, c: 4 }` would be `{ a: 1, b: 3, c: 4 }`. -## $page.data +## page.data The `+page.svelte` component, and each `+layout.svelte` component above it, has access to its own data plus all the data from its parents. -In some cases, we might need the opposite — a parent layout might need to access page data or data from a child layout. For example, the root layout might want to access a `title` property returned from a `load` function in `+page.js` or `+page.server.js`. This can be done with `$page.data`: +In some cases, we might need the opposite — a parent layout might need to access page data or data from a child layout. For example, the root layout might want to access a `title` property returned from a `load` function in `+page.js` or `+page.server.js`. This can be done with `page.data`: ```svelte{data.a} + {data.b} = {data.c}
``` -> Notice that the `load` function in `+page.js` receives the merged data from both layout `load` functions, not just the immediate parent. +> [!NOTE] Notice that the `load` function in `+page.js` receives the merged data from both layout `load` functions, not just the immediate parent. Inside `+page.server.js` and `+layout.server.js`, `parent` returns data from parent `+layout.server.js` files. @@ -359,16 +403,21 @@ In `+page.js` or `+layout.js` it will return data from parent `+layout.js` files Take care not to introduce waterfalls when using `await parent()`. Here, for example, `getData(params)` does not depend on the result of calling `parent()`, so we should call it first to avoid a delayed render. -```diff +```js /// file: +page.js +// @filename: ambient.d.ts +declare function getData(params: Record- one: {data.one} -
-- two: {data.two} -
-- three: - {#await data.streamed.three} - Loading... - {:then value} - {value} - {:catch error} - {error.message} - {/await} -
+{comment.content}
+ {/each} +{:catch error} +error loading comments: {error.message}
+{/await} +``` + +When streaming data, be careful to handle promise rejections correctly. More specifically, the server could crash with an "unhandled promise rejection" error if a lazy-loaded promise fails before rendering starts (at which point it's caught) and isn't handling the error in some way. When using SvelteKit's `fetch` directly in the `load` function, SvelteKit will handle this case for you. For other promises, it is enough to attach a noop-`catch` to the promise to mark it as handled. + +```js +/// file: src/routes/+page.server.js +/** @type {import('./$types').PageServerLoad} */ +export function load({ fetch }) { + const ok_manual = Promise.reject(); + ok_manual.catch(() => {}); + + return { + ok_manual, + ok_fetch: fetch('/fetch/that/could/fail'), + dangerous_unhandled: Promise.reject() + }; +} ``` -> On platforms that do not support streaming, such as AWS Lambda, responses will be buffered. This means the page will only render once all promises resolve. If you are using a proxy (e.g. NGINX), make sure it does not buffer responses from the proxied server. +> [!NOTE] On platforms that do not support streaming, such as AWS Lambda or Firebase, responses will be buffered. This means the page will only render once all promises resolve. If you are using a proxy (e.g. NGINX), make sure it does not buffer responses from the proxied server. -> Streaming data will only work when JavaScript is enabled. You should avoid returning nested promises from a universal `load` function if the page is server rendered, as these are _not_ streamed — instead, the promise is recreated when the function reruns in the browser. +> [!NOTE] Streaming data will only work when JavaScript is enabled. You should avoid returning promises from a universal `load` function if the page is server rendered, as these are _not_ streamed — instead, the promise is recreated when the function reruns in the browser. -> The headers and status code of a response cannot be changed once the response has started streaming, therefore you cannot `setHeaders` or throw redirects inside a streamed promise. +> [!NOTE] The headers and status code of a response cannot be changed once the response has started streaming, therefore you cannot `setHeaders` or throw redirects inside a streamed promise. + +> [!NOTE] [In SvelteKit 1.x](migrating-to-sveltekit-2#Top-level-promises-are-no-longer-awaited) top-level promises were automatically awaited, only nested promises were streamed. ## Parallel loading @@ -546,11 +621,28 @@ export async function load() { A `load` function that calls `await parent()` will also rerun if a parent `load` function is rerun. -Dependency tracking does not apply _after_ the `load` function has returned — for example, accessing `params.x` inside a nested [promise](#streaming-with-promises) will not cause the function to rerun when `params.x` changes. (Don't worry, you'll get a warning in development if you accidentally do this.) Instead, access the parameter in the main body of your `load` function. +Dependency tracking does not apply _after_ the `load` function has returned — for example, accessing `params.x` inside a nested [promise](#Streaming-with-promises) will not cause the function to rerun when `params.x` changes. (Don't worry, you'll get a warning in development if you accidentally do this.) Instead, access the parameter in the main body of your `load` function. + +Search parameters are tracked independently from the rest of the url. For example, accessing `event.url.searchParams.get("x")` inside a `load` function will make that `load` function re-run when navigating from `?x=1` to `?x=2`, but not when navigating from `?x=1&y=1` to `?x=1&y=2`. + +### Untracking dependencies + +In rare cases, you may wish to exclude something from the dependency tracking mechanism. You can do this with the provided `untrack` function: + +```js +/// file: src/routes/+page.js +/** @type {import('./$types').PageLoad} */ +export async function load({ untrack, url }) { + // Untrack url.pathname so that path changes don't trigger a rerun + if (untrack(() => url.pathname === '/')) { + return { message: 'Welcome!' }; + } +} +``` ### Manual invalidation -You can also rerun `load` functions that apply to the current page using [`invalidate(url)`](modules#$app-navigation-invalidate), which reruns all `load` functions that depend on `url`, and [`invalidateAll()`](modules#$app-navigation-invalidateall), which reruns every `load` function. Server load functions will never automatically depend on a fetched `url` to avoid leaking secrets to the client. +You can also rerun `load` functions that apply to the current page using [`invalidate(url)`]($app-navigation#invalidate), which reruns all `load` functions that depend on `url`, and [`invalidateAll()`]($app-navigation#invalidateAll), which reruns every `load` function. Server load functions will never automatically depend on a fetched `url` to avoid leaking secrets to the client. A `load` function depends on `url` if it calls `fetch(url)` or `depends(url)`. Note that `url` can be a custom identifier that starts with `[a-z]:`: @@ -575,8 +667,8 @@ export async function load({ fetch, depends }) {random number: {data.number}
- + ``` ### When do load functions rerun? @@ -597,16 +689,100 @@ To summarize, a `load` function will rerun in the following situations: - It references a property of `params` whose value has changed - It references a property of `url` (such as `url.pathname` or `url.search`) whose value has changed. Properties in `request.url` are _not_ tracked +- It calls `url.searchParams.get(...)`, `url.searchParams.getAll(...)` or `url.searchParams.has(...)` and the parameter in question changes. Accessing other properties of `url.searchParams` will have the same effect as accessing `url.search`. - It calls `await parent()` and a parent `load` function reran -- It declared a dependency on a specific URL via [`fetch`](#making-fetch-requests) (universal load only) or [`depends`](types#public-types-loadevent), and that URL was marked invalid with [`invalidate(url)`](modules#$app-navigation-invalidate) -- All active `load` functions were forcibly rerun with [`invalidateAll()`](modules#$app-navigation-invalidateall) +- A child `load` function calls `await parent()` and is rerunning, and the parent is a server load function +- It declared a dependency on a specific URL via [`fetch`](#Making-fetch-requests) (universal load only) or [`depends`](@sveltejs-kit#LoadEvent), and that URL was marked invalid with [`invalidate(url)`]($app-navigation#invalidate) +- All active `load` functions were forcibly rerun with [`invalidateAll()`]($app-navigation#invalidateAll) + +`params` and `url` can change in response to a `` link click, a [`