在Angular中,使用WebPack 5模块联邦,我们如何公开远程使用的Web Workers?

hgc7kmma  于 11个月前  发布在  Webpack
关注(0)|答案(3)|浏览(116)

在我的配置中,我目前正在使用一个shell应用程序和一个遥控器,两者都是用angular 12.2.0编写的,我面临着一个我不知道如何解决的问题。

Shell webpack.config.js

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const mf = require("@angular-architects/module-federation/webpack");
const path = require("path");
const share = mf.share;

const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
  path.join(__dirname, '../../tsconfig.json'),
  ['auth-lib']
);

module.exports = {
  output: {
    uniqueName: "portal",
    publicPath: "auto"
  },
  optimization: {
    runtimeChunk: false
  },
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  plugins: [
    new ModuleFederationPlugin({

        // For hosts (please adjust)
        remotes: {
          "myremote": "myremote@http://localhost:4250/remoteEntry.js"
        },

        shared: share({
          "@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
          "@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
          "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
          "@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },

          ...sharedMappings.getDescriptors()
        })

    }),
    sharedMappings.getPlugin()
  ],
};

字符串

远程webpack.config.js

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const mf = require("@angular-architects/module-federation/webpack");
const path = require("path");
const share = mf.share;

const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
  path.join(__dirname, 'tsconfig.json'),
  [/* mapped paths to share */]
);

module.exports = {
  output: {
    uniqueName: "interviews",
    publicPath: "auto"
  },
  optimization: {
    runtimeChunk: false
  },
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  plugins: [
    new ModuleFederationPlugin({

        // For remotes (please adjust)
        name: "myremote",
        filename: "remoteEntry.js",
        exposes: {
            './Module': './src/app/myremote/myremote.module.ts'
        },

        shared: share({
          "@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
          "@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
          "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
          "@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },

          ...sharedMappings.getDescriptors()
        })

    }),
    sharedMappings.getPlugin()
  ],
};


当我在shell应用程序中使用对我的远程模块的引用时,一切都很顺利,就像这样:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';

const routes: Routes = [{
  path: '',
  component: HomeComponent,
  pathMatch: 'full'
}, {
  path: 'myremote',
  loadChildren: () => import('myremote/Module').then(m => m.MyRemoteModule)
}];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }


当远程模块的组件在其代码中示例化一个新的Web Worker时,问题就会出现,如下所示:

const myWorker = new Worker(
    new URL('../path/to/workers/worker.ts',
    import.meta.url
  ),
  { type: 'module', name: 'my-worker' }
);
// since I'm also using comlink, I also do that, but that's not really relevant here
this.worker = this.createWrapper<WorkerService>(myWorker);


上面的代码,在Webpack 5中,已经在我的应用程序中生成了一个单独的bundle,名为my-worker.js,它不是组件的一部分,也不是模块的bundle。因此,将模块暴露给Module Federation,不会将worker的代码暴露给remoteEntry.js。然后尝试使用shell应用程序导航到加载我的远程的路由,将出错并通知:
ERROR错误:承诺(Promise):安全错误:无法构造“Worker”:无法从源“http://localhost:5000”访问位于“http://localhost:4250/my-worker.js”的脚本。错误:无法构造“Worker”:无法从源“http://localhost:5000”访问位于“http://localhost:4250/my-worker.js”的脚本。
所以问题是,如果我想有一个遥控器,并公开它的模块在shell应用程序中使用,其中一个模块使用Web Worker,我如何确保Webpack创建的单独的worker bundle也被公开,以便shell应用程序能够示例化它?

ssgvzors

ssgvzors1#

感谢alexander-akait,答案就在这里
https://github.com/webpack/webpack/discussions/14380
假设错误是SecurityError
ERROR错误:Uncaught(in promise):SecurityError
该问题与需要在本地服务器中设置CORS有关。

ql3eal8s

ql3eal8s2#

我找到了一个变通办法。
步骤1.在单独的文件中创建自定义worker类

export class CorsWorker {
 private readonly worker: Worker;

constructor(url: string | URL) {
    const objectURL = URL.createObjectURL(
        new Blob([`importScripts(${JSON.stringify(url.toString())});`], {
            type: 'application/javascript'
        })
    );
    this.worker = new Worker(objectURL);
    URL.revokeObjectURL(objectURL);
}

getWorker() {
    return this.worker;
 }
}

字符串
第2步-不要使用Webpack Worker,而是使用CorsWorker导入你的worker文件。

import { CorsWorker as Worker } from './cors-worker';

// aliasing CorsWorker to Worker makes it statically analyzable
const corsWorker = new Worker(new URL('../worker', import.meta.url));

const worker = corsWorker.getWorker();


这个例子对我很有用。我们可以通过关注这个GitHub讨论线程https://github.com/webpack/webpack/discussions/14648来获得更多信息。

hgtggwj0

hgtggwj03#

我稍微修改了Pravanjan的答案,以便在处理模块时不会抛出与WorkerGlobalScope上不可用的importScripts相关的错误。
步骤1.在单独的文件中创建自定义worker类

export class CorsWorker {
    private readonly url: string | URL;
    private readonly options?: WorkerOptions;

    // Have this only to trick Webpack into properly transpiling
    // the url address from the component which uses it
    constructor(url: string | URL, options?: WorkerOptions) {
        this.url = url;
        this.options = options;
    }

    async createWorker(): Promise<Worker> {
        const f = await fetch(this.url);
        const t = await f.text();
        const b = new Blob([t], {
            type: 'application/javascript',
        });
        const url = URL.createObjectURL(b);
        const worker = new Worker(url, this.options);
        return worker;
    }
}

字符串
第2步-不要使用Webpack Worker,而是使用CorsWorker导入你的worker文件。

import { CorsWorker as Worker } from './cors-worker';

// aliasing CorsWorker to Worker makes it statically analyzable

const corsWorker = await (new Worker(
    new URL('../workers/my-worker.worker', import.meta.url),
    { type: 'module', name: 'my-worker' },
)).createWorker();

相关问题