微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

动态生成适当的 Angular 元素而不会膨胀构建大小? 进一步背景

如何解决动态生成适当的 Angular 元素而不会膨胀构建大小? 进一步背景

总结:

createCustomElement() 在 switch case 中被多次调用时,所有 组件将包含在构建中,而不仅仅是实际使用的组件。这会增加重复代码的构建大小。

详情

我有一个站点架构的 Angular 11 应用程序。每个站点angular.json 中都有一个项目,因此它们可以独立构建并基于包含“siteCode”的相应 environment.ts 文件生成自己的 dist 包。

对于我网站中的一个大组件——我们称之为 myWidget——我还将它导出为通用 Web 组件(又名“Angular 元素”,又名“自定义元素”),用于其他网站消费。所以我在主应用程序的一个子项目中有 myWidget,它也有自己的项目列在 angular.json 中。这意味着我可以为给定的站点运行一个只包含 myWidget 的构建(当然还有核心的 Angular 框架)。

app.module.ts of myWidget sub-project(简化):

import { MyWidgetSite1Component } from './my-widget/site-widgets/my-widget-site1.component';
import { MyWidgetSite2Component } from './my-widget/site-widgets/my-widget-site2.component';
import { MyWidgetSite3Component } from './my-widget/site-widgets/my-widget-site3.component';

@NgModule({
  declarations: [AppComponent],imports: [MyWidgetModule]
})
export class AppModule {

  constructor(private injector: Injector) {

    //Create generic web component version of myWidget.  Use correct child version per site.
    
    switch (environment.siteCode) {
      case "site1": {
        const myWidgetCustomElement = createCustomElement(MyWidgetSite1Component,{ injector: this.injector });
        customElements.define('site1-myWidget',myWidgetCustomElement);
        break;
      }
      case "site2": {
        const myWidgetCustomElement = createCustomElement(MyWidgetSite2Component,{ injector: this.injector });
        customElements.define('site2-myWidget',myWidgetCustomElement);
        break;
      }
      case "site3": {
        const myWidgetCustomElement = createCustomElement(MyWidgetSite3Component,{ injector: this.injector });
        customElements.define('site3-myWidget',myWidgetCustomElement);
        break;
      }
    }
  }
}

问题:它在构建中包含所有这三个组件,而不仅仅是将用于该站点一个(通过 webpack 包分析器验证)。

进一步背景

这里的三个特定于站点的 myWidget 组件都继承自一个公共基础组件,所有真正的逻辑都在其中,因此它们几乎相同。我这样做是为了我可以为该站点加载适当的 CSS 文件,并将它们作为特定于组件的 CSS 捆绑在内部导出的 MyWidget Web 组件中。它使用 shadowDom 封装,这样 web 组件与它插入的父页面完全隔离。所以有问题的组件看起来像这样:

my-widget-site1.component.ts

@Component({
  selector: 'my-widget-site1',templateUrl: '../my-widget/my-widget.component.html',//Shares base myWidget template

  //First file does nothing but import appropriate site's stylesheets from main project.  It would
  //have been better to directly include them here,but that resulted in odd build errors.
  styleUrls: [
    './my-widget-site1.component.scss','../my-widget/my-widget.component.scss'],encapsulation: ViewEncapsulation.ShadowDom
})
export class MyWidgetSite1Component extends MyWidgetComponent implements OnInit {
  //Do not add any code here
}

my-widget-site1.component.scss

@import '../../../../../../src/app/sites/site1/theme.scss';
@import '../../../../../../src/styles.scss';
@import '../../../../../../src/app/sites/site1/styles.scss';

结论

我能想到一些解决这个问题的一般思路:

1) 动态加载所需组件而不是在 switch case 中加载的一些技巧?

我找不到任何东西。似乎只要我必须import 组件,它就会包含在构建中。

2) 完全避免每个站点有多个组件版本?

我很想这样做,但我不知道如何解决 CSS 问题。给定站点的适当 CSS 文件需要在构建时捆绑到此组件中,以便它们封装在 Web 组件的影子根中,而不是构建为导入到消费页面全局范围的单独 CSS 文件.这意味着我不能只在 angular.json

中项目构建的“样式”部分列出它们

我尝试在 scss 上执行动态 @import 语句,但这似乎不可能。

您能否在构建过程中编写一些脚本,以便在构建时选择正确的 scss 文件?我不知道从哪里开始这样的事情。

解决方法

我想出了一个有趣的解决方案。

我可以摆脱对多个组件文件的需求,并通过使用“快捷方式”指向必要的 scss 文件而不是完整路径来有效地实现动态 @import

@import "theme";
@import "styles";
@import "site-styles";

您可以通过 angular.json 配置它将在其中找到指定文件的文件夹:

"stylePreprocessorOptions": {
  "includePaths": [
    "src/app/sites/site1/",//theme.scss and site-styles.scss are here
    "src/"  //styles.scss is here
  ]
}

所以现在我可以使用一个始终具有相同导入的组件,但在构建时它实际上会为正在构建的站点使用正确的文件。

关于快捷语法的信息:https://www.digitalocean.com/community/tutorials/angular-shortcut-to-importing-styles-files-in-components

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。