Svelte 构建后按钮无响应
experimental.async 顶层 await 后取得的回调,旧 Svelte 生产编译可能过早读成 undefined。核对 5.57.2 修复与实际生产事件接线。
开发环境按钮可以触发回调,生产构建后点击却完全没反应,控制台也没有错误。若组件开启了 experimental.async,并在顶层 await 之后通过函数调用取得事件处理器,需要检查生产编译产物有没有过早读取这个变量。
Svelte 5.57.1 存在对应的编译缺口。正式版 5.57.2 修正了带异步 blocker 的事件处理器读取,不能把它当作所有按钮失效或 hydration 错误的统一原因。
回调尚未赋值,事件已经接线
一个说明条件的组件是:
<script>
const makeHandler = () => () => console.log('clicked');
await Promise.resolve();
const onclick = makeHandler();
</script>
<button {onclick}>点击</button>
它需要在应用已有的 Svelte 编译配置中启用 experimental.async。这项特性仍有实验边界,不能因为示例用了顶层 await,就把所有项目默认切到异步编译模式。
旧生产编译把 await 后面的赋值放进异步执行分支,却在连接事件时直接传入 onclick。当时变量仍是 undefined,所以按钮没有实际可调用的处理器,也不一定抛出异常。
开发构建会通过包装器在事件发生时再读取变量,因而能表现正常。只在开发页面点击成功,无法覆盖这条生产 shortcut。
核对处理器来自哪里
需要同时确认顶层 await、后面的调用赋值,以及事件属性读取这个变量。函数声明、直接写出的箭头函数,与调用工厂函数取得的值,不一定走同一编译路径。
也要排除应用把 handler 改成了空值、元素被遮挡、事件被阻止传播,或页面根本没有加载到正确客户端脚本。生产静默失效只是症状,编译后的变量赋值与事件接线顺序才是这条问题的判断依据。
同样条件不只可能影响 click 委托事件。非委托事件和 <svelte:window> 的处理器也需要按实际使用检查;不能因为换了事件目标就断定绕过了编译缺口。
使用保留延迟读取的正式编译器
5.57.2 在判断局部标识符可否直接用作 handler 时,排除了带 blocker 的绑定,让它进入原有的包装路径。这样事件发生时读取已经赋值的处理器;没有这个异步条件的普通组件仍使用原来的优化。
沿框架与插件支持的兼容路径升级后,重新生成生产资源,确认实际发布的客户端脚本来自该编译器。只更换开发服务的依赖、不更新生产产物,不会改变旧页面的接线代码。
若暂时需要应用级调整,应保留回调的参数、this 需求和赋值前提。不能把工厂调用盲目移到 await 之前,那里可能还没有它所需的数据;也不能用一个丢弃事件参数的包装器修复真实业务回调。
验收实际生产产物
在受控环境中用项目原有方式构建和预览生产资源,等待相关异步数据完成后点击,确认业务回调真正运行。再检查已有的非委托或 window 事件,以及普通没有顶层 await 的组件。
控制台没有报错,只能说明没有显示异常。需要确认事件确实到达原处理函数、参数正确且没有重复调用,才能判断这个静默失败已被处理。


