在SvelteKit中集成Whisper.cpp流式WebAssembly语音识别时遇到Web Worker启动失败问题
看起来你已经做了不少基础工作:把核心文件移到static目录、修改app.html、禁用SSR、配置跨域头,但Web Worker就是没正常启动——这种情况我之前在集成Wasm+Worker到框架里也碰到过,大概率是路径或者框架加载逻辑的问题。下面是几个针对性的排查和修复步骤:
1. 先确认Worker文件的路径是否正确
Whisper的stream.js里肯定有创建Worker的代码,比如类似new Worker('libstream.worker.js')的语句。在SvelteKit里,静态文件的根路径是/,所以如果你的libstream.worker.js放在static目录下,必须用绝对路径来引用它,否则在不同路由下会找不到文件。
打开stream.js,找到创建Worker的地方,把相对路径改成绝对路径:
// 原来的代码可能是这样 // const worker = new Worker('libstream.worker.js'); // 改成绝对路径 const worker = new Worker('/libstream.worker.js');
改完后刷新页面,打开浏览器DevTools的Network标签,看看libstream.worker.js是不是能正常加载(状态码200)。如果还是404,那就是路径没写对,再检查文件位置。
2. 调整app.html里的脚本加载顺序
你把原来的index.html内容整合到了app.html,但要注意SvelteKit的%sveltekit.body%是应用内容的入口点,建议把stream.js的脚本标签放在%sveltekit.body%之后,或者加上defer属性,确保DOM加载完成后再初始化Wasm和Worker:
<!-- 在app.html的body末尾添加 --> <script src="/stream.js" defer></script>
这样可以避免因为DOM元素还没加载就执行stream.js里的代码,导致后续Worker初始化失败。
3. 验证Security Headers是否生效
你在hooks.server.ts里设置了Cross-Origin-Opener-Policy和Cross-Origin-Embedder-Policy,这两个头是Wasm共享内存必须的,但要确认它们确实被加到了响应头里。
打开DevTools的Network标签,刷新页面,查看主页面的响应头,确认这两个头存在:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
如果没有,检查hooks.server.ts的代码是否正确,比如有没有拼写错误,或者SvelteKit版本有没有特殊的处理方式(比如某些版本需要用handleFetch或者其他钩子)。
4. 给Worker加调试日志,确认是否启动
如果前面的步骤都做了还是不行,那我们直接给Worker加日志,看看它到底有没有被执行。
打开libstream.worker.js,在文件最顶部添加:
console.log('Worker: 我启动啦!'); // 再给主线程发个消息确认 self.postMessage({ cmd: 'debug', message: 'Worker initialized successfully' });
然后在stream.js的worker.onmessage里加个处理这个debug消息的分支:
worker.onmessage = e => { var d = e["data"]; var cmd = d["cmd"]; // ... 原来的其他处理逻辑 ... else if (cmd === "debug") { console.log('主线程收到Worker的消息:', d.message); } // ... 原来的其他处理逻辑 ... };
刷新页面后看控制台,如果能看到Worker的日志,说明Worker已经启动了,那问题可能出在后续的Wasm加载或者消息通信上;如果看不到,那就是Worker根本没被正确创建,回到第一步检查路径。
5. 尝试禁用SvelteKit的Dev Server优化(临时)
有时候SvelteKit的dev server会对静态文件做一些优化,可能影响Worker的加载。可以尝试在svelte.config.js里添加一些配置,关闭不必要的优化:
import adapter from '@sveltejs/adapter-auto'; import { vitePreprocess } from '@sveltejs/kit/vite'; /** @type {import('@sveltejs/kit').Config} */ const config = { preprocess: vitePreprocess(), kit: { adapter: adapter(), vite: { server: { fs: { allow: ['static'], // 确保静态目录被允许访问 }, }, }, }, }; export default config;
做完这些步骤,应该能解决Worker启动失败的问题。如果还是不行,再检查DevTools的Console标签里有没有其他更详细的错误信息,比如Worker加载时的语法错误或者权限问题。
备注:内容来源于stack exchange,提问作者rahokey531

