Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/sv/src/migrate/migrations/sveltekit-3/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import externalRedirects from './tasks/external-redirects.ts';
import packageJson from './tasks/package-json.ts';
import params from './tasks/params.ts';
import paths from './tasks/paths.ts';
import prepareAiMigration from './tasks/prepare-ai-migration.ts';
import shallowRouting from './tasks/shallow-routing.ts';
import svelteConfig from './tasks/svelte-config.ts';
import tsconfig from './tasks/tsconfig.ts';
Expand Down Expand Up @@ -38,5 +39,6 @@ export default defineMigration({
tasks.add(params, { prerequisite: false });
tasks.add(tsconfig, { prerequisite: true });
tasks.add(appState, { prerequisite: false });
tasks.add(prepareAiMigration, { prerequisite: false });
}
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import experimentalAddon from '../../../../addons/experimental.ts';

Check failure on line 1 in packages/sv/src/migrate/migrations/sveltekit-3/tasks/package-json.ts

View workflow job for this annotation

GitHub Actions / lint

'experimentalAddon' is defined but never used
import { defineMigrationTask } from '../../../index.ts';

export default defineMigrationTask({
id: 'package-json',
description: 'Update package.json to be compatible with SvelteKit 3.0',
run: (args) => {

Check failure on line 7 in packages/sv/src/migrate/migrations/sveltekit-3/tasks/package-json.ts

View workflow job for this annotation

GitHub Actions / lint

'args' is defined but never used. Allowed unused args must match /^_/u
// instead of duplicating the logic of the experimental addon, lets just call it.
// migrates kit to it's 'next' version.
experimentalAddon.run({
...args,
options: { versions: ['kit-3'], features: [] },
cancel: () => {}
});
// experimentalAddon.run({
// ...args,
// options: { versions: ['kit-3'], features: [] },
// cancel: () => {}
// });
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { defineMigrationTask } from '../../../index.ts';

const REPORT_PATH = 'MIGRATION_TASKS.md';
export const GENERATED_MARKER = '<!-- Generated by sv migrate sveltekit-3:prepare-ai-migration -->';

type MigrationTask = {
title: string;
checks: Array<{
include: string | string[];
patterns: Array<string | RegExp>;
}>;
summary: string;
instructions: string;
links: Array<{ label: string; url: string }>;
};

const migrationTasks: MigrationTask[] = [
{
title: 'Remove `experimental.handleRenderingErrors`',
checks: [
{
include: '**/{svelte,vite}.config.{js,ts,mjs,mts,cjs,cts}',
patterns: ['handleRenderingErrors']
}
],
summary:
'SvelteKit 3 removes the `experimental.handleRenderingErrors` feature flag because rendering errors are now handled this way by default.',
instructions:
'Remove the `handleRenderingErrors` property from the SvelteKit configuration. If that leaves an empty `experimental` object, remove that object as well. No replacement option is needed — SvelteKit 3 always wraps route components in error boundaries so rendering errors reach the nearest `+error.svelte` page.',
links: [
{
label: 'SvelteKit PR #16265',
url: 'https://github.com/sveltejs/kit/pull/16265'
}
]
},
{
// Temporary: this is already handled by the automatic Kit 3 migration. It exercises a
// migration task with multiple detection rules and can be removed after this task is proven.
title: 'Replace the `$lib` alias with `#lib` and remove `files.lib`',
checks: [
{
include: '**/*.{js,ts,svelte,mjs,mts,cjs,cts}',
patterns: ['$lib']
},
{
include: '**/{svelte,vite}.config.{js,ts,mjs,mts,cjs,cts}',
patterns: [/\bfiles\s*:\s*\{[\s\S]*?\blib\s*:/]
}
],
summary:
'SvelteKit 3 removes the built-in `$lib` alias and the `kit.files.lib` configuration. The replacement is a Node subpath import named `#lib`, configured through the package.json `imports` field.',
instructions:
'Replace remaining `$lib` module references with `#lib`. Add `"#lib": "./src/lib/index.js"` and `"#lib/*": "./src/lib/*"` to package.json `imports`, adjusting `src/lib` if the project used a custom library directory. Remove `files.lib` from the SvelteKit configuration. Check imports, re-exports, dynamic imports, ambient module declarations, tests, and configuration strings rather than assuming every textual match is executable code. If the project intentionally needs to preserve `$lib`, configure it explicitly through SvelteKit `alias` instead of adding the `#lib` imports.',
links: [
{
label: 'SvelteKit PR #16360',
url: 'https://github.com/sveltejs/kit/pull/16360'
},
{
label: 'Node.js package imports',
url: 'https://nodejs.org/api/packages.html#subpath-imports'
}
]
}
];

type Finding = { task: MigrationTask; files: string[] };

export default defineMigrationTask({
id: 'prepare-ai-migration',
description: 'Prepare instructions for AI-assisted migration tasks',
run: ({ sv }) => {
const findings: Finding[] = [];

for (const task of migrationTasks) {
const files = new Set<string>();
for (const check of task.checks) {
sv.files(
{
include: check.include,
exclude: [REPORT_PATH],
where: (content) => check.patterns.some((pattern) => matches(content, pattern))
},
(_content, file) => {
files.add(file);
return false;
}
);
}

if (files.size > 0) findings.push({ task, files: [...files].sort() });
}

if (findings.length === 0) return;

sv.file(REPORT_PATH, (content) => {
if (content && !content.includes(GENERATED_MARKER)) {
throw new Error(
`'${REPORT_PATH}' already exists and was not generated by this migration. Move or rename it before rerunning the task.`
);
}

return renderReport(findings);
});
}
});

function matches(content: string, pattern: string | RegExp): boolean {
return typeof pattern === 'string' ? content.includes(pattern) : pattern.test(content);
}

export function renderReport(findings: Finding[]): string {
const sections = findings.map(({ task, files }) => {
const links = task.links.map(({ label, url }) => `- [${label}](${url})`).join('\n');
const locations = files.map((file) => `- [ ] \`${file}\``).join('\n');

return `### ${task.title}

${task.summary}

#### What to do

${task.instructions}

#### References

${links}

#### Files to review

${locations}`;
});

return `${GENERATED_MARKER}
# SvelteKit 3 migration tasks

## For humans

Some migrations are uncommon, context-dependent, or disproportionately difficult to automate safely. Modern AI assistants can handle many of these cases effectively when they are given focused context. This file uses that current technology to bridge the gap while keeping the automatic migrations reliable and maintainable.

The findings are intentionally broad and may include files that do not require changes. Review the AI's work before accepting it.

## For AI assistants

Work through the migration tasks below one at a time:

1. Read the linked documentation or pull request before changing code.
2. Inspect every listed file and its surrounding context.
3. Ignore a finding when the file is not actually affected.
4. Make the smallest necessary change. Do not perform unrelated refactors or introduce unnecessary abstractions.
5. Ask the user when application intent cannot be inferred.
6. Run the project's appropriate checks after editing.

Also search the project for \`@migration-task\` comments. They may describe additional manual migration work that must be resolved.

## Migration tasks

${sections.join('\n\n')}

## Final verification

- [ ] Review every migration task and ignore any irrelevant findings.
- [ ] Resolve remaining \`@migration-task\` comments.
- [ ] Run the project's type checker and tests.
- [ ] Build the project successfully.
- [ ] Delete this file when all migration work is complete.
`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!-- Generated by sv migrate sveltekit-3:prepare-ai-migration -->
# SvelteKit 3 migration tasks

## For humans

Some migrations are uncommon, context-dependent, or disproportionately difficult to automate safely. Modern AI assistants can handle many of these cases effectively when they are given focused context. This file uses that current technology to bridge the gap while keeping the automatic migrations reliable and maintainable.

The findings are intentionally broad and may include files that do not require changes. Review the AI's work before accepting it.

## For AI assistants

Work through the migration tasks below one at a time:

1. Read the linked documentation or pull request before changing code.
2. Inspect every listed file and its surrounding context.
3. Ignore a finding when the file is not actually affected.
4. Make the smallest necessary change. Do not perform unrelated refactors or introduce unnecessary abstractions.
5. Ask the user when application intent cannot be inferred.
6. Run the project's appropriate checks after editing.

Also search the project for `@migration-task` comments. They may describe additional manual migration work that must be resolved.

## Migration tasks

### Remove `experimental.handleRenderingErrors`

SvelteKit 3 removes the `experimental.handleRenderingErrors` feature flag because rendering errors are now handled this way by default.

#### What to do

Remove the `handleRenderingErrors` property from the SvelteKit configuration. If that leaves an empty `experimental` object, remove that object as well. No replacement option is needed — SvelteKit 3 always wraps route components in error boundaries so rendering errors reach the nearest `+error.svelte` page.

#### References

- [SvelteKit PR #16265](https://github.com/sveltejs/kit/pull/16265)

#### Files to review

- [ ] `nested/svelte.config.ts`
- [ ] `svelte.config.js`
- [ ] `vite.config.ts`

### Replace the `$lib` alias with `#lib` and remove `files.lib`

SvelteKit 3 removes the built-in `$lib` alias and the `kit.files.lib` configuration. The replacement is a Node subpath import named `#lib`, configured through the package.json `imports` field.

#### What to do

Replace remaining `$lib` module references with `#lib`. Add `"#lib": "./src/lib/index.js"` and `"#lib/*": "./src/lib/*"` to package.json `imports`, adjusting `src/lib` if the project used a custom library directory. Remove `files.lib` from the SvelteKit configuration. Check imports, re-exports, dynamic imports, ambient module declarations, tests, and configuration strings rather than assuming every textual match is executable code. If the project intentionally needs to preserve `$lib`, configure it explicitly through SvelteKit `alias` instead of adding the `#lib` imports.

#### References

- [SvelteKit PR #16360](https://github.com/sveltejs/kit/pull/16360)
- [Node.js package imports](https://nodejs.org/api/packages.html#subpath-imports)

#### Files to review

- [ ] `src/routes/+page.svelte`
- [ ] `svelte.config.js`

## Final verification

- [ ] Review every migration task and ignore any irrelevant findings.
- [ ] Resolve remaining `@migration-task` comments.
- [ ] Run the project's type checker and tests.
- [ ] Build the project successfully.
- [ ] Delete this file when all migration work is complete.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This intentionally broad textual match may be irrelevant and should still be reported.
const removedOption = 'handleRenderingErrors';

export default { removedOption };
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
import Component from '$lib/Component.svelte';
</script>

<Component />
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
kit: {
// This directory was previously available through $lib.
files: {
lib: 'src/shared'
},
experimental: {
handleRenderingErrors: true
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
plugins: [sveltekit({ experimental: { handleRenderingErrors: true } })]
});
Loading