Skip to main content

其他

Svelte 4 迁移指南

本迁移指南概述了如何从 Svelte 版本 3 迁移到 4。 有关每项更改的更多详细信息,请参阅链接的 PR。 使用迁移脚本自动迁移其中一些: npx svelte-migrate@latest svelte-4

This migration guide provides an overview of how to migrate from Svelte version 3 to 4. See the linked PRs for more details about each change. Use the migration script to migrate some of these automatically: npx svelte-migrate@latest svelte-4

如果你是库作者,请考虑是否仅支持 Svelte 4 或者是否也可以支持 Svelte 3。 由于大多数重大更改不会影响很多人,因此这很容易实现。 另请记住更新 peerDependencies 中的版本范围。

If you're a library author, consider whether to only support Svelte 4 or if it's possible to support Svelte 3 too. Since most of the breaking changes don't affect many people, this may be easily possible. Also remember to update the version range in your peerDependencies.

最低版本要求(Minimum version requirements)

  • 升级到节点 16 或更高版本。 不再支持早期版本。 (#8566)
  • 如果你使用的是 SvelteKit,请升级到 1.20.4 或更高版本 (sveltejs/kit#10172)
  • 如果你在没有 SvelteKit 的情况下使用 Vite,请升级到 vite-plugin-svelte 2.4.1 或更高版本 (#8516)
  • 如果你使用的是 webpack,请升级到 webpack 5 或更高版本以及 svelte-loader 3.1.8 或更高版本。 不再支持早期版本。 (#8515198dbcf
  • 如果你使用的是 Rollup,请升级到 rollup-plugin-svelte 7.1.5 或更高版本 (198dbcf)
  • 如果你使用的是 TypeScript,请升级到 TypeScript 5 或更高版本。 较低版本可能仍然有效,但对此不做任何保证。 (#8488)

打包器的浏览器条件(Browser conditions for bundlers)

现在,打包程序在为浏览器构建前端打包包时必须指定 browser 条件。 SvelteKit 和 Vite 会自动为你处理这个问题。 如果你使用其他任何方法,你可能会观察到生命周期回调(例如 onMount)未被调用,并且你需要更新模块解析配置。

Bundlers must now specify the browser condition when building a frontend bundle for the browser. SvelteKit and Vite will handle this automatically for you. If you're using any others, you may observe lifecycle callbacks such as onMount not get called and you'll need to update the module resolution configuration.

  • 对于 Rollup,这是通过在 @rollup/plugin-node-resolve 插件的选项中设置 browser: true 来完成的。 有关更多详细信息,请参阅 rollup-plugin-svelte 文档
  • 对于 wepback,这是通过将 "browser" 添加到 conditionNames 数组来完成的。 如果你已设置,你可能还需要更新 alias 配置。 有关更多详细信息,请参阅 svelte-loader 文档

(#8516)

(#8516)

Svelte 不再支持 CommonJS (CJS) 编译器输出格式,并且还删除了 svelte/register 钩子和 CJS 运行时版本。 如果你需要保留 CJS 输出格式,请考虑使用打包器在构建后步骤中将 Svelte 的 ESM 输出转换为 CJS。 (#8613)

Svelte no longer supports the CommonJS (CJS) format for compiler output and has also removed the svelte/register hook and the CJS runtime version. If you need to stay on the CJS output format, consider using a bundler to convert Svelte's ESM output to CJS in a post-build step. (#8613)

Svelte 函数的更严格类型(Stricter types for Svelte functions)

现在 createEventDispatcherActionActionReturnonMount 有更严格的类型:

There are now stricter types for createEventDispatcher, Action, ActionReturn, and onMount:

  • createEventDispatcher 现在支持指定有效负载是可选的、必需的或不存在的,并相应地检查调用站点 (#7224)
ts
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
optional: number | null;
required: string;
noArgument: null;
}>();
Expected 2-3 arguments, but got 1.2554Expected 2-3 arguments, but got 1.
Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.2345Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.
// Svelte version 3:
dispatch('optional');
dispatch('required'); // I can still omit the detail argument
dispatch('noArgument', 'surprise'); // I can still add a detail argument
Expected 2-3 arguments, but got 1.2554Expected 2-3 arguments, but got 1.
Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.2345Argument of type '"surprise"' is not assignable to parameter of type 'null | undefined'.
// Svelte version 4 using TypeScript strict mode:
dispatch('optional');
dispatch('required'); // error, missing argument
dispatch('noArgument', 'surprise'); // error, cannot pass an argument
  • ActionActionReturn 现在的默认参数类型为 undefined,这意味着如果要指定此操作接收参数,则需要键入泛型。 迁移脚本将自动迁移此内容 (#7442)
const action: Action = (node, params) => { .. } // this is now an error if you use params in any way
const action: Action<HTMLElement, string> = (node, params) => { .. } // params is of type string
  • 如果你从中异步返回函数,onMount 现在会显示类型错误,因为这可能是代码中的错误,你希望在销毁时调用回调,而这只对同步返回的函数执行此操作 (#8136)
// 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 自定义元素(Custom Elements with Svelte)

使用 Svelte 创建自定义元素已经过彻底修改并显着改进。 tag 选项已弃用,取而代之的是新的 customElement 选项:

The creation of custom elements with Svelte has been overhauled and significantly improved. The tag option is deprecated in favor of the new customElement option:

<svelte:options tag="my-component" />
<svelte:options customElement="my-component" />

进行此更改是为了允许 更多可配置性 用于高级用例。 迁移脚本将自动调整你的代码。 属性的更新时间也略有变化。 (#8457)

This change was made to allow more configurability for advanced use cases. The migration script will adjust your code automatically. The update timing of properties has changed slightly as well. (#8457)

SvelteComponentTyped 已弃用(SvelteComponentTyped is deprecated)

SvelteComponentTyped 已弃用,因为 SvelteComponent 现在具有其所有类型功能。 将 SvelteComponentTyped 的所有实例替换为 SvelteComponent

SvelteComponentTyped is deprecated, as SvelteComponent now has all its typing capabilities. Replace all instances of SvelteComponentTyped with SvelteComponent.

 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<any> 可以解决此问题。

If you have used SvelteComponent as the component instance type previously, you may see a somewhat opaque type error now, which is solved by changing : typeof SvelteComponent to : typeof SvelteComponent<any>.

<script>
  import ComponentA from './ComponentA.svelte';
  import ComponentB from './ComponentB.svelte';
  import { SvelteComponent } from 'svelte';

  let component: typeof SvelteComponent;
  let component: typeof SvelteComponent<any>;

  function choseRandomly() {
	component = Math.random() > 0.5 ? ComponentA : ComponentB;
  }
</script>

<button on:click={choseRandomly}>random</button>
<svelte:element this={component} />

迁移脚本将自动为你执行这两项操作。 (#8512)

The migration script will do both automatically for you. (#8512)

默认情况下,转场是本地的(Transitions are local by default)

现在默认情况下,转场是本地的,以防止页面导航发生混乱。 "local" 意味着如果转换位于嵌套控制流块 (each/if/await/key) 内且不是直接父块但创建/销毁了其上方的块,则该转换将不会播放。 在以下示例中,slide 介绍动画仅在 successfalsetrue 时播放,但在 showfalsetrue 时不会播放:

Transitions are now local by default to prevent confusion around page navigations. "local" means that a transition will not play if it's within a nested control flow block (each/if/await/key) and not the direct parent block but a block above it is created/destroyed. In the following example, the slide intro animation will only play when success goes from false to true, but it will not play when show goes from false to true:

{#if show}
	...
	{#if success}
		<p in:slide>Success</p>
	{/each}
{/if}

要使转换全局化,请添加 |global 修饰符 - 然后它们将在创建/销毁上面的任何控制流块时播放。 迁移脚本将自动为你执行此操作。 (#6686)

To make transitions global, add the |global modifier - then they will play when any control flow block above is created/destroyed. The migration script will do this automatically for you. (#6686)

默认插槽绑定(Default slot bindings)

默认槽绑定不再暴露给命名槽,反之亦然:

Default slot bindings are no longer exposed to named slots and vice versa:

<script>
	import Nested from './Nested.svelte';
</script>

<Nested let:count>
	<p>
		count in default slot - is available: {count}
	</p>
	<p slot="bar">
		count in bar slot - is not available: {count}
	</p>
</Nested>

这使得槽绑定更加一致,因为当默认槽来自列表而命名槽不是时,行为是未定义的。 (#6049)

This makes slot bindings more consistent as the behavior is undefined when for example the default slot is from a list and the named slot is not. (#6049)

预处理器(Preprocessors)

应用预处理器的顺序已更改。 现在,预处理器按顺序执行,在一组内,顺序是标记、脚本、样式。

The order in which preprocessors are applied has changed. Now, preprocessors are executed in order, and within one group, the order is markup, script, style.

ts
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,这可能会影响你 - 在这种情况下,你应该确保它出现在任何脚本或样式预处理器之前。

This could affect you for example if you are using MDsveX - in which case you should make sure it comes before any script or style preprocessor.

preprocess: [
	vitePreprocess(),
	mdsvex(mdsvexConfig)
	mdsvex(mdsvexConfig),
	vitePreprocess()
]

每个预处理器还必须有一个名称。 (#8618)

Each preprocessor must also have a name. (#8618)

新的 eslint 包(New eslint package)

eslint-plugin-svelte3 已弃用。 它可能仍然适用于 Svelte 4,但我们对此不做任何保证。 我们建议切换到我们的新软件包 eslint-plugin-svelte。 有关如何迁移的说明,请参阅 这个 Github 帖子。 或者,你可以使用 npm create svelte@latest 创建一个新项目,选择 eslint(可能还有 TypeScript)选项,然后将相关文件复制到现有项目中。

eslint-plugin-svelte3 is deprecated. It may still work with Svelte 4 but we make no guarantees about that. We recommend switching to our new package eslint-plugin-svelte. See this Github post for an instruction how to migrate. Alternatively, you can create a new project using npm create svelte@latest, select the eslint (and possibly TypeScript) option and then copy over the related files into your existing project.

其他重大变更(Other breaking changes)

  • inert 属性现在应用于外部元素,使它们对辅助技术不可见并阻止交互。 (#8628)
  • 运行时现在使用 classList.toggle(name, boolean),这可能无法在非常旧的浏览器中运行。 如果你需要支持这些浏览器,请考虑使用 polyfill。 (#8629)
  • 运行时现在使用 CustomEvent 构造函数,该构造函数可能无法在非常旧的浏览器中工作。 如果你需要支持这些浏览器,请考虑使用 polyfill。 (#8775)
  • 人们使用 svelte/store 中的 StartStopNotifier 接口(传递给 writable 等的创建函数)从头开始实现自己的存储,现在除了设置函数之外还需要传递更新函数。 这对使用存储或使用现有 Svelte 存储创建存储的人没有影响。 (#6750)
  • derived 现在将在错误值上抛出错误,而不是传递给它的存储。 (#7947)
  • 删除了 svelte/internal 的类型定义,以进一步阻止使用那些非公共 API 的内部方法。 其中大部分可能会在 Svelte 5 中发生变化
  • 现在批量删除 DOM 节点,这会稍微改变其顺序,如果你在这些元素上使用 MutationObserver (#8763),这可能会影响触发事件的顺序
  • 如果你之前通过 svelte.JSX 命名空间增强了全局类型,则需要将其迁移到使用 svelteHTML 命名空间。 同样,如果你使用 svelte.JSX 命名空间来使用其中的类型定义,则需要迁移这些命名空间以使用 svelte/elements 中的类型。 你可以找到有关如何执行 here 的更多信息
上一页 TypeScript
下一页 svelte/register