动态生成适当的角度元素而不会使构建大小膨胀?



摘要:

当在开关机箱内多次调用createCustomElement()时,所有组件都将包含在构建中,而不仅仅是实际使用的组件。 这会增加具有重复代码的生成大小。

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

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

myWidget 子项目的app.module.ts (简体):

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 bundle 分析器验证)。

更远的背景

这里的三个特定于站点的 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) 动态加载所需组件而不是在开关盒中加载的一些技巧?

我什么也没找到。 似乎只要我必须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

最新更新