拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ONNX Runtime Web 导出功能端到端测试实践:基于 Next.js 与 Vite 的打包器兼容性验证

ONNX Runtime Web 导出功能端到端测试实践基于 Next.js 与 Vite 的打包器兼容性验证【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime导读onnxruntime-web 以纯 JavaScript/WebAssembly 方式在浏览器中运行 ONNX 模型但其 ESM 打包产物能否被主流前端打包器正确解析、拆分与加载直接影响开发者的集成体验。本文基于 ONNX Runtime 仓库中js/web/test/e2e/exports目录下的端到端测试工程系统讲解如何用 Next.jsApp Router 与 Turbopack和 ViteVue JavaScript两类真实脚手架项目配合 Puppeteer 自动化验证 onnxruntime-web 的导出功能。读完本文你将掌握这两套测试用例的工程结构、多线程与 proxy 两种运行时配置的验证方法以及如何在自己项目中复现同样的集成测试。测试背景为什么需要专门验证导出功能onnxruntime-web 的打包产物包含.mjs格式的 ES Module 文件与.wasm二进制资源。不同打包器对 ESM 的静态分析、依赖预构建pre-bundling与资源内联策略各不相同容易出现两类典型问题依赖预构建破坏 WebAssembly 加载如 Vite 在optimizeDeps阶段对使用 WebAssembly 的 npm 包进行预打包时可能出现加载异常这是 Vite 5.x 时期的已知问题测试工程中对此有专门处理详见后文SSR/CSR 上下文不匹配Next.js 默认在服务端渲染组件而 onnxruntime-web 依赖浏览器环境window、WebAssembly、SharedArrayBuffer等必须采用 CSR 组件或关闭 SSR 的动态导入方式。因此js/web/test/e2e/exports/README.md 专门建立一个独立的测试目录用两个真实脚手架应用nextjs-default 与 vite-default来覆盖最常见的 React 与 Vue 生态打包链路。测试工程总览整个导出测试位于仓库的 js/web/test/e2e/exports 目录结构如下js/web/test/e2e/exports/ ├── README.md # 测试说明与用例导航 ├── main.js # 测试入口安装依赖、调度 dev/prod 测试 ├── test.js # 测试执行启动服务器 Puppeteer 浏览器自动化 ├── utils.js # 通用工具shell 命令执行、依赖安装、进程树清理 └── testcases/ ├── nextjs-default.md # Next.js 用例说明 ├── vite-default.md # Vite 用例说明 ├── nextjs-default/ # Next.js 脚手架应用 └── vite-default/ # Vite 脚手架应用三个核心脚本各司其职形成一条清晰的测试流水线utils.js 中的installOrtPackages()负责在每个测试用例目录下安装依赖默认执行npm ci若传入额外包则执行npm installrunShellCmd()以子进程方式运行命令并通过事件机制感知服务器就绪main.js 作为入口按 nextjs-default → vite-default 的顺序依次调度各用例的 dev 测试、Turbopack 测试、生产构建测试及产物校验test.js 中的launchBrowserAndRunTests()使用puppeteer-core驱动本机 Chrome在页面上模拟用户点击并校验推理结果。nextjs-defaultNext.js 下的 onnxruntime-web 集成验证脚手架创建方式根据 nextjs-default.md 的记录该用例由npx create-next-applatest交互式生成创建参数如下全部保持默认值除项目名外均选 No√ What is your project named? ... nextjs-default √ Would you like to use TypeScript? ... No √ Would you like to use ESLint? ... No √ Would you like to use Tailwind CSS? ... No √ Would you like your code inside a src/ directory? ... No √ Would you like to use App Router? (recommended) ... No √ Would you like to use Turbopack for next dev? ... No √ Would you like to customize the import alias (/* by default)? ... No从 package.json 可以看到实际依赖为next^15.5.24、react^19.0.0、react-dom^19.0.0并保留了默认的dev/build/start三个脚本同时通过overrides固定了postcss版本保证脚手架在后续npm ci时可复现安装。虽然向导中选择不使用 App Router但当前代码实际上落在app/目录结构下app/layout.js与app/page.js这是测试随仓库演进的结果。基于模板的针对性改造在脚手架基础上测试工程做了两类改造两份用例文档描述一致清理删除默认的 Logo、图片、CSS 与 SVG避免无关资源干扰测试新增测试组件添加一个纯客户端渲染CSR组件内含一个多线程Multi-thread复选框#cb-mt一个代理Proxy复选框#cb-px一个 Load Model 按钮#btn-load一个 Run Model 按钮#btn-run一个状态显示 DIV#ortstate与一个日志显示 DIV#ortlog新增 helper 模块负责创建 ORT Session 并执行推理验证。改造后的 CSR 组件实现在 onnx-test-bar.js 中其关键点在于use client; import { useState } from react; export default function OnnxTestBar() { const [ortState, setOrtState] useState(0); const [ortLog, setOrtLog] useState(Ready.); ... const loadModel async () { setOrtState(1); ... const { createTestSession } await import(./onnx-helper); await createTestSession(document.getElementById(cb-mt).checked, document.getElementById(cb-px).checked); ... };组件用useState维护一个从 0 到 6 的状态机loadModel与runTest均通过动态import()按需加载 onnx-helper 模块——这既模拟了真实业务中按需加载 onnxruntime-web 的场景也验证了打包器对动态导入的正确切分。状态机的含义为状态值含义0初始就绪两个按钮可用1正在加载模型2模型加载成功激活 Run Test 按钮3模型加载失败日志区显示错误4正在运行推理测试5推理测试通过6推理测试失败在 page.js 中该组件通过next/dynamic并以ssr: false挂载这是 Next.js 中规避服务端渲染执行浏览器专属代码的标准做法use client; import dynamic from next/dynamic; const OnnxTestBarComponent dynamic(() import(../components/onnx-test-bar), { ssr: false }); export default function Home() { return ( div main OnnxTestBarComponent / /main /div ); }同时 next.config.mjs 保持默认空配置意味着这套测试覆盖的是 Next.js无自定义 webpack 配置时的开箱即用导出行为。onnx-helper会话创建与推理验证onnx-helper.js 是验证逻辑的核心它演示了 onnxruntime-web 的两个关键运行时开关import * as ort from onnxruntime-web; export const createTestSession async (multiThreaded, proxy) { const model base64StringToUint8Array(testModelData); const options {}; if (multiThreaded) { ort.env.wasm.numThreads 2; assert(typeof SharedArrayBuffer ! undefined, SharedArrayBuffer is not supported); } if (proxy) { ort.env.wasm.proxy true; } mySession await ort.InferenceSession.create(model, options); };多线程ort.env.wasm.numThreads 2启用 WASM 多线程需要页面具备SharedArrayBuffer能力即必须通过 COOP/COEP 响应头开启跨源隔离cross-origin isolation。代码在启用前用assert显式检查SharedArrayBuffer是否存在这正是浏览器端多线程最容易被忽视的前置条件代理ort.env.wasm.proxy true将 onnxruntime-web 的 WASM 计算放入独立 Web Worker 中执行避免阻塞主线程这是生产环境提升 UI 流畅度的常见配置。模型数据采用内联 base64 字符串解码为Uint8Array测试模型为test_abs/model.onnx对应 Abs 算子因此无需网络请求即可加载测试更稳定。推理验证部分构造 60 个正负交替的浮点数形状[3, 4, 5]运行模型后逐元素断言输出等于输入的绝对值const inputData [...Array(60).keys()].map((i) (i % 2 0 ? i : -i)); const expectedOutputData inputData.map((i) Math.abs(i)); const fetches await mySession.run({ x: new ort.Tensor(float32, inputData, [3, 4, 5]) }); const y fetches.y; assert(y instanceof ort.Tensor, unexpected result); assert(y.dims.length 3 y.dims[0] 3 y.dims[1] 4 y.dims[2] 5, incorrect shape); for (let i 0; i expectedOutputData.length; i) { assert(y.data[i] expectedOutputData[i], output data mismatch at index ${i}); } return PASS;这里同时校验了输出张量的类型、维度[3, 4, 5]与 60 个数值的逐项正确性属于端到端级别的结果验证。测试矩阵根据文档nextjs-default 用例在三种服务器模式下分别跑 2×2 全组合服务器模式组合说明npm run dev多线程 OFF/ON × 代理 OFF/ON开发服务器npm run dev -- --turbopack多线程 OFF/ON × 代理 OFF/ON开发服务器Turbopacknpm run buildnpm run start多线程 OFF/ON × 代理 OFF/ON生产模式其中npm run dev -- --turbopack专门覆盖 Next.js 的 Rust 版打包器 Turbopack验证其在开发模式下对 onnxruntime-web 的处理生产模式则验证next build产物含资源指纹与代码分割在next start下可正常运行。vite-defaultVite Vue 下的集成验证脚手架创建方式vite-default.md 记录该用例由npm create vitelatest生成选择了 Vue 框架与 JavaScript 变体√ Project name: ... vite-default √ Select a framework: » Vue √ Select a variant: » JavaScript生成后按提示cd vite-default npm install npm run dev即可启动。模板改造与 Vite 关键配置改造内容与 nextjs-default 一致删除默认 Logo/图片/CSS/SVG新增包含两个复选框、两个按钮、状态 DIV 与日志 DIV 的 CSR 组件并添加同构的 onnx-helper 模块onnx-helper.js 与 Next.js 版逻辑完全相同会话创建、多线程/proxy 开关、Abs 模型推理验证均一致。页面侧的逻辑落在 Vue 的 HelloWorld.vue 中同样通过动态import(./onnx-helper)按需加载。Vite 版最重要的差异化配置在 vite.config.jsimport { defineConfig } from vite; import vue from vitejs/plugin-vue; export default defineConfig({ // This is a known issue when using WebAssembly with Vite 5.x // Need to specify optimizeDeps.exclude to NPM packages that uses WebAssembly // See: https://github.com/vitejs/vite/issues/8427 optimizeDeps: { exclude: [onnxruntime-web], }, plugins: [vue()], });optimizeDeps.exclude: [onnxruntime-web]是这套用例验证的重点Vite 默认会对依赖进行预构建esbuild 预打包而使用 WebAssembly 的包在预构建阶段存在已知兼容问题必须将其排除在预构建之外让 onnxruntime-web 以原生 ESM 方式被浏览器直接加载。该配置项也因此成为onnxruntime-web Vite集成的必备配置。测试矩阵与产物校验vite-default 的测试矩阵略少于 Next.js无 Turbopack 变体模式组合端口npm run dev多线程 OFF/ON × 代理 OFF/ON5173npm run buildnpm run start多线程 OFF/ON × 代理 OFF/ON4173除此之外main.js 在 vite-default 的生产构建完成后还执行了一次产物校验verifyAssetsawait verifyAssets(vite-default, async (cwd) { const globby await import(globby); return { test: File dist/assets/**/ort.*.mjs should not exist, success: globby.globbySync(dist/assets/**/ort.*.mjs, { cwd }).length 0, }; });该断言检查生产构建产物dist/assets/下不应残留独立的ort.*.mjs文件——如果 onnxruntime-web 的 ESM 产物未被正确合并进 chunk就会在dist/assets中出现独立的ort.*.mjs资源说明打包器对 onnxruntime-web 的导出处理异常。这是对导出功能最直接的产物级验证也是本测试目录命名的由来。端到端执行原理Puppeteer 驱动浏览器模拟test.js 中的launchBrowserAndRunTests()负责整个浏览器自动化流程其完整链路为用puppeteer-core启动本机 Chromeheadless: true并附加--enable-featuresSharedArrayBuffer启动参数保证多线程用例可用与 onnx-helper 中的 SharedArrayBuffer 检查呼应打开http://localhost:port等待#ortstate可见根据组合勾选#cb-mt多线程与#cb-px代理复选框点击#btn-load用waitForFunction等待ortstate进入2成功或3失败若失败则从#ortlog读取错误日志点击#btn-run等待ortstate进入5通过或6失败同样读取#ortlog定位问题汇总四条组合的结果任一失败即整体判定该模式测试失败。服务器侧的编排在runTest()中先用runShellCmd以子进程方式启动npm run dev或npm run start通过监听 stdout 中特定就绪字符串来感知服务器可用——Next.js 的就绪标志是✓ Ready inVite 的就绪标志是终端带颜色的➜ Local:代码中以转义序列\x1b[32m➜\x1b[39m匹配收到就绪事件后立即执行浏览器测试结束后通过tree-kill递归杀掉整个进程树防止端口残留。生产模式runProdTest则先执行npm run build再对next start/vite preview启动的服务器跑同一套浏览器用例。本地复现与扩展指南在具备 Node.js 与 Chrome 环境的前提下可按以下步骤复现这套导出测试确认测试入口整体入口为 main.js 的main(PRESERVE, PACKAGES_TO_INSTALL)函数PRESERVE为真时跳过依赖安装PACKAGES_TO_INSTALL用于指定额外安装的包如指向本地构建的 onnxruntime-web tarball安装依赖首次运行会依次在testcases/nextjs-default与testcases/vite-default下执行npm ci或按传入参数执行npm install pkg由于 onnxruntime-web 依赖外置 npm 包建议结合构建脚本将仓库内最新构建的包注入PACKAGES_TO_INSTALL以验证本地改动运行测试脚本会依次执行——nextjs-default 的 dev 模式含 Turbopack与生产模式、vite-default 的 dev 与生产模式以及 vite-default 的dist产物校验每轮四组合全部通过才算成功按需扩展如需覆盖更多打包器或框架如 Svelte、Astro、Webpack 5 手动配置可参照现有两个用例的模式——用官方脚手架生成项目 → 添加相同的 CSR 测试组件与 onnx-helper 模块 → 在 main.js 中注册runDevTest/runProdTest必要时补充verifyAssets产物断言即可复用同一套 Puppeteer 自动化框架。小结onnxruntime-web 的导出功能测试并不是简单的能否 import而是通过两个贴近真实工程的最小脚手架覆盖了三大类集成风险WebAssembly 依赖的预构建冲突ViteoptimizeDeps.exclude、SSR/CSR 环境隔离Next.jsdynamicssr: false、多线程与代理等运行时开关SharedArrayBuffer、numThreads、proxy。配合 Puppeteer 的 2×2 组合矩阵与产物级断言为 onnxruntime-web 的每个发布版本提供了可靠的打包器兼容性保障也为使用 React/Vue 生态的开发者提供了可直接借鉴的集成样板。【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门