通过 Webpack 5 模块联合提供样式和资源

问题描述 投票:0回答:4

我已经在我的 Angular 11 应用程序中成功实现了相对较新的 webpack 5 模块联合系统,因此它可以从另一个版本按需远程加载模块。

我一无所知的是如何处理样式表和图像等资源。例如,联合模块中有一个菜单元素需要自己的样式:

  • 将它们放入组件的样式表中会使块膨胀,编译器会抱怨这一点,而且在显示菜单之前它们不会加载
  • 如果样式位于联合模块的全局样式表上,则它们根本不会加载,因为我请求的是子模块而不是主模块(我认为)
  • 该样式是联邦模块特有的,因此不能放入加载应用程序中

我认为样式可以被编译并放入联合模块的构建资产中,但是当它在有联合和没有联合的情况下使用时,这会破坏链接。

我仍在尝试这个,但我认为最好问一下。有人遇到这个问题吗

angular webpack assets webpack-module-federation
4个回答
8
投票

我认为实现这一点的最优雅的方法是将微前端的全局 styles.scss 导入到它的入口模块 component.scss 中,并在入口模块 component.ts 中设置

encapsulation: ViewEncapsulation.None
以打破它的样式封装,这反过来又会导致该样式在全球范围内应用。


1
投票

好吧,我将发布我的想法,它并不漂亮,但它似乎对于 CSS 资源来说工作得很好。

首先,我在远程模块的构建中将它们分开: 角度.json:

"styles": [
  "projects/xxx-admin/src/styles/styles.scss",
  "projects/xxx-admin/src/styles/admin.scss",
  {
    "input": "projects/xxx-admin/src/styles/admin.scss",
    "bundleName": "admin_module_styles",
    "inject": false
  }
],

这会生成一个具有清晰的非自动生成名称的 CSS。然后我们从应用程序的路由中加载联合模块:

{
  path: "admin",
  component: AdminPanelComponent,
  canActivate: [XxxAdminGuard],
  loadChildren: () => {
    const baseUrl = getAdminFrontendBaseUrl();
    return loadAdminStyles().then(
      () => loadRemoteModule({
        remoteName: "xxx_admin",
        remoteEntry: `${baseUrl}/remoteEntry.js`,
        exposedModule: "AdminModule",
      }).then((m) => m.AdminModule));
  },
},

...

export function loadAdminStyles(): Promise<void> {
  return new Promise((resolve => {
    const baseUrl = getAdminFrontendBaseUrl();
    const el = document.getElementById("admin-module-styles");

    // Load one instance, do it like this to handle errors and retrying
    if (el) {
      el.remove();
    }
    const headEl = document.getElementsByTagName("head")[0];
    const styleLinkEl = document.createElement("link");
    styleLinkEl.rel = "stylesheet";
    styleLinkEl.id = "admin-module-styles";
    styleLinkEl.href = `${baseUrl}/admin_module_styles.css`;
    headEl.appendChild(styleLinkEl);
    resolve();
  }));
}

这不是最理想的,但我想不出更好的办法了。


0
投票

在microfront中,将资产转移到assets/mfe_name。通过 microfront 的名称,您可以从父主机进行代理。

主持人:

"/assets/*mfe_name*/*": {
           "target": "*mfe_host*",
           "secure": true,
           "changeOrigin": true
    },

启动:ngserve --proxyConfig=proxy

因此,您可以从本地主机和产品上获取文件,以便从远程主机访问


0
投票

所以你可以做如下:

  1. 在远程应用程序中将

    assets
    文件夹重命名为某个唯一的名称,例如remote-app1

  2. 全局样式必须移至 shell 应用程序或使用

    encapsulation emulated
    创建容器组件。不封装不是一个好方法,因为它不仅会为 shell 应用全局样式,还会影响其他应用程序。 (使用 :host ::ng-deep 在此容器中深入设计)

  3. 在 shell 应用程序中,创建一个服务工作线程来侦听所有获取请求。一旦获取请求到来,检查其路径前缀并将 URL 更改为适当的远程 URL(检查 png、svg、.json 后缀以了解粒度)。

就像在 sw

self.addEventListener('fetch', (event) => {...}

为什么喜欢这个?

  • 如果您使用代理,它将无法在生产中工作(也不推荐)
  • 远程应用程序的全局样式不应该影响其他样式,这就是封装的原因
  • 重命名资产文件夹(在所有遥控器中都是唯一的)不仅可以解决获取图像问题,还可以解决两个遥控器具有相同图像名称的问题。

如果您还想使用翻译(ngx-translate),请在容器组件(point2)中使用

TranslateModule.forChild
isolate: true

© www.soinside.com 2019 - 2024. All rights reserved.