本迁移指南概述了如何从 Svelte 版本 3 迁移到 4。查看链接的 PR 以获取每个更改的更多详细信息。使用迁移脚本来自动迁移其中一些: `npx svelte-migrate@latest svelte-4` 如果您是库的作者,请考虑是否只支持 Svelte 4,或者是否可能也支持 Svelte 3。由于大多数破坏性更改不会影响很多人,这可能很容易实现。同时,请记得更新您的`peerDependencies`中的版本范围。 ## 最低版本要求 * 升级到 Node 16 或更高版本。早期版本不再受支持。([#8566](https://github.com/sveltejs/svelte/issues/8566)) * 如果您正在使用 SvelteKit,请升级到 1.20.4 或更高版本([sveltejs/kit#10172](https://github.com/sveltejs/kit/pull/10172)) * 如果您在使用 Vite 而不使用 SvelteKit,请升级到`vite-plugin-svelte` 2.4.1 或更高版本([#8516](https://github.com/sveltejs/svelte/issues/8516)) * 如果您正在使用 webpack,请升级到 webpack 5 或更高版本,以及`svelte-loader` 3.1.8 或更高版本。早期版本不再受支持。([#8515](https://github.com/sveltejs/svelte/issues/8515),[198dbcf](https://github.com/sveltejs/svelte/commit/198dbcf)) * 如果您正在使用 Rollup,请升级到`rollup-plugin-svelte` 7.1.5 或更高版本([198dbcf](https://github.com/sveltejs/svelte/commit/198dbcf))。 * 如果您正在使用 TypeScript,请升级到 TypeScript 5 或更高版本。较低版本可能仍然可以使用,但对此不提供任何保证。([#8488](https://github.com/sveltejs/svelte/issues/8488)) ## 浏览器对打包工具的条件 打包器现在必须在构建浏览器前端包时指定 `浏览器` 条件。SvelteKit 和 Vite 将自动为您处理此操作。如果您使用其他工具,可能会观察到生命周期回调例如 `onMount` 没有被调用,您需要更新模块解析配置。 * 对于 Rollup,这是在`@rollup/plugin-node-resolve`插件中完成的,通过在其选项中设置`browser: true`。有关更多详细信息,请参阅`rollup-plugin-svelte`文档。 * 对于 webpack,这是通过向`conditionNames`数组中添加`"browser"`来完成的。如果您已经设置了它,可能还需要更新您的`alias`配置。有关更多详细信息,请参阅`svelte-loader`文档。 (《[#8516](https://github.com/sveltejs/svelte/issues/8516)》) ## 删除 CJS 相关输出 Svelte 不再支持编译输出的 CommonJS(CJS)格式,并且也已移除了`svelte/register`钩子和 CJS 运行时版本。如果您需要保持 CJS 输出格式,请考虑在构建后步骤中使用打包器将 Svelte 的 ESM 输出转换为 CJS。([#8613](https://github.com/sveltejs/svelte/issues/8613)) ## 更严格的 Svelte 函数类型 现在对`createEventDispatcher`、`Action`、`ActionReturn`和`onMount`有更严格的类型: * `创建事件调度器`现在支持指定负载是可选的、必需的或不存在,并且相应地检查调用位置([编号 7224](https://github.com/sveltejs/svelte/issues/7224)) ```ts // @errors: 2554 2345 import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher<{ optional: number | null; required: string; noArgument: null; }>(); // Svelte version 3: dispatch('optional'); dispatch('required'); // I can still omit the detail argument dispatch('noArgument', 'surprise'); // I can still add a detail argument // Svelte version 4 using TypeScript strict mode: dispatch('optional'); dispatch('required'); // error, missing argument dispatch('noArgument', 'surprise'); // error, cannot pass an argument ``` * `操作` 和 `操作返回` 现在默认参数类型为 `未定义`,这意味着如果您想指定此操作接收参数,则需要输入泛型。迁移脚本将自动迁移此操作([#7442](https://github.com/sveltejs/svelte/pull/7442))。 ```ts // @noErrors ---const action: Action = (node, params) => { ... } // this is now an error if you use params in any way--- +++const action: Action = (node, params) => { ... } // params is of type string+++ ``` * `onMount`现在在从其中异步返回一个函数时显示类型错误,因为这很可能是你代码中的一个错误,你期望在销毁时调用回调,它只为同步返回的函数执行([#8136](https://github.com/sveltejs/svelte/issues/8136)) ```js // @noErrors // Example where this change reveals an actual bug onMount( --- // someCleanup() not called because function handed to onMount is async async () => { const something = await foo();--- +++ // someCleanup() is called because function handed to onMount is sync () => { foo().then(something => {...}); // ... return () => someCleanup(); } ); ``` ## 自定义元素与 Svelte 自定义元素在 Svelte 中的创建已经彻底重写并大幅改进。\```` `标签选项已被弃用,转而使用新的``customElement``选项: ``` ```svelte ------ ++++++ ``` 此更改是为了允许[更多可配置性](custom-elements#Component-options)以适应高级用例。迁移脚本将自动调整您的代码。属性更新时间也略有变化。([#8457](https://github.com/sveltejs/svelte/issues/8457)) ## SvelteComponentTyped 已弃用 `SvelteComponentTyped` 已弃用,因为 `SvelteComponent` 现在已具备所有类型功能。将所有 `SvelteComponentTyped` 实例替换为 `SvelteComponent`。 ```js ---import { SvelteComponentTyped } from 'svelte';--- +++import { SvelteComponent } from 'svelte';+++ ---export class Foo extends SvelteComponentTyped<{ aProp: string }> {}--- +++export class Foo extends SvelteComponent<{ aProp: string }> {}+++ ``` 如果您之前已将`SvelteComponent`用作组件实例类型,现在可能会看到一些不太透明的类型错误,这可以通过将`: typeof SvelteComponent`更改为`: typeof SvelteComponent`来解决。 ```svelte ``` 迁移脚本将为您自动完成这两项。([#8512](https://github.com/sveltejs/svelte/issues/8512)) ## 默认情况下,转换是局部的 过渡现在默认为本地,以防止页面导航混淆。"本地"意味着如果过渡在嵌套控制流块(`each/if/await/key`)内而不是直接父块,而是在其上创建/销毁的块内,则不会播放。在以下示例中,`slide`引入动画仅在`success`从`false`变为`true`时播放,但*不会*在`show`从`false`变为`true`时播放: ```svelte {#if show} ... {#if success}

Success

{/each} {/if} ``` 为了使转换全局化,添加 `|global` 修饰符 - 然后,当创建/销毁 *任何* 控制流程块时,它们将播放。迁移脚本将自动为您完成此操作。([#6686](https://github.com/sveltejs/svelte/issues/6686)) ## 默认槽绑定 默认槽绑定不再暴露给命名槽,反之亦然: ```svelte

count in default slot - is available: {count}

count in bar slot - is not available: {count}

``` 这使插槽绑定更加一致,因为当默认插槽来自列表而命名插槽不是时,行为是未定义的。([#6049](https://github.com/sveltejs/svelte/issues/6049)) ## 预处理程序 预处理器的应用顺序已更改。现在,预处理器按顺序执行,在一个组内,顺序是标记、脚本、样式。 ```js // @errors: 2304 import { preprocess } from 'svelte/compiler'; const { code } = await preprocess( source, [ { markup: () => { console.log('markup-1'); }, script: () => { console.log('script-1'); }, style: () => { console.log('style-1'); } }, { markup: () => { console.log('markup-2'); }, script: () => { console.log('script-2'); }, style: () => { console.log('style-2'); } } ], { filename: 'App.svelte' } ); // Svelte 3 logs: // markup-1 // markup-2 // script-1 // script-2 // style-1 // style-2 // Svelte 4 logs: // markup-1 // script-1 // style-1 // markup-2 // script-2 // style-2 ``` 这可能会影响您,例如如果您正在使用`MDsveX` - 在这种情况下,您应确保它在任何脚本或样式预处理器之前。 ```js // @noErrors preprocess: [ --- vitePreprocess(), mdsvex(mdsvexConfig)--- +++ mdsvex(mdsvexConfig), vitePreprocess()+++ ] ``` 每个预处理器也必须有一个名称。([#8618](https://github.com/sveltejs/svelte/issues/8618)) ## 新 eslint 包 `eslint-plugin-svelte3` 已弃用。它可能与 Svelte 4 一起工作,但我们对此不提供任何保证。我们建议切换到我们新的包 [eslint-plugin-svelte](https://github.com/sveltejs/eslint-plugin-svelte)。有关迁移说明,请参阅 [此 Github 帖子](https://github.com/sveltejs/kit/issues/10242#issuecomment-1610798405)。或者,您可以使用 `npm create svelte@latest` 创建一个新项目,选择 eslint(以及可能 TypeScript)选项,然后将相关文件复制到您的现有项目中。 ## 其他重大变更 * the `inert` 属性现在应用于退出元素,使它们对辅助技术不可见并防止交互。([#8628](https://github.com/sveltejs/svelte/pull/8628)) * 运行时现在使用 `classList.toggle(name, boolean)` ,在非常旧的浏览器中可能不起作用。如果您需要支持这些浏览器,请考虑使用[polyfill](https://github.com/eligrey/classList.js)。([#8629](https://github.com/sveltejs/svelte/issues/8629)) * 运行时现在使用 `CustomEvent` 构造函数,这可能在不那么旧的浏览器中不起作用。如果您需要支持这些浏览器,请考虑使用 [polyfill](https://github.com/theftprevention/event-constructor-polyfill/tree/master)。([#8775](https://github.com/sveltejs/svelte/pull/8775)) * 人们现在使用从零开始构建自己的存储的 `StartStopNotifier` 接口(该接口传递给 `writable` 等创建函数)从 `svelte/store`,除了设置函数外,还需要传递一个更新函数。这对使用存储或使用现有 Svelte 存储创建存储的人没有影响。([#6750](https://github.com/sveltejs/svelte/issues/6750)) * `派生`现在将在传入的值不真实时引发错误,而不是存储传递给它的值。([编号#7947](https://github.com/sveltejs/svelte/issues/7947)) * 类型定义从 `svelte/internal` 中移除,以进一步阻止使用那些非公开 API 的内部方法。其中大部分在 Svelte 5 中可能会发生变化。 * 删除 DOM 节点现在已批量处理,这略微改变了其顺序,可能会影响您在这些元素上使用`MutationObserver`时事件的触发顺序([#8763](https://github.com/sveltejs/svelte/pull/8763)) * 如果您之前通过`svelte.JSX`命名空间增强了全局类型定义,则需要将其迁移到使用`svelteHTML`命名空间。同样,如果您使用了`svelte.JSX`命名空间来使用其中的类型定义,则需要将这些迁移到使用`svelte/elements`中的类型。更多关于如何操作的信息,请[在此处](https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#im-getting-deprecation-warnings-for-sveltejsx--i-want-to-migrate-to-the-new-typings)查找。