Pav*_*sky 6 webpack web-audio-api next.js audio-worklet webpack-5
我们的应用程序构建在 Next 之上,目前我们正在将音频录制引擎从 Script Processor 迁移到 Audio Worklet API。(当然具有向后兼容性)过渡的一部分也是升级到 Webpack 5。我们正在利用 Web Workers 和 Audio Worklet。在切换到 Webpack 5(它自带对 Workers 的本机支持)之前(至少看起来是这样),我们使用了worker-plugin。它对两者都非常有效,但是随着过渡,我们不能再依赖它,因为它使用过时的 webpack 的 API,并且 Next 附带了自己捆绑的 Webpack 4 和 5,它们似乎不包含向后兼容性。
现在的挑战是让这些与 Next 捆绑在一起的 Webpack 5 一起使用。第一个问题来自网络工作者的全局范围未定义。config.output.globalObject这可以通过设置为来解决"(typeof self !== 'undefined' ? self : this)"。一旦工作人员正常工作,下一个问题就会出现在尝试捆绑工作集的代码时。目前,Webpack 5 不支持工作集导入,但它们公开了解析器配置,可用于告诉 webpack 将其作为工作进程加载,如此Github 问题所示。这将在下一步中失败,除非您还设置了config.output.publicPath = "/_next/";通过加载块时audioContext.audioWorklet.addModule(...),代码崩溃Uncaught TypeError: Cannot read property 'webpackChunk_N_E' of undefined。如果我们检查包含捆绑工作集代码的块,我们将看到该道具的使用方式如下:
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...
Run Code Online (Sandbox Code Playgroud)
很明显,AudioWorkletGlobalScope没有self或this,所以这就是为什么它进展得不太顺利。
那么问题是,如何解决这个问题?Audio Worklet 似乎仍然很少受到 Next 和 Webpack 的关注,尽管它现在甚至在Safari中也默认可用。(自 14.5 起)
下面是代表我们当前状态的代码片段。(我们正在使用打字稿)
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;
}
});
Run Code Online (Sandbox Code Playgroud)
src/util/audio-worklet.ts
export const AudioWorklet = (url: URL) => {
return url as unknown as string;
};
Run Code Online (Sandbox Code Playgroud)
.../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)));
Run Code Online (Sandbox Code Playgroud)
.../audio-worklet-processor.worklet.ts
// import statements for utility code
class Processor extends AudioWorkletProcessor {
// Your run of the mill processor code
}
registerProcessor("processor", Processor);
Run Code Online (Sandbox Code Playgroud)
资料来源:
经过大量挖掘,这个问题似乎是由 webpack 在块中导入脚本引起的。具体来说,当我们尝试导入任何重要的代码(例如 lodash)或使用 babel 认为使用其垫片所必需的数据结构时,Webpack 会注入使用installChunk的函数importScripts,这显然不受 AudioWorklets 支持。这还会插入上面导致Uncaught TypeError: Cannot read property 'webpackChunk_N_E' of undefined.
这是一个一一复制的存储库: https: //github.com/thecynicalpaul/test-audio-worklet-webpack5(nmp i,然后npm run dev)
当我们找到一个临时解决方案时,我自己回答了这个问题。
发生此问题的原因是 Webpack 5 中的 URL 加载器将工作集文件视为 Web Worker 文件。这意味着,上下文是worker,它将尝试使用诸如 之类的API importScripts,这显然不受支持。
我们找到的解决方案是禁用与工作集相关的任何块的块分割,从而有效地消除了使用的需要importScripts:
(在next.config.jswebpack的函数里面)
if (!options.isServer && !options.dev) {
config.optimization.splitChunks = {
chunks: (chunk) => {
// this may vary widely on your loader config
if (chunk.name && chunk.name.includes("worklet")) {
return false;
}
return true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
出于显而易见的原因,这并不是总体方案中的最佳解决方案,并且 webpack 团队目前正在寻找更好的方法来处理这个问题。
| 归档时间: |
|
| 查看次数: |
1600 次 |
| 最近记录: |