如何解决动态生成适当的 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
]
}
所以现在我可以使用一个始终具有相同导入的组件,但在构建时它实际上会为正在构建的站点使用正确的文件。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。