Angular:为与主项目共享代码的工作线程构建独立捆绑包

huangapple go评论64阅读模式
英文:

Angular: Build standalone bundle for worklet that shares code with the main project

问题

我有一个使用 Angular 13 的音频应用程序,使用了音频工作线程。UI 部分是 Angular/TypeScript,但工作线程是纯 JavaScript。通过调用 Worklet.addModule() 并提供存储在 assets 文件夹中的 JavaScript 文件路径来加载工作线程。

我想用 TypeScript 开发工作线程,并与 UI 共享一些代码。由于 addModule() 需要单个 JavaScript 文件,我正在尝试学习如何将工作线程代码和任何导入的模块转译为独立的 JavaScript 文件,而项目的 UI 部分则像往常一样捆绑。

我对 Angular 和 TypeScript 感到相当熟悉,但因为觉得解决方案可能在其中,所以刚刚开始学习更多关于 tsc 和 webpack。我走在正确的道路上吗?

我已经在寻找解决方案,并发现了一些与 Angular 和 AudioWorklet 相关的信息,但没有取得突破。我已经让 Web Workers 与 Angular 协同工作,但还没有找到将其扩展到工作线程的方法。

英文:

I have an Angular 13 audio application that uses an audio worklet. The UI is Angular/Typescript but the worklet is straight Javascript. The worklet is loaded by calling Worklet.addModule() with the path to the javascript file stored in the assets folder.

I would like to develop the worklet in Typescript and share some of the code with the UI. Since addModule() needs a single Javascript file I'm trying to learn how to get the worklet code and any imported modules transpiled into a standalone Javascript file while the UI part of the project is bundled as usual.

I'm pretty comfortable with Angular and Typescript but have just started to learn more about tsc and webpack because I feel like the solution is somewhere in there. Am I on the right track?

I've poked around for solutions and have found a few hits related to Angular and AudioWorklet, but no breakthroughs. I've gotten web workers to work with Angular but haven't found a way to extend that to worklets.

答案1

得分: 0

我找到了一个满足我两个要求的解决方案:

  • 用Typescript编写AudioWorkletProcessor
  • 与Angular UI共享Typescript模块

由于现代化工作代码也是一个目标,我将Angular从13升级到了16,将Webpack升级到了版本5,将Typescript升级到了5.0.2。我认为以下解决方案对于旧版本也应该适用。

高级别

  • 安装custom-webpack NPM包
  • 安装@types/audioworklet NPM包
  • 向现有的Angular项目添加一个子项目
  • 编辑工作子项目的webpack和tsconfig文件

配置

angular.json

原始项目的angular.json设置保持不变。工作子项目的构建设置配置为使用custom-webpack作为构建器

"architect": {
  "build": {
    "builder": "@angular-builders/custom-webpack:browser",
    "options": {
      "customWebpackConfig": {
        "path": "projects/reader-worklet/webpack-reader.config.js",
        "verbose": {
          "properties": [
            "entry"
          ]
        }
      },
      "outputPath": "dist/reader-worklet",
      "main": "projects/reader-worklet/src/worklet.ts",
      "tsConfig": "projects/reader-worklet/tsconfig.app.json",
      ...
    }
  }
}

webpack-reader.config.js

工作线程的Webpack配置很简单。产生影响的关键设置是将target: "webworker"设置为避免DOM引用,以及optimization.runtimeChunk: false以便将rumtime.js不作为单独的.js文件构建,而是包含在单一的输出文件render-worklet.js中。是的,我在一个地方称之为reader-worklet,在另一个地方称之为render-worklet,我仍然不确定应该怎么称呼它 Angular:为与主项目共享代码的工作线程构建独立捆绑包

"use strict";

const path = require('path');
const mode = process.env.NODE_ENV === "production" ? "production" : "development";

module.exports = {
  // WARNING: MUST set the 'mode' manually because it isn't done by NX/NG cli
  mode,
  entry: {
    main: {
      import: path.resolve(__dirname, './src/worklet.ts'),
      filename: "render-worklet.js",
    },
  },
  output: {
    clean: true
  },
  optimization: {
    runtimeChunk: false
  },
  target: "webworker",
  devtool: 'source-map',
  module: {
    rules: [],
  },
  plugins: []
};

tsconfig.app.json

{
    "extends": "../../tsconfig.json",
    "compilerOptions": {
    "outDir": "../../out-tsc/app",
    "module": "es2022",
    "esModuleInterop": true,
    "target": "es2022",
    "lib": ["es2022"],
    "moduleResolution": "node",
    "sourceMap": true,
    "types": [ "@types/audioworklet"]
    },
    "files": ["src/worklet.ts"],
    "include": [ "src/**/*.d.ts"]
}

AudioWorkletProcessor

这是一个基本的类,扩展了AudioWorkletProcessor。它导入了一个与UI代码共享的类WTrackSettings。这里没有用于任何内容,只是用来验证它能够在工作线程中导入和使用的,process() 方法生成一个方波输出。

import {WTrackSettings} from "../../../src/app/include/shared_defs";
export class TSWorklet extends AudioWorkletProcessor {

    active = true;

    constructor() {
        super();
        this.sayHello();
    }

    public sayHello(): void {
        const ts: WTrackSettings = new WTrackSettings();
        console.table(ts);
        console.log("Hello!!!");
    }

    process(inputs: Float32Array[][], outputs: Float32Array[][], parameters: Record<string, Float32Array>): boolean {
        let buflen = 0;
        let outBuffer = outputs[0];
        if (outBuffer.length > 0) {
            buflen = outBuffer[0].length;
        }

        let frameCount = 0;
        for (; frameCount < buflen / 2; frameCount++) {
            outBuffer[0][frameCount] = 1;
            outBuffer[1][frameCount] = 0
        }
        for (; frameCount < buflen; frameCount++) {
            outBuffer[0][frameCount] = 0;
            outBuffer[1][frameCount] = 1
        }

        return this.active;
    }
}

registerProcessor('ts-reader-worklet', TSWorklet);

我没有展示AudioWorkletNode的实现,因为当AudioWorkletProcessor用JavaScript编写时,它完全相同。

英文:

I found a solution that gives me the two requirements I was after:

  • Write AudioWorkletProcessor in Typescript
  • Share Typescript modules with the Angular UI

Since modernizing the worklet code was also a goal I upgraded Angular from 13 to 16, Webpack to version 5 and Typescript to 5.0.2. I don't see any reason why the following solution wouldn't work for older versions.

High level

  • Install custom-webpack NPM package
  • Install @types/audioworklet NPM package
  • Add a subproject to the existing Angular project
  • Edit webpack and tsconfig files for worklet subproject

Configuration

angular.json

The angular.json settings for the original project are unchanged. The worklet sub-project build settings are configured to use custom-webpack as the builder


  &quot;architect&quot;: {
    &quot;build&quot;: {
      &quot;builder&quot;: &quot;@angular-builders/custom-webpack:browser&quot;,
      &quot;options&quot;: {
        &quot;customWebpackConfig&quot;: {
          &quot;path&quot;: &quot;projects/reader-worklet/webpack-reader.config.js&quot;,
          &quot;verbose&quot;: {
            &quot;properties&quot;: [
              &quot;entry&quot;
            ]
          }
        },
        &quot;outputPath&quot;: &quot;dist/reader-worklet&quot;,
        &quot;main&quot;: &quot;projects/reader-worklet/src/worklet.ts&quot;,
        &quot;tsConfig&quot;: &quot;projects/reader-worklet/tsconfig.app.json&quot;,
    ...

webpack-reader.config.js

The webpack configuration for the worklet is minimal. The key settings that made a difference were to set target:&quot;webworker&quot; to avoid DOM references and optimization.runtimeChunk: false so that rumtime.js is not built as a separate .js file, but rather included in the single output file render-worklet.js. Yes, I call it reader-worklet in one place and render-worklet in another, I'm still not sure what to call it Angular:为与主项目共享代码的工作线程构建独立捆绑包


    &quot;use strict&quot;;
    
    const path = require(&#39;path&#39;);
    const mode = process.env.NODE_ENV === &quot;production&quot; ? &quot;production&quot; : &quot;development&quot;;
    
    module.exports = {
      // WARNING: MUST set the &#39;mode&#39; manually because it isn&#39;t done by NX/NG cli
      mode,
      entry: {
        main: {
          import: path.resolve(__dirname, &#39;./src/worklet.ts&#39;),
          filename: &quot;render-worklet.js&quot;,
        },
      },
      output: {
        clean: true
      },
      optimization: {
        runtimeChunk: false
      },
      target: &quot;webworker&quot;,
      devtool: &#39;source-map&#39;,
      module: {
        rules: [],
      },
      plugins: []
    };

tsconfig.app.json


    {
        &quot;extends&quot;: &quot;../../tsconfig.json&quot;,
        &quot;compilerOptions&quot;: {
        &quot;outDir&quot;: &quot;../../out-tsc/app&quot;,
        &quot;module&quot;: &quot;es2022&quot;,
        &quot;esModuleInterop&quot;: true,
        &quot;target&quot;: &quot;es2022&quot;,
        &quot;lib&quot;: [&quot;es2022&quot;],
        &quot;moduleResolution&quot;: &quot;node&quot;,
        &quot;sourceMap&quot;: true,
        &quot;types&quot;: [ &quot;@types/audioworklet&quot;]
        },
        &quot;files&quot;: [&quot;src/worklet.ts&quot;],
        &quot;include&quot;: [ &quot;src/**/*.d.ts&quot;]
    }

AudioWorkletProcessor

Here is a basic class that extends AudioWorkletProcessor. It imports a class WTrackSettings that is shared with the UI code. It's not used for anything here, just dumped to the console to verify that it's able to be imported and used in the worklet. The process() method generates a square wave output.

import {WTrackSettings} from &quot;../../../src/app/include/shared_defs&quot;;
export class TSWorklet extends AudioWorkletProcessor {

    active = true;

    constructor() {
        super();
        this.sayHello();
    }

    public sayHello(): void {
        const ts: WTrackSettings = new WTrackSettings();
        console.table(ts);
        console.log(&quot;Hello!!!&quot;);
    }


    process(inputs: Float32Array[][], outputs: Float32Array[][], parameters: Record&lt;string, Float32Array&gt;): boolean {
        let buflen = 0;
        let outBuffer = outputs[0];
        if (outBuffer.length &gt; 0) {
            buflen = outBuffer[0].length;
        }

        let frameCount = 0;
        for (; frameCount &lt; buflen / 2; frameCount++) {
            outBuffer[0][frameCount] = 1;
            outBuffer[1][frameCount] = 0
        }
        for (; frameCount &lt; buflen; frameCount++) {
            outBuffer[0][frameCount] = 0;
            outBuffer[1][frameCount] = 1
        }

        return this.active;
    }
}

registerProcessor(&#39;ts-reader-worklet&#39;, TSWorklet);

I haven't shown the AudioWorkletNode implementation because it's exactly the same as when the AudioWorkletProcessor is written in Javascript.

huangapple
  • 本文由 发表于 2023年5月26日 15:21:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76338503.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定