From 148e664f14f1817e508129db2147167f90ab56e8 Mon Sep 17 00:00:00 2001 From: Christian Badura <93912698+cbadura@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:30:40 +0200 Subject: [PATCH] Migrate to webcomponent (#167) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: migrate theme ui * fix: change helm value detail * fix: use correct lib version * fix: remove config from shared, correct webpack entry * fix: remove dialogsvc from shared module * fix: finish migration to webcomponent and raise libs --------- Co-authored-by: Christian Badura Co-authored-by: Henry Täschner <129834483+HenryT-CG@users.noreply.github.com> --- angular.json | 2 +- helm/values.yaml | 3 + package-lock.json | 131 +++++++++++++++++++------- package.json | 22 +++-- src/app/app-entrypoint.component.html | 1 + src/app/app-entrypoint.component.ts | 7 ++ src/app/onecx-theme-remote.module.ts | 46 +++++++-- src/app/shared/shared.module.ts | 23 +---- src/bootstrap.ts | 16 +--- webpack.config.js | 16 +++- 10 files changed, 179 insertions(+), 88 deletions(-) create mode 100644 src/app/app-entrypoint.component.html create mode 100644 src/app/app-entrypoint.component.ts diff --git a/angular.json b/angular.json index c3e418b..14f3f92 100644 --- a/angular.json +++ b/angular.json @@ -35,7 +35,7 @@ "node_modules/@onecx/portal-integration-angular/assets/output.css", "src/styles.scss" ], - "scripts": [], + "scripts": ["node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"], "extraWebpackConfig": "webpack.config.js", "commonChunk": false }, diff --git a/helm/values.yaml b/helm/values.yaml index e95b5a0..0da7cb4 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -16,6 +16,9 @@ app: description: "OneCX Theme UI" note: "OneCX Theme UI auto import via MF operator" type: MODULE + technology: WEBCOMPONENTMODULE + remoteName: onecx-theme + tagName: ocx-theme-component # Permission permission: enabled: true diff --git a/package-lock.json b/package-lock.json index 9c824c5..78d66e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@angular/common": "15.2.7", "@angular/compiler": "15.2.7", "@angular/core": "15.2.7", + "@angular/elements": "15.2.7", "@angular/forms": "15.2.7", "@angular/platform-browser": "15.2.7", "@angular/platform-browser-dynamic": "15.2.7", @@ -26,15 +27,18 @@ "@ngrx/router-store": "^15.4.0", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", - "@onecx/accelerator": "^4.39.0", - "@onecx/angular-accelerator": "^4.39.0", - "@onecx/angular-integration-interface": "^4.39.0", - "@onecx/angular-remote-components": "^4.39.0", - "@onecx/angular-testing": "^4.39.0", - "@onecx/integration-interface": "^4.39.0", - "@onecx/keycloak-auth": "^4.39.0", - "@onecx/portal-integration-angular": "^4.39.0", - "@onecx/portal-layout-styles": "^4.39.0", + "@onecx/accelerator": "^4.42.0", + "@onecx/angular-accelerator": "^4.42.0", + "@onecx/angular-auth": "^4.42.0", + "@onecx/angular-integration-interface": "^4.42.0", + "@onecx/angular-remote-components": "^4.42.0", + "@onecx/angular-testing": "^4.42.0", + "@onecx/angular-webcomponents": "^4.42.0", + "@onecx/integration-interface": "^4.42.0", + "@onecx/keycloak-auth": "^4.42.0", + "@onecx/portal-integration-angular": "^4.42.0", + "@onecx/portal-layout-styles": "^4.42.0", + "@webcomponents/webcomponentsjs": "^2.8.0", "file-saver": "^2.0.5", "i18n-iso-countries": "^7.11.0", "keycloak-angular": "^13.1.0", @@ -1291,6 +1295,21 @@ "zone.js": "~0.11.4 || ~0.12.0 || ~0.13.0" } }, + "node_modules/@angular/elements": { + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/@angular/elements/-/elements-15.2.7.tgz", + "integrity": "sha512-ojjq07Xj5k7QCfq3U7Kfobe6UgM7vZsudgRynT43uHpXkWNmoxEKbQ279LY+xj0YkiwygfNOUzf39YtMVTc7UQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/core": "15.2.7", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/@angular/forms": { "version": "15.2.7", "license": "MIT", @@ -7097,18 +7116,18 @@ } }, "node_modules/@onecx/accelerator": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/accelerator/-/accelerator-4.40.2.tgz", - "integrity": "sha512-1jyc17KS6O/aK3q+tOTX8sLj+PMBodhOiqDs0CpD2HbUvDDF3nGOayqGiFjyBzIVkzCbKSpcbgjpcVb+ZRfVzw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/accelerator/-/accelerator-4.42.0.tgz", + "integrity": "sha512-Kq+cE5BwE49/ZTgOBL94TV6jzlaXuBkw90mCdmkC6J0xRXKAtlzv40FrtfTUGBJ6/Pd5G/Y/ZZvHHb6BF5MEbQ==", "peerDependencies": { "rxjs": "7.8.1", "tslib": "^2.3.0" } }, "node_modules/@onecx/angular-accelerator": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/angular-accelerator/-/angular-accelerator-4.40.2.tgz", - "integrity": "sha512-QLNIhhixZBS3dOV2PBiarMmmfvpdqbL+5zoXoEaADiK8ThV0E0rIYDdV/uVCTQvUzU0nz5dZApM0b441b6Oq7A==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/angular-accelerator/-/angular-accelerator-4.42.0.tgz", + "integrity": "sha512-uGRB0U3D2wNE7OvKqPObE5RgsP9mcBxk1QuNqUBJbVwzmJ5A0PzSA6R7loa2mVqrDwp3C+qF28W3WDRadp8n9w==", "dependencies": { "tslib": "^2.3.0" }, @@ -7129,10 +7148,28 @@ "rxjs": "~7.8.0" } }, + "node_modules/@onecx/angular-auth": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/angular-auth/-/angular-auth-4.42.0.tgz", + "integrity": "sha512-VBN7XTAKQxgBuwvDwJoN6/Yl5y4VlV+C1xpRXBksIpMQmyBBc/Q7bnx1/xcwUXgU70ftWCMFF4DjSpP4pci4Rg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular-architects/module-federation": "^15.0.0", + "@angular/common": "^15.2.7", + "@angular/core": "^15.2.7", + "@onecx/angular-integration-interface": "^4", + "@onecx/integration-interface": "^4", + "keycloak-angular": "^13.0.0", + "keycloak-js": "^18.0.0", + "rxjs": "~7.8.0" + } + }, "node_modules/@onecx/angular-integration-interface": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/angular-integration-interface/-/angular-integration-interface-4.40.2.tgz", - "integrity": "sha512-Rzg5S3pAsV53RxCP1c273TeMwJtFCoQMV0zUsKgIleXMwdP4u1RL2876HQ0vKuHpHGdrDrfMWZgXLKNNtcdjwg==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/angular-integration-interface/-/angular-integration-interface-4.42.0.tgz", + "integrity": "sha512-PdOJMzSalZxjfEbwDIbcOQhCLDBoXPzwuN9JYUyF4n3IenbNJZmOODCNgWo4Kf9/84tJfalemoX+JnmHNQoo/g==", "dependencies": { "tslib": "^2.3.0" }, @@ -7143,9 +7180,9 @@ } }, "node_modules/@onecx/angular-remote-components": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/angular-remote-components/-/angular-remote-components-4.40.2.tgz", - "integrity": "sha512-6/x/VZg/KPrrKkEBSGDi6v6nP6ELleCQ2err6gFPBCeoj2Ch4Yn5ays/Bdq8H+P73pYIFFp35gGVINPEyZfnKg==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/angular-remote-components/-/angular-remote-components-4.42.0.tgz", + "integrity": "sha512-sWtPOsvN2SbRtZUi6AIKLR1CJm9cAFMTMoCTs9xenQSYq7joJTnOI3I+1zQhekYvwxuFWxf0vxNINrcP+k7pdQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -7160,9 +7197,9 @@ } }, "node_modules/@onecx/angular-testing": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/angular-testing/-/angular-testing-4.40.2.tgz", - "integrity": "sha512-YCe7/etJsjyfFvc7yxZXNSILAFYxppiNTBFP5FYEVijTgdZiDT+vsiRMl8Whv5eLH+GeXe5VTQhLT43GA8ialQ==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/angular-testing/-/angular-testing-4.42.0.tgz", + "integrity": "sha512-QLTlgKofrSzcgP1DyhKPuhu4RDrUMBdx/nDLJGG6HpzkGXpAna6iGx77R2kU/fsFcJ8uTwEjdgLBVv8Vj2erAQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -7171,10 +7208,27 @@ "primeng": "^15.0.0" } }, + "node_modules/@onecx/angular-webcomponents": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/angular-webcomponents/-/angular-webcomponents-4.42.0.tgz", + "integrity": "sha512-VeooxAtnfUr4lEonO1JzA4SOpHkp5mxvhRXd2b8tFrIIwzlsLSLrD7TninGQ5+Bn0KXURCyIeamYAiF5B+Sh0g==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": "^15.2.7", + "@angular/elements": "^15.2.7", + "@angular/platform-browser": "^15.2.7", + "@angular/router": "^15.2.7", + "@onecx/accelerator": "^4", + "@onecx/portal-integration-angular": "^4", + "rxjs": "~7.8.0" + } + }, "node_modules/@onecx/integration-interface": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/integration-interface/-/integration-interface-4.40.2.tgz", - "integrity": "sha512-/4JvXsJ9ARyJ530gg1w3c998Py6Qm5wv/5r3PcTI56LgKBxR0DPuqIcaHXINH/hFVUij7exeRSLhF2QPO79FvA==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/integration-interface/-/integration-interface-4.42.0.tgz", + "integrity": "sha512-dXpbxEU4xaln+ABI5DACYGvMnkYHJw6O85YJjhVANYqCERvK5im5wCaP54IFmdFneBKskLYByHUqRzu8Qhs8Xw==", "peerDependencies": { "@onecx/accelerator": "^4", "rxjs": "7.8.1", @@ -7182,9 +7236,9 @@ } }, "node_modules/@onecx/keycloak-auth": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/keycloak-auth/-/keycloak-auth-4.40.2.tgz", - "integrity": "sha512-t0EWS5vie+A8+t43EXDVh6BHICEkBbnbLHAjI/MWawH0j66pEjfeRumNpzt/GBWW+3016c3XiQWQZNGKl1pHHg==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/keycloak-auth/-/keycloak-auth-4.42.0.tgz", + "integrity": "sha512-MQF5gpGFf//w6zZrTt2CmRkbWyGATsl279y3MlLp4UkvPFanD5d1wNFE2MKbqKmO03oftOezWM1lzaMgQ5xK4Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -7199,9 +7253,9 @@ } }, "node_modules/@onecx/portal-integration-angular": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/portal-integration-angular/-/portal-integration-angular-4.40.2.tgz", - "integrity": "sha512-oTcXXTy0ef3cEx7KogjPMhI2nMwlpxjchJbGOazJEV3TQxGa/v2cdQgvy3a8ExknfKInYmRnBx9Wc1cci5cLww==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/portal-integration-angular/-/portal-integration-angular-4.42.0.tgz", + "integrity": "sha512-zVJlDgTsFixZ8GYvMIJ700Tz/ebahYN+Mt44Ge+6bQa4bes15vo22eTZ5fPtGFYh8x+gGsR/2bEkroKKyNeTNg==", "dependencies": { "tslib": "^2.3.0" }, @@ -7232,9 +7286,9 @@ } }, "node_modules/@onecx/portal-layout-styles": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@onecx/portal-layout-styles/-/portal-layout-styles-4.40.2.tgz", - "integrity": "sha512-qjM1F0fqJEd5bah0HWweMDHc61KYr4Z+ypUGVAnlMAVCq9z2mTA8gycwt8feA5XQgsOnVLF5lNapSQzPAZHrxw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@onecx/portal-layout-styles/-/portal-layout-styles-4.42.0.tgz", + "integrity": "sha512-REw28qQgA3v8V+sVIipO86RH6wP8o2CpOSzd5k+ffQjh1JXXgiVCthndqRGZMCCxgoJAWbF1Y0iU2+PPJWUxcA==", "peerDependencies": { "tslib": "^2.5.0" } @@ -13408,6 +13462,11 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@webcomponents/webcomponentsjs": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.8.0.tgz", + "integrity": "sha512-loGD63sacRzOzSJgQnB9ZAhaQGkN7wl2Zuw7tsphI5Isa0irijrRo6EnJii/GgjGefIFO8AIO7UivzRhFaEk9w==" + }, "node_modules/@xmldom/xmldom": { "version": "0.8.10", "license": "MIT", diff --git a/package.json b/package.json index b4e211c..1dff4fb 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@angular/common": "15.2.7", "@angular/compiler": "15.2.7", "@angular/core": "15.2.7", + "@angular/elements": "15.2.7", "@angular/forms": "15.2.7", "@angular/platform-browser": "15.2.7", "@angular/platform-browser-dynamic": "15.2.7", @@ -52,15 +53,18 @@ "@ngrx/router-store": "^15.4.0", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", - "@onecx/accelerator": "^4.39.0", - "@onecx/angular-accelerator": "^4.39.0", - "@onecx/angular-integration-interface": "^4.39.0", - "@onecx/angular-remote-components": "^4.39.0", - "@onecx/angular-testing": "^4.39.0", - "@onecx/integration-interface": "^4.39.0", - "@onecx/keycloak-auth": "^4.39.0", - "@onecx/portal-integration-angular": "^4.39.0", - "@onecx/portal-layout-styles": "^4.39.0", + "@onecx/accelerator": "^4.42.0", + "@onecx/angular-accelerator": "^4.42.0", + "@onecx/angular-auth": "^4.42.0", + "@onecx/angular-integration-interface": "^4.42.0", + "@onecx/angular-remote-components": "^4.42.0", + "@onecx/angular-webcomponents": "^4.42.0", + "@onecx/angular-testing": "^4.42.0", + "@onecx/integration-interface": "^4.42.0", + "@onecx/keycloak-auth": "^4.42.0", + "@onecx/portal-integration-angular": "^4.42.0", + "@onecx/portal-layout-styles": "^4.42.0", + "@webcomponents/webcomponentsjs": "^2.8.0", "file-saver": "^2.0.5", "i18n-iso-countries": "^7.11.0", "keycloak-angular": "^13.1.0", diff --git a/src/app/app-entrypoint.component.html b/src/app/app-entrypoint.component.html new file mode 100644 index 0000000..0680b43 --- /dev/null +++ b/src/app/app-entrypoint.component.html @@ -0,0 +1 @@ + diff --git a/src/app/app-entrypoint.component.ts b/src/app/app-entrypoint.component.ts new file mode 100644 index 0000000..de82f4c --- /dev/null +++ b/src/app/app-entrypoint.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core' + +@Component({ + selector: 'app-root', + templateUrl: './app-entrypoint.component.html' +}) +export class AppEntrypointComponent {} diff --git a/src/app/onecx-theme-remote.module.ts b/src/app/onecx-theme-remote.module.ts index 8223d7a..eb1c4ac 100644 --- a/src/app/onecx-theme-remote.module.ts +++ b/src/app/onecx-theme-remote.module.ts @@ -1,27 +1,44 @@ -import { HttpClient } from '@angular/common/http' -import { NgModule } from '@angular/core' -import { RouterModule, Routes } from '@angular/router' +import { HttpClient, HttpClientModule } from '@angular/common/http' +import { BrowserModule } from '@angular/platform-browser' +import { APP_INITIALIZER, DoBootstrap, Injector, NgModule } from '@angular/core' +import { Router, RouterModule, Routes } from '@angular/router' import { MissingTranslationHandler, TranslateLoader, TranslateModule } from '@ngx-translate/core' import { AppStateService, ConfigurationService, createTranslateLoader, + PortalApiConfiguration, PortalCoreModule, PortalMissingTranslationHandler } from '@onecx/portal-integration-angular' import { addInitializeModuleGuard } from '@onecx/angular-integration-interface' +import { createAppEntrypoint, initializeRouter, startsWith } from '@onecx/angular-webcomponents' +import { AppEntrypointComponent } from './app-entrypoint.component' +import { AngularAuthModule } from '@onecx/angular-auth' +import { BrowserAnimationsModule } from '@angular/platform-browser/animations' +import { environment } from 'src/environments/environment' +import { Configuration } from './shared/generated' + +function apiConfigProvider(configService: ConfigurationService, appStateService: AppStateService) { + return new PortalApiConfiguration(Configuration, environment.apiPrefix, configService, appStateService) +} const routes: Routes = [ { - path: '', + matcher: startsWith(''), loadChildren: () => import('./theme/theme.module').then((m) => m.ThemeModule) } ] @NgModule({ + declarations: [AppEntrypointComponent], imports: [ + AngularAuthModule, + BrowserAnimationsModule, + BrowserModule, + HttpClientModule, PortalCoreModule.forMicroFrontend(), - RouterModule.forChild(addInitializeModuleGuard(routes)), + RouterModule.forRoot(addInitializeModuleGuard(routes)), TranslateModule.forRoot({ isolate: true, loader: { @@ -33,11 +50,24 @@ const routes: Routes = [ }) ], exports: [], - providers: [ConfigurationService], + providers: [ + ConfigurationService, + { + provide: APP_INITIALIZER, + useFactory: initializeRouter, + multi: true, + deps: [Router, AppStateService] + }, + { provide: Configuration, useFactory: apiConfigProvider, deps: [ConfigurationService, AppStateService] } + ], schemas: [] }) -export class OneCXThemeModule { - constructor() { +export class OneCXThemeModule implements DoBootstrap { + constructor(private injector: Injector) { console.info('OneCX Theme Module constructor') } + + ngDoBootstrap(): void { + createAppEntrypoint(AppEntrypointComponent, 'ocx-theme-component', this.injector) + } } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 33ddda5..61c8512 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -12,7 +12,7 @@ import { ConfirmPopupModule } from 'primeng/confirmpopup' import { ConfirmationService } from 'primeng/api' import { DataViewModule } from 'primeng/dataview' import { DialogModule } from 'primeng/dialog' -import { DialogService, DynamicDialogModule } from 'primeng/dynamicdialog' +import { DynamicDialogModule } from 'primeng/dynamicdialog' import { DropdownModule } from 'primeng/dropdown' import { FileUploadModule } from 'primeng/fileupload' import { InputTextModule } from 'primeng/inputtext' @@ -27,24 +27,12 @@ import { TabViewModule } from 'primeng/tabview' import { TableModule } from 'primeng/table' import { ToastModule } from 'primeng/toast' -import { - AppStateService, - ConfigurationService, - PortalDialogService, - PortalApiConfiguration, - PortalCoreModule -} from '@onecx/portal-integration-angular' +import { PortalCoreModule } from '@onecx/portal-integration-angular' -import { Configuration } from 'src/app/shared/generated' import { LabelResolver } from './label.resolver' -import { environment } from 'src/environments/environment' import { ImageContainerComponent } from './image-container/image-container.component' import { ThemeColorBoxComponent } from './theme-color-box/theme-color-box.component' -export function apiConfigProvider(configService: ConfigurationService, appStateService: AppStateService) { - return new PortalApiConfiguration(Configuration, environment.apiPrefix, configService, appStateService) -} - @NgModule({ declarations: [ImageContainerComponent, ThemeColorBoxComponent], imports: [ @@ -128,12 +116,7 @@ export function apiConfigProvider(configService: ConfigurationService, appStateS TranslateModule ], //this is not elegant, for some reason the injection token from primeng does not work across federated module - providers: [ - ConfirmationService, - LabelResolver, - { provide: DialogService, useClass: PortalDialogService }, - { provide: Configuration, useFactory: apiConfigProvider, deps: [ConfigurationService, AppStateService] } - ], + providers: [ConfirmationService, LabelResolver], schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA] }) export class SharedModule {} diff --git a/src/bootstrap.ts b/src/bootstrap.ts index 4d4077a..f909f5e 100644 --- a/src/bootstrap.ts +++ b/src/bootstrap.ts @@ -1,13 +1,5 @@ -import { enableProdMode } from '@angular/core' -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' -import { AppModule } from './app/app.module' +import { environment } from 'src/environments/environment' +import { OneCXThemeModule } from './app/onecx-theme-remote.module' +import { bootstrapModule } from '@onecx/angular-webcomponents' -import { environment } from './environments/environment' - -if (environment.production) { - enableProdMode() -} - -platformBrowserDynamic() - .bootstrapModule(AppModule) - .catch((err) => console.error(err)) +bootstrapModule(OneCXThemeModule, 'microfrontend', environment.production) diff --git a/webpack.config.js b/webpack.config.js index 04a4fad..d6990a9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -5,7 +5,7 @@ const config = withModuleFederationPlugin({ name: 'onecx-theme-ui', filename: 'remoteEntry.js', exposes: { - './OneCXThemeModule': 'src/app/onecx-theme-remote.module.ts' + './OneCXThemeModule': 'src/bootstrap.ts' }, shared: share({ '@angular/core': { singleton: true, requiredVersion: 'auto' }, @@ -47,5 +47,17 @@ const plugins = config.plugins.filter((plugin) => !(plugin instanceof ModifyEntr module.exports = { ...config, - plugins + plugins, + output: { + uniqueName: 'onecx-theme-ui', + publicPath: 'auto' + }, + experiments: { + ...config.experiments, + topLevelAwait: true + }, + optimization: { + runtimeChunk: false, + splitChunks: false + } }