Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web Worker Incompatibility with Vite Bundler #15

Open
Interpause opened this issue Mar 29, 2022 · 8 comments
Open

Web Worker Incompatibility with Vite Bundler #15

Interpause opened this issue Mar 29, 2022 · 8 comments
Assignees

Comments

@Interpause
Copy link

When using Vite to bundle onnxruntime-web into my project, I face the following error when attempting to import it.

✘ [ERROR] Could not resolve "worker-loader?inline=no-fallback!./proxy-worker/main"

    .yarn/cache/onnxruntime-web-npm-1.11.0-a6a06c5230-b03ff8acb3.zip/node_modules/onnxruntime-web/lib/wasm/proxy-wrapper.js:123:34:
      123 │ ... proxyWorker = require('worker-loader?inline=no-fallback!./proxy-worker/main').default();~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  You can mark the path "worker-loader?inline=no-fallback!./proxy-worker/main" as external to
  exclude it from the bundle, which will remove this error. You can also surround this "require"
  call with a try/catch block to handle this failure at run-time instead of bundle-time.

error when starting dev server:
Error: Build failed with 1 error:
.yarn/cache/onnxruntime-web-npm-1.11.0-a6a06c5230-b03ff8acb3.zip/node_modules/onnxruntime-web/lib/wasm/proxy-wrapper.js:123:34: ERROR: Could not resolve "worker-loader?inline=no-fallback!./proxy-worker/main"
    at failureErrorWithLog (/home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:1599:15)
    at /home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:1245:28
    at runOnEndCallbacks (/home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:1030:63)
    at buildResponseToResult (/home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:1243:7)
    at /home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:1352:14
    at /home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:662:9
    at handleIncomingPacket (/home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:759:9)
    at Socket.readFromStdout (/home/user/Documents/Projects/onnx-test/.yarn/unplugged/esbuild-npm-0.14.28-c2ae07b619/node_modules/esbuild/lib/main.js:629:7)
    at Socket.emit (node:events:526:28)
    at addChunk (node:internal/streams/readable:315:12)

From what I can tell, worker-loader seems to be a Webpack-specific method for loading web workers. Would it be possible to fix this? If not, I think Webpack should be added as a peer dependency to make it clearer that specifically Webpack must be used. Thanks.

@sonovice
Copy link

sonovice commented Apr 9, 2022

Additionally, the current solution using worker-loader is deprecated in webpack v5. It is now recommended to use Workers directly:

new Worker(new URL('./worker.js', import.meta.url));

@fs-eire
Copy link
Contributor

fs-eire commented Apr 22, 2022

I understand the issue with "worker-loader", but it resolves the big problem of file not found after deployment. With worker-loader the actual content is embedded so we no longer worry about various file-not-found issues caused by different reasons.

The problem is not about worker-loader, it's about why Vite runs into the source code of onnxruntime-web. Vite actually run into scan file 'onnxruntime-web/lib/wasm/proxy-wrapper.js'. This is not what I expected; my expectation is the bundler picks up the single file 'dist/ort-web.min.js' directly, skipping the building phrase and ignores anything under folder 'onnxruntime-web/lib'. this should be picked up by the "browser" field.

@fs-eire fs-eire self-assigned this Apr 22, 2022
@xraywu
Copy link

xraywu commented Jun 27, 2022

@Interpause kindly have you found a workaround using Vite to bundle? Many thanks.

@Interpause
Copy link
Author

Interpause commented Jun 28, 2022

I ended up adding onnxruntime-web via a script tag (which adds it to the global namespace). Then, I used the npm onnxruntime-web package just for typing. See Interpause/onnx-web-test@5dcb31a for what exactly I did. So technically I did not use Vite to bundle it... Also it means dependency on being able to reach the jsdelivr CDN.

@jordanparker6
Copy link

Any update as to whether support for vitejs bundling is on the roadmap?

I am using the workaround above but I am getting the following error.

TypeError: cannot resolve operator 'Erf' with opsets: ai.onnx v11

Erf operator seems to be present post v13 and the CDN is only delivering v11.

@Interpause Interpause changed the title Incompatibility with Vite Bundler Web Worker Incompatibility with Vite Bundler Sep 18, 2022
@fs-eire
Copy link
Contributor

fs-eire commented Sep 19, 2022

TypeError: cannot resolve operator 'Erf' with opsets: ai.onnx v11

this is no longer the bundling issue. the error message indicates that operator Erf v13 is not supported in WebGL backend. Switching to web assembly backend should be able to resolve this issue.

@K024
Copy link

K024 commented Jan 3, 2023

I've written a simple plugin for ViteJS which directly imports dist/ort-web.min.js as @fs-eire expected. Please have a try @Interpause

CODE

vite.config.ts

import { defineConfig, Plugin } from "vite"
import fs from "node:fs/promises"

export type OnnxruntimeWebPluginOptions = {
  /**
   * @default "onnxruntime-web/dist/ort-web.min.js"
   */
  importSource?: string

  /**
   * @default "node_modules/onnxruntime-web/dist"
   */
  ortDistDir?: string
}

function proxyScript(importSource: string, wasmPaths: string) {
  return `
import * as ort from "${importSource}";
ort.env.wasm.wasmPaths = import.meta.env.BASE_URL + "${wasmPaths}/";
export default ort; export * from "${importSource}";`
}

export function onnxruntimeWebPlugin(options?: OnnxruntimeWebPluginOptions): Plugin {

  const importSource = options?.importSource ?? "onnxruntime-web/dist/ort-web.min.js"
  const ortDistDir = options?.ortDistDir ?? "node_modules/onnxruntime-web/dist"
  const ortModuleId = "onnxruntime-web"
  const virtualModuleId = "\0/vite-plugin-onnxruntime-web/ort"

  let isDev = false
  let assetsDir = "assets"

  return {
    name: "vite-plugin-onnxruntime-web",
    enforce: "pre",
    configResolved(config) {
      isDev = config.command === "serve"
      assetsDir = config.build.assetsDir
    },
    resolveId(source) {
      if (source === ortModuleId)
        return virtualModuleId
    },
    load(id) {
      if (id === virtualModuleId)
        return proxyScript(importSource, isDev ? ortDistDir : assetsDir)
    },
    async generateBundle() {
      for (const file of await fs.readdir(ortDistDir)) {
        if (file.endsWith(".wasm")) {
          this.emitFile({
            type: "asset",
            fileName: `${assetsDir}/${file}`,
            source: await fs.readFile(`${ortDistDir}/${file}`),
          })
        }
      }
    },
  }
}

export default defineConfig({
  plugins: [
    onnxruntimeWebPlugin(),
  ]
})

Currently, wasm doesn't have an official way to be directly imported as an es module (MDN docs). This causes the hard parts in the plugin. Web workers are built inline in the dist files and are nothing to do with the implementation. I've tested this with vite^4.0.4 and onnxruntime-web^1.13.1, and it works correctly.


Update: a simpler way without a plugin:

ort.ts

import * as ort from "onnxruntime-web/dist/ort-web.min.js"

import wasm from "onnxruntime-web/dist/ort-wasm.wasm?url"
import wasmThreaded from "onnxruntime-web/dist/ort-wasm-threaded.wasm?url"
import wasmSimd from "onnxruntime-web/dist/ort-wasm-simd.wasm?url"
import wasmSimdThreaded from "onnxruntime-web/dist/ort-wasm-simd-threaded.wasm?url"

import modelUrl from "./model.onnx?url"

ort.env.wasm.wasmPaths = {
  "ort-wasm.wasm": wasm,
  "ort-wasm-threaded.wasm": wasmThreaded,
  "ort-wasm-simd.wasm": wasmSimd,
  "ort-wasm-simd-threaded.wasm": wasmSimdThreaded,
}

vite-env.d.ts

/// <reference types="vite/client" />

declare module "onnxruntime-web/dist/*.js" {
  export * from "onnxruntime-web"  
}

@jpggvilaca
Copy link

@K024 where do you put the ort.ts file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants