使用Huggingface Transformers.js客户端推理时遇window未定义错误
问题:Transformers.js在Next.js中运行时抛出"window未定义"错误
我是Transformers.js新手,这个库基于ONNX Runtime在浏览器中运行大模型。严格按照官方Next.js教程操作后,遇到了运行错误。
复现步骤
- 在VSCode中执行命令:
npx create-next-app@latest
应用名称可自定义。
- 创建应用时的配置选项如下:
√ 你的项目名称是什么?... next √ 是否使用TypeScript?... 否/是 √ 是否使用ESLint?... 否/是 √ 是否使用Tailwind CSS?... 否/是 √ 是否使用`src/`目录?... 否/是 √ 是否使用App Router?(推荐)... 否/是 √ 是否自定义默认导入别名?... 否/是
- 安装Transformers.js:
npm i @xenova/transformers
- 替换
next.config.mjs内容为:
/** @type {import('next').NextConfig} */ const nextConfig = { // (可选)导出为静态站点 output: 'export', // 可根据需要修改或移除该选项 // 覆盖默认webpack配置 webpack: (config) => { config.resolve.alias = { ...config.resolve.alias, "sharp$": false, "onnxruntime-node$": false, } return config; }, } export default nextConfig
- 创建
src/app/worker.js文件,代码如下:
import { pipeline, env } from "@xenova/transformers"; // 跳过本地模型检查 env.allowLocalModels = false; // 使用单例模式延迟构建pipeline class PipelineSingleton { static task = 'text-classification'; static model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english'; static instance = null; static async getInstance(progress_callback = null) { if (this.instance === null) { this.instance = pipeline(this.task, this.model, { progress_callback }); } return this.instance; } } // 监听主线程消息 self.addEventListener('message', async (event) => { // 获取分类pipeline,首次调用时会加载模型并缓存 let classifier = await PipelineSingleton.getInstance(x => { // 添加进度回调以跟踪模型加载状态 self.postMessage(x); }); // 执行文本分类 let output = await classifier(event.data.text); // 将结果发送回主线程 self.postMessage({ status: 'complete', output: output, }); });
- 替换
/src/app/page.js内容为:
'use client' import { useState, useEffect, useRef, useCallback } from 'react' export default function Home() { // 跟踪分类结果和模型加载状态 const [result, setResult] = useState(null); const [ready, setReady] = useState(null); // 创建Worker对象引用 const worker = useRef(null); // 组件挂载时初始化Worker useEffect(() => { if (!worker.current) { // 若Worker不存在则创建 worker.current = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' }); } // 处理Worker线程的消息回调 const onMessageReceived = (e) => { switch (e.data.status) { case 'initiate': setReady(false); break; case 'ready': setReady(true); break; case 'complete': setResult(e.data.output[0]) break; } }; // 添加消息监听 worker.current.addEventListener('message', onMessageReceived); // 组件卸载时清理监听 return () => worker.current.removeEventListener('message', onMessageReceived); }); const classify = useCallback((text) => { if (worker.current) { worker.current.postMessage({ text }); } }, []); return ( <main className="flex min-h-screen flex-col items-center justify-center p-12"> <h1 className="text-5xl font-bold mb-2 text-center">Transformers.js</h1> <h2 className="text-2xl mb-4 text-center">Next.js模板</h2> <input className="w-full max-w-xs p-2 border border-gray-300 rounded mb-4" type="text" placeholder="在此输入文本" onInput={e => { classify(e.target.value); }} /> {ready !== null && ( <pre className="bg-gray-100 p-2 rounded"> {(!ready || !result) ? '加载中...' : JSON.stringify(result, null, 2)} </pre> )} </main> ) }
- 执行
npm run dev启动应用,刷新localhost:3000后,Chrome控制台出现如下错误:
错误栈跟踪
未捕获的引用错误:window未定义 at 9693 (ort-web.min.js:5035:333) at __nested_webpack_require_1009257__ (ort-web.min.js:15255:43) at 1173 (ort-web.min.js:5086:28) at __nested_webpack_require_1009257__ (ort-web.min.js:15255:43) at 9482 (ort-web.min.js:4752:49) at __nested_webpack_require_1009257__ (ort-web.min.js:15255:43) at 2100 (ort-web.min.js:4744:29) at __nested_webpack_require_1009257__ (ort-web.min.js:15255:43) at 1446 (ort-web.min.js:3450:34) at __nested_webpack_require_1009257__ (ort-web.min.js:15255:43) 9693 @ ort-web.min.js:5035 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 1173 @ ort-web.min.js:5086 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 9482 @ ort-web.min.js:4752 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 2100 @ ort-web.min.js:4744 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 1446 @ ort-web.min.js:3450 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 9162 @ ort-web.min.js:13374 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 8316 @ ort-web.min.js:6520 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 6416 @ ort-web.min.js:10163 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 5038 @ ort-web.min.js:5503 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 7091 @ ort-web.min.js:5466 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 6919 @ ort-web.min.js:13253 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 7714 @ ort-web.min.js:5212 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 6018 @ ort-web.min.js:5261 __nested_webpack_require_1009257__ @ ort-web.min.js:15255 eval @ ort-web.min.js:15281 eval @ ort-web.min.js:15283 eval @ ort-web.min.js:8 eval @ ort-web.min.js:10 (app-pages-browser)/./node_modules/onnxruntime-web/dist/ort-web.min.js @ _app-pages-browser_src_app_worker_js.js:275 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 fn @ _app-pages-browser_src_app_worker_js.js:712 eval @ onnx.js:9 (app-pages-browser)/./node_modules/@xenova/transformers/src/backends/onnx.js @ _app-pages-browser_src_app_worker_js.js:308 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 fn @ _app-pages-browser_src_app_worker_js.js:712 eval @ env.js:8 (app-pages-browser)/./node_modules/@xenova/transformers/src/env.js @ _app-pages-browser_src_app_worker_js.js:330 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 fn @ _app-pages-browser_src_app_worker_js.js:712 eval @ hub.js:10 (app-pages-browser)/./node_modules/@xenova/transformers/src/utils/hub.js @ _app-pages-browser_src_app_worker_js.js:440 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 fn @ _app-pages-browser_src_app_worker_js.js:712 eval @ tokenizers.js:48 (app-pages-browser)/./node_modules/@xenova/transformers/src/tokenizers.js @ _app-pages-browser_src_app_worker_js.js:374 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 fn @ _app-pages-browser_src_app_worker_js.js:712 eval @ pipelines.js:29 (app-pages-browser)/./node_modules/@xenova/transformers/src/pipelines.js @ _app-pages-browser_src_app_worker_js.js:352 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 fn @ _app-pages-browser_src_app_worker_js.js:712 eval @ transformers.js:450 (app-pages-browser)/./node_modules/@xenova/transformers/src/transformers.js @ _app-pages-browser_src_app_worker_js.js:385 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 fn @ _app-pages-browser_src_app_worker_js.js:712 eval @ worker.js:2 (app-pages-browser)/./src/app/worker.js @ _app-pages-browser_src_app_worker_js.js:286 options.factory @ _app-pages-browser_src_app_worker_js.js:1057 __webpack_require__ @ _app-pages-browser_src_app_worker_js.js:503 (anonymous) @ _app-pages-browser_src_app_worker_js.js:1655 (anonymous) @ _app-pages-browser_src_app_worker_js.js:1658 显示36更多帧 显示更少
解决方案
错误核心原因是:Next.js构建Worker时,默认会在服务端环境处理相关代码,但onnxruntime-web依赖浏览器环境的window对象,导致服务端渲染时抛出错误。可通过以下方式修复:
方案1:修改webpack配置,隔离服务端与浏览器代码
更新next.config.mjs:
/** @type {import('next').NextConfig} */ const nextConfig = { output: 'export', webpack: (config, { isServer }) => { // 服务端构建时排除onnxruntime-web if (isServer) { config.externals.push('onnxruntime-web'); } config.resolve.alias = { ...config.resolve.alias, "sharp$": false, "onnxruntime-node$": false, }; // 配置Worker加载规则 config.module.rules.push({ test: /worker\.js$/, use: { loader: 'worker-loader', options: { inline: 'fallback' } } }); return config; }, } export default nextConfig
然后安装依赖:
npm install worker-loader --save-dev
最后修改page.js中的Worker创建代码:
import Worker from './worker.js'; worker.current = new Worker();
方案2:在Worker中添加环境判断
在worker.js顶部添加判断,确保只在浏览器环境执行代码:
if (typeof window === 'undefined') { module.exports = {}; return; } import { pipeline, env } from "@xenova/transformers"; // 剩余代码保持不变
额外建议
检查@xenova/transformers版本,升级到最新版,新版本可能已修复Next.js环境兼容问题。
内容的提问来源于stack exchange,提问作者Koushik Sarkar
相关产品推荐
相关产品推荐

