Our application is built on top of Next, and we are currently in the process of migrating our audio recording engine to Audio Worklet API from Script Processor. (with backwards compatibility of course) Part of the transition is also upgrading to Webpack 5. We are utilizing both Web Workers and Audio Worklets. Prior to switch to Webpack 5, which comes with native support for Workers, (or so it appears) we used worker-plugin. It worked wonderfully for both, however with the transition we can no longer rely on it, because it uses outdated webpack's APIs, and Next comes with its own bundled Webpack 4 and 5, which don't seem to have backwards compatibility included.
Now the challenge is to get these working with Webpack 5 bundled with Next. The first issue comes from web worker's global scope being undefined. This can be resolved with by setting config.output.globalObject
to "(typeof self !== 'undefined' ? self : this)"
. Once workers are functional, the next issue comes when trying to bundle worklet's code. Currently, Webpack 5 doesn't support worklet import, but they expose parser config, which can be used to tell webpack to load it as a worker, as per this Github issue. This will fail with Next unless you also set config.output.publicPath = "/_next/";
Upon loading the chunk via audioContext.audioWorklet.addModule(...)
, the code crashes with Uncaught TypeError: Cannot read property 'webpackChunk_N_E' of undefined
. If we inspect the chunk containing bundled worklet code, we'll see that this prop is being used in the following way:
var chunkLoadingGlobal = (typeof self !== 'undefined' ? self : this)["webpackChunk_N_E"] = (typeof self !== 'undefined' ? self : this)["webpackChunk_N_E"] || []; var parentChunkLoadingFunction = chunkLoadingGlobal.push.bind(chunkLoadingGlobal); . . . (typeof self !== 'undefined' ? self : this)["webpackHotUpdate_N_E"] = function...
It's clear, that AudioWorkletGlobalScope
doesn't have either self
or this
, so that's why it's not going too well.
So the question is, how can this be worked around? Audio Worklets seem to be getting very little attention still from both Next and Webpack, despite it being available by default now even in Safari. (since 14.5)
Below are the code snippets representing our current state. (we are using Typescript)
next.config.js
module.exports = withPlugins([...], { future: {webpack5: true}, webpack: (config, options) => { config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`; config.output.publicPath = "/_next/"; config.resolve = { ...config.resolve, alias: { ...config.resolve.alias, "audio-worklet": path.resolve(__dirname, "src/util/audio-worklet") } } config.module.parser = { ...config.module.parser, javascript: { worker: ["AudioWorklet from audio-worklet", "..."] } } config.output.chunkFilename = options.isServer ? `${options.dev ? "[name].[hash]" : "[name].[chunkhash]"}.js` : `static/chunks/${options.dev ? "[name].[hash]" : "[name].[chunkhash]"}.js`; return config; } });
src/util/audio-worklet.ts
export const AudioWorklet = (url: URL) => { return url as unknown as string; };
.../audio-context.ts
import { AudioWorklet } from "audio-worklet"; const audioContext = new AudioContext(); audioContext.audioWorklet.addModule(new AudioWorklet(new URL("path/to/processor.worklet.ts", import.meta.url)));
.../audio-worklet-processor.worklet.ts
// import statements for utility code class Processor extends AudioWorkletProcessor { // Your run of the mill processor code } registerProcessor("processor", Processor);
Sources:
- https://github.com/GoogleChromeLabs/worker-plugin
- https://webpack.js.org/configuration/module/#moduleparserjavascript
- https://github.com/webpack/webpack/issues/11543
- https://github.com/vercel/next.js/tree/canary/examples/with-web-worker
没有评论:
发表评论