webpack / webpack-dev-server

Serves a webpack app. Updates the browser on changes. Documentation https://webpack.js.org/configuration/dev-server/.
MIT License
7.8k stars 1.44k forks source link

Web Audio Workers do not have access to global scope `self` #4988

Closed FallingSnow closed 10 months ago

FallingSnow commented 1 year ago

Bug report

I'm running into an issue while using web audio workers. It seems there isn't a target that uses globalThis instead of self. The code causing the issue is below. https://github.com/webpack/webpack-dev-server/blob/540c43852ea33f9cb18820e1cef05d5ddb86cc3e/client-src/index.js#L149-L151

AudioWorkletGlobalScope defines the only scope available to a web audio worker.

Actual Behavior

ReferenceError: self is not defined

I have tried changing the globalObject in my webpack config but it seems webpack-dev-server doesn't use this option.

output: {
  globalObject: "globalThis"
}

I also tried setting the target to webworker but the error persists.

Expected Behavior

Either code generated should use the globalObject set by webpack or default to globalThis. Or the self code portions should not be included in web worker output.

How Do We Reproduce?

Create a audio worker using code compiled by webpack-dev-server and register it using the same name as below; "realtime-audio". The audio worker file should be complied to a separate bundle. See https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletNode for another complete example.

audio.ts

export class RealtimeAudio extends AudioWorkletProcessor {

  constructor() {
    super();
    console.debug("Created realtime audio player");
  }

  process(
    inputs: Float32Array[][],
    outputs: Float32Array[][],
    parameters: Record<string, Float32Array>
  ): boolean {
    return true;
  }
}

registerProcessor("realtime-audio", RealtimeAudio);

main.ts

let audioCtx = new AudioContext({
  latencyHint: "interactive",
  sampleRate: 48_000,
});
audioCtx.audioWorklet.addModule("audio.bundle.js");
let worker = new AudioWorkletNode(audioCtx, "realtime-audio", {});

This should trigger the error.

Please paste the results of npx webpack-cli info here, and mention other relevant information

  System:
    OS: Linux 6.4 Arch Linux
    CPU: (8) x64 13th Gen Intel(R) Core(TM) i5-13600K
    Memory: 498.34 MB / 2.86 GB
  Binaries:
    Node: 20.5.1 - ~/.nvm/versions/node/v20.5.1/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v20.5.1/bin/yarn
    npm: 9.8.0 - ~/.nvm/versions/node/v20.5.1/bin/npm
  Packages:
    compression-webpack-plugin: ^10.0.0 => 10.0.0
    css-loader: ^6.8.1 => 6.8.1
    html-webpack-plugin: ^5.5.1 => 5.5.1
    strict-csp-html-webpack-plugin: 1.0.0-beta.2 => 1.0.0-beta.2
    style-loader: ^3.3.3 => 3.3.3
    swc-loader: ^0.2.3 => 0.2.3
    webpack: ^5.85.0 => 5.85.0
    webpack-bundle-analyzer: ^4.9.0 => 4.9.0
    webpack-cli: ^5.1.1 => 5.1.1
    webpack-dev-server: ^4.15.1 => 4.15.1
    webpack-subresource-integrity: 5.2.0-rc.1 => 5.2.0-rc.1
alexander-akait commented 10 months ago

You don't need to use client (and maybe hot, but it depends on your goals), please use:

module.exports = [
  {
    entry: "./src/index.js",
    mode: "development",
    output: {
      path: path.resolve(__dirname, "./dist"),
      filename: "main.js",
    },
  },
  {
    entry: "./src/audio.js",
    mode: "development",
    target: "webworker",
    output: {
      publicPath: "",
      path: path.resolve(__dirname, "./dist"),
      filename: "audio.bundle.js",
    },
    devServer: {
      client: false,
      hot: false,
    }
  }
];

i.e. you disable client and hot on your audio worklet.

But there is a small problem, you can't use dev server options for the first compilation, but we are working on it https://github.com/webpack/webpack-cli/pull/4045 and release will be soon, after cut a release you can do such things:

module.exports = [
  {
    entry: "./src/index.js",
    mode: "development",
    output: {
      path: path.resolve(__dirname, "./dist"),
      filename: "main.js",
    },
    devServer: {
      // Your options for dev server
    }
  },
  {
    entry: "./src/audio.js",
    mode: "development",
    target: "webworker",
    output: {
      publicPath: "",
      path: path.resolve(__dirname, "./dist"),
      filename: "audio.bundle.js",
    },
    devServer: false
  }
];

Sorry for delay and feel free to feedback