From de446567e2bc83d58edfa1b4ad295a0d1b44e834 Mon Sep 17 00:00:00 2001 From: Philipp Pracht Date: Fri, 28 Jun 2024 13:51:55 +0200 Subject: [PATCH] Light dom container (#3697) --- code_quality.js | 2 +- .../create-dynamic-compound-container.cy.js | 86 +++++++++- .../wc/create-dynamic-wc-container.cy.js | 24 ++- container/public/package.json | 2 +- container/src/LuigiCompoundContainer.svelte | 57 ++++--- container/src/LuigiContainer.svelte | 154 ++++++++---------- container/src/main.ts | 2 +- .../LuigiCompoundContainer.svelte.d.ts | 6 + container/typings/LuigiContainer.svelte.d.ts | 6 + docs/luigi-compound-container-api.md | 10 ++ docs/luigi-container-api.md | 12 +- docs/luigi-core-api.md | 2 +- prettier_config.json | 1 + scripts/npmPublish.sh | 3 +- 14 files changed, 237 insertions(+), 130 deletions(-) diff --git a/code_quality.js b/code_quality.js index e89f8365fc..843e357a81 100644 --- a/code_quality.js +++ b/code_quality.js @@ -108,7 +108,7 @@ const groupFilesByExtension = files => { const prettifyFile = (file, config) => { try { const text = fs.readFileSync(file).toString(); - if (prettier.check(text, config)) { + if (prettier.check(text, config) || config?.excludedFiles?.includes(file)) { return; } diff --git a/container/cypress/e2e/test-app/compound/create-dynamic-compound-container.cy.js b/container/cypress/e2e/test-app/compound/create-dynamic-compound-container.cy.js index 987afff9fd..bf9a94609a 100644 --- a/container/cypress/e2e/test-app/compound/create-dynamic-compound-container.cy.js +++ b/container/cypress/e2e/test-app/compound/create-dynamic-compound-container.cy.js @@ -173,12 +173,84 @@ describe('create luigi-compound-container dynamically', () => { cy.get('luigi-compound-container') .shadow() - .then($container => { - cy.wrap($container) - .find( - 'luigi-wc-68747470733a2f2f6c75696769776562636f6d706f6e656e74732e6769746c61622e696f2f6e6573746564322e6a73' - ) - .should('not.exist'); - }); + .should('not.exist'); + }); + it('luigi compound container with no shadow dom', () => { + const scriptCode = ` + + `; + const stub = cy.stub(); + cy.on('window:alert', stub); + cy.visit(tetsPage); + cy.get('.content').invoke('append', scriptCode); + cy.get('luigi-compound-container') + .shadow() + .should('not.exist'); }); }); diff --git a/container/cypress/e2e/test-app/wc/create-dynamic-wc-container.cy.js b/container/cypress/e2e/test-app/wc/create-dynamic-wc-container.cy.js index 1b23247c5b..033758ff4b 100644 --- a/container/cypress/e2e/test-app/wc/create-dynamic-wc-container.cy.js +++ b/container/cypress/e2e/test-app/wc/create-dynamic-wc-container.cy.js @@ -73,9 +73,27 @@ describe('Create luigi-container dynamically', () => { cy.get('.content').invoke('append', htmlCode); cy.get('[data-test-id="luigi-container"]') .shadow() - .find( - 'luigi-wc-687474703a2f2f6c6f63616c686f73743a383038302f68656c6c6f576f726c64574353656c66526567697374657265642e6a73' - ) + .should('not.exist'); + }); + + it('no shadow dom for LuigiContainer', () => { + cy.once('uncaught:exception', () => false); + const scriptCode = ` + const lc = document.querySelector('#lc'); + lc.viewurl = "./wc/helloWorldWC.js"; + lc.webcomponent = true; + lc.noShadow = true; + `; + const htmlCode = ` + + + `; + const stub = cy.stub(); + cy.on('window:alert', stub); + cy.visit(tetsPage); + cy.get('.content').invoke('append', htmlCode); + cy.get('[data-test-id="luigi-container"]') + .shadow() .should('not.exist'); }); }); diff --git a/container/public/package.json b/container/public/package.json index be1a00d53e..a13be14813 100644 --- a/container/public/package.json +++ b/container/public/package.json @@ -19,5 +19,5 @@ "micro-frontends", "microfrontends" ], - "version": "1.1.0" + "version": "1.2.0-rc3" } diff --git a/container/src/LuigiCompoundContainer.svelte b/container/src/LuigiCompoundContainer.svelte index a385f702b3..42a074acd4 100644 --- a/container/src/LuigiCompoundContainer.svelte +++ b/container/src/LuigiCompoundContainer.svelte @@ -1,10 +1,12 @@ { - mainComponent._luigi_mfe_webcomponent.context = contextObj; + (thisComponent.getNoShadow() ? thisComponent : mainComponent)._luigi_mfe_webcomponent.context = contextObj; }; const ctx = GenericHelperFunctions.resolveContext(context); deferInit = false; @@ -109,32 +116,34 @@ const node = { compound: compoundConfig, viewUrl: viewurl, - webcomponent: - GenericHelperFunctions.checkWebcomponentValue(webcomponent) || true, + webcomponent: GenericHelperFunctions.checkWebcomponentValue(webcomponent) || true }; // TODO: fill with sth - webcomponentService - .renderWebComponentCompound(node, mainComponent, ctx) - .then((compCnt) => { - eventBusElement = compCnt as HTMLElement; - if (thisComponent.hasAttribute('skip-init-check') || !node.viewUrl) { - thisComponent.initialized = true; - setTimeout(() => { - webcomponentService.dispatchLuigiEvent(Events.INITIALIZED, {}); - }); - } else if ( - (eventBusElement as any).LuigiClient && - !(eventBusElement as any).deferLuigiClientWCInit - ) { - thisComponent.initialized = true; + if(!thisComponent.getNoShadow()){ + mainComponent.innerHTML='' + const shadow = thisComponent.attachShadow({ mode: "open"}); + shadow.append(mainComponent); + }else{ + //removing mainComponent + thisComponent.innerHTML = ''; + } + webcomponentService.renderWebComponentCompound(node, thisComponent.getNoShadow() ? thisComponent : mainComponent, ctx).then(compCnt => { + eventBusElement = compCnt as HTMLElement; + if (thisComponent.hasAttribute('skip-init-check') || !node.viewUrl) { + thisComponent.initialized = true; + setTimeout(() => { webcomponentService.dispatchLuigiEvent(Events.INITIALIZED, {}); - } - }); + }); + } else if ((eventBusElement as any).LuigiClient && !(eventBusElement as any).deferLuigiClientWCInit) { + thisComponent.initialized = true; + webcomponentService.dispatchLuigiEvent(Events.INITIALIZED, {}); + } + }); containerInitialized = true; thisComponent.containerInitialized = true; }; onMount(async () => { - const thisComponent: any = (mainComponent.getRootNode() as ShadowRoot).host; + const thisComponent: any = mainComponent.getRootNode() === document ? mainComponent.parentNode : (mainComponent.getRootNode() as ShadowRoot).host; thisComponent.init = () => { initialize(thisComponent); @@ -156,4 +165,4 @@ height: 100%; border: none; } - + \ No newline at end of file diff --git a/container/src/LuigiContainer.svelte b/container/src/LuigiContainer.svelte index f6c6cd6972..d3807e096e 100644 --- a/container/src/LuigiContainer.svelte +++ b/container/src/LuigiContainer.svelte @@ -1,68 +1,35 @@ { - let notInitFn = (name) => { - return () => - console.warn( - name + - " can't be called on luigi-container before its micro frontend is attached to the DOM.", - ); + extend: customElementConstructor => { + let notInitFn = name => { + return () => console.warn(name + " can't be called on luigi-container before its micro frontend is attached to the DOM."); }; + return class extends customElementConstructor { sendCustomMessage = notInitFn('sendCustomMessage'); updateContext = notInitFn('updateContext'); @@ -71,9 +38,12 @@ if (this.containerInitialized && name === 'context') { this.updateContext(JSON.parse(newValue)); } - } + }; + getNoShadow(){ + return this.hasAttribute('no-shadow') || this.noShadow + }; }; - }, + } }} /> @@ -91,6 +61,7 @@ export let label: string; export let webcomponent: any; export let deferInit: boolean; + export let noShadow: Boolean; export let locale: string; export let theme: string; export let activeFeatureToggleList: string[]; @@ -105,7 +76,6 @@ export let allowRules: string[]; export let sandboxRules: string[]; - export let userSettings: any; export let anchor: string; @@ -145,16 +115,16 @@ thisComponent.sendCustomMessage = (id: string, data?: any) => { ContainerAPI.sendCustomMessage( id, - mainComponent, + thisComponent.getNoShadow() ? thisComponent : mainComponent, !!webcomponent, iframeHandle, - data, + data ); }; thisComponent.updateContext = (contextObj: any, internal?: any) => { - if (webcomponent) { - mainComponent._luigi_mfe_webcomponent.context = contextObj; + if (webcomponent) { + (thisComponent.getNoShadow() ? thisComponent : mainComponent)._luigi_mfe_webcomponent.context = contextObj; } else { ContainerAPI.updateContext(contextObj, internal, iframeHandle); } @@ -168,18 +138,29 @@ webcomponentService.thisComponent = thisComponent; const ctx = GenericHelperFunctions.resolveContext(context); - if (webcomponent && webcomponent != "false") { - mainComponent.innerHTML = ''; - const webComponentValue = - GenericHelperFunctions.checkWebcomponentValue(webcomponent); + if (webcomponent && webcomponent != 'false') { + if(!thisComponent.getNoShadow()){ + mainComponent.innerHTML='' + const shadow = thisComponent.attachShadow({ mode: "open"}); + shadow.append(mainComponent); + }else{ + //removing mainComponent + thisComponent.innerHTML = ''; + } + const webComponentValue = GenericHelperFunctions.checkWebcomponentValue(webcomponent); webcomponentService.renderWebComponent( viewurl, - mainComponent, + thisComponent.getNoShadow() ? thisComponent : mainComponent, ctx, - typeof webComponentValue === 'object' - ? { webcomponent: webComponentValue } - : {}, + typeof webComponentValue === 'object' ? { webcomponent: webComponentValue } : {} ); + }else{ + if(!thisComponent.getNoShadow()){ + //removeing mainComponent + thisComponent.innerHTML=''; + const shadow = thisComponent.attachShadow({ mode: "open"}); + shadow.append(mainComponent); + } } if (skipInitCheck) { thisComponent.initialized = true; @@ -187,11 +168,8 @@ webcomponentService.dispatchLuigiEvent(Events.INITIALIZED, {}); }); } else if (webcomponent) { - mainComponent.addEventListener('wc_ready', () => { - if ( - !(mainComponent as any)._luigi_mfe_webcomponent - ?.deferLuigiClientWCInit - ) { + (thisComponent.getNoShadow() ? thisComponent : mainComponent).addEventListener('wc_ready', () => { + if (!(thisComponent.getNoShadow() ? thisComponent : (mainComponent as any))._luigi_mfe_webcomponent?.deferLuigiClientWCInit) { thisComponent.initialized = true; webcomponentService.dispatchLuigiEvent(Events.INITIALIZED, {}); } @@ -203,7 +181,7 @@ }; onMount(async () => { - const thisComponent: any = (mainComponent.getRootNode() as ShadowRoot).host; + const thisComponent: any = mainComponent.parentNode; thisComponent.iframeHandle = iframeHandle; thisComponent.init = () => { initialize(thisComponent); @@ -216,12 +194,21 @@ onDestroy(async () => {}); -
+
{#if containerInitialized} - {#if !webcomponent || webcomponent === "false"} + {#if !webcomponent || webcomponent === 'false'} +