Skip to content

Commit

Permalink
refactor(framework): remove the CSP module (#8496)
Browse files Browse the repository at this point in the history
Previously, we used <style> and <link> tags to style web components due to the lack of browser support for adoptedStyleSheets. However, as  latest version of all relevant browsers now support "adoptedStyleSheets", we are removing all additional functionality that was implemented to compensate for the missing support and rely entirely on "adoptedStyleSheets". As a result, there is no need of additional handling to full-fill Content Security Policy (CSP) requirements, because adoptedStyleSheets are CSP compliant.

BREAKING CHANGE: Removed the `CSP.js` module and the creation of `<style>` and `<link>` tags, as all browsers now support adoptedStyleSheets. The following APIs are not available any more and should not be used:
```ts
import { setUseLinks } from "@ui5/webcomponents-base/dist/CSP.js"
import { setPackageCSSRoot } from "@ui5/webcomponents-base/dist/CSP.js"
import { setPreloadLinks } from "@ui5/webcomponents-base/dist/CSP.js"
```

Related to [#8461](#8461)
  • Loading branch information
nnaydenow authored Mar 21, 2024
1 parent 7656a93 commit aa463d9
Show file tree
Hide file tree
Showing 20 changed files with 33 additions and 396 deletions.
101 changes: 0 additions & 101 deletions docs/2-advanced/08-CSP.md

This file was deleted.

8 changes: 0 additions & 8 deletions packages/base/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ Contains the base files for all Web Components, most notably `@ui5/webcomponents
Components | `import applyDirection from "@ui5/webcomponents-base/dist/locale/applyDirection.js"`| Applies direction ("ltr"/"rtl") - re-renders all RTL-aware components |
Components | `import { setCustomElementsScopingSuffix } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"`| Adds suffix to the tag names of all components |
Components | `@ui5/webcomponents-base/dist/util/InvisibleMessage.js` | Provides a way to expose dynamic content changes that can be announced by screen readers |
CSP compliance| `import { setPackageCSSRoot } from "@ui5/webcomponents-base/dist/CSP.js"`| Sets directory path where the CSS resources for given package will be served from |
CSP compliance| `import { setUseLinks } from "@ui5/webcomponents-base/dist/CSP.js"` | Enables or disables the usage of `<link>` tags instead of `<style>` tags |
CSP compliance| `import { setPreloadLinks } from "@ui5/webcomponents-base/dist/CSP.js"` | Enables or disables the preloading of `<link>` tags |

### `applyDirection.js`
- `applyDirection`
Expand All @@ -42,11 +39,6 @@ Contains the base files for all Web Components, most notably `@ui5/webcomponents

- `ignoreCustomElements`

### `CSP.js`
- `setPackageCSSRoot`
- `setUseLinks`
- `setPreloadLinks`

### `i18nBundle.js`

- `registerI18nLoader`
Expand Down
12 changes: 0 additions & 12 deletions packages/base/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@ import { registerIconLoader } from "./dist/asset-registries/Icons.js";
// Boot.ts
import { attachBoot } from "./dist/Boot.js";

// CSP.ts
import {
setPackageCSSRoot,
setUseLinks,
setPreloadLinks,
} from "./dist/CSP.js";

// CustomElementsScope.ts
import {
setCustomElementsScopingSuffix,
Expand Down Expand Up @@ -172,11 +165,6 @@ export {
// Boot.ts
attachBoot,

// CSP.ts
setPackageCSSRoot,
setUseLinks,
setPreloadLinks,

// CustomElementsScope.ts
setCustomElementsScopingSuffix,
getCustomElementsScopingSuffix,
Expand Down
69 changes: 0 additions & 69 deletions packages/base/src/CSP.ts

This file was deleted.

116 changes: 21 additions & 95 deletions packages/base/src/ManagedStyles.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import createStyleInHead from "./util/createStyleInHead.js";
import createLinkInHead from "./util/createLinkInHead.js";
import { shouldUseLinks, getUrl } from "./CSP.js";
import { StyleData, StyleDataCSP } from "./types.js";
import { isSafari } from "./Device.js";
import { getCurrentRuntimeIndex, compareRuntimes } from "./Runtimes.js";

const isSSR = typeof document === "undefined";
Expand All @@ -22,87 +18,34 @@ const createStyle = (data: StyleData, name: string, value = "", theme?: string)
const content = typeof data === "string" ? data : data.content;
const currentRuntimeIndex = getCurrentRuntimeIndex();

if (shouldUseLinks()) {
const attributes = {} as Record<string, any>;
attributes[name] = value;
if (theme) {
attributes["data-ui5-runtime-index"] = currentRuntimeIndex;
attributes["data-ui5-theme"] = theme;
}
const href = getUrl((data as StyleDataCSP).packageName, (data as StyleDataCSP).fileName);
createLinkInHead(href, attributes);
} else if (document.adoptedStyleSheets && !isSafari()) {
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync(content);
(stylesheet as Record<string, any>)._ui5StyleId = getStyleId(name, value); // set an id so that we can find the style later
if (theme) {
(stylesheet as Record<string, any>)._ui5RuntimeIndex = currentRuntimeIndex;
(stylesheet as Record<string, any>)._ui5Theme = theme;
}
document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
} else {
const attributes = {} as Record<string, any>;
attributes[name] = value;
if (theme) {
attributes["data-ui5-runtime-index"] = currentRuntimeIndex;
attributes["data-ui5-theme"] = theme;
}
createStyleInHead(content, attributes);
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync(content);
(stylesheet as Record<string, any>)._ui5StyleId = getStyleId(name, value); // set an id so that we can find the style later
if (theme) {
(stylesheet as Record<string, any>)._ui5RuntimeIndex = currentRuntimeIndex;
(stylesheet as Record<string, any>)._ui5Theme = theme;
}
document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
};

const updateStyle = (data: StyleData, name: string, value = "", theme?: string) => {
const content = typeof data === "string" ? data : data.content;
const currentRuntimeIndex = getCurrentRuntimeIndex();

if (shouldUseLinks()) {
const link = document.querySelector(`head>link[${name}="${value}"]`) as HTMLLinkElement;
const href = getUrl((data as StyleDataCSP).packageName, (data as StyleDataCSP).fileName);

if (!theme) {
link.href = href;
} else {
const linkRuntimeIndex = link.getAttribute("data-ui5-runtime-index") || undefined;
const linkTheme = link.getAttribute("data-ui5-theme");
if (linkTheme !== theme || shouldUpdate(linkRuntimeIndex)) {
link.href = href;
link.setAttribute("data-ui5-runtime-index", String(currentRuntimeIndex));
link.setAttribute("data-ui5-theme", theme);
}
}
} else if (document.adoptedStyleSheets && !isSafari()) {
const stylesheet = document.adoptedStyleSheets.find(sh => (sh as Record<string, any>)._ui5StyleId === getStyleId(name, value));
if (!stylesheet) {
return;
}
const stylesheet = document.adoptedStyleSheets.find(sh => (sh as Record<string, any>)._ui5StyleId === getStyleId(name, value));
if (!stylesheet) {
return;
}

if (!theme) {
stylesheet.replaceSync(content || "");
} else {
const stylesheetRuntimeIndex: string | undefined = (stylesheet as Record<string, any>)._ui5RuntimeIndex;
const stylesheetTheme: string | undefined = (stylesheet as Record<string, any>)._ui5Theme;
if (stylesheetTheme !== theme || shouldUpdate(stylesheetRuntimeIndex)) {
stylesheet.replaceSync(content || "");
(stylesheet as Record<string, any>)._ui5RuntimeIndex = String(currentRuntimeIndex);
(stylesheet as Record<string, any>)._ui5Theme = theme;
}
}
if (!theme) {
stylesheet.replaceSync(content || "");
} else {
const style = document.querySelector(`head>style[${name}="${value}"]`);
if (!style) {
return;
}

if (!theme) {
style.textContent = content || "";
} else {
const styleRuntimeIndex = style.getAttribute("data-ui5-runtime-index") || undefined;
const styleTheme = style.getAttribute("data-ui5-theme");
if (styleTheme !== theme || shouldUpdate(styleRuntimeIndex)) {
style.textContent = content || "";
style.setAttribute("data-ui5-runtime-index", String(currentRuntimeIndex));
style.setAttribute("data-ui5-theme", theme);
}
const stylesheetRuntimeIndex: string | undefined = (stylesheet as Record<string, any>)._ui5RuntimeIndex;
const stylesheetTheme: string | undefined = (stylesheet as Record<string, any>)._ui5Theme;
if (stylesheetTheme !== theme || shouldUpdate(stylesheetRuntimeIndex)) {
stylesheet.replaceSync(content || "");
(stylesheet as Record<string, any>)._ui5RuntimeIndex = String(currentRuntimeIndex);
(stylesheet as Record<string, any>)._ui5Theme = theme;
}
}
};
Expand All @@ -111,29 +54,12 @@ const hasStyle = (name: string, value = ""): boolean => {
if (isSSR) {
return true;
}
if (shouldUseLinks()) {
return !!document.querySelector(`head>link[${name}="${value}"]`);
}

const styleElement = document.querySelector(`head>style[${name}="${value}"]`);

if (document.adoptedStyleSheets && !isSafari()) {
return !!styleElement || !!document.adoptedStyleSheets.find(sh => (sh as Record<string, any>)._ui5StyleId === getStyleId(name, value));
}

return !!styleElement;
return !!document.adoptedStyleSheets.find(sh => (sh as Record<string, any>)._ui5StyleId === getStyleId(name, value));
};

const removeStyle = (name: string, value = "") => {
if (shouldUseLinks()) {
const linkElement = document.querySelector(`head>link[${name}="${value}"]`);
linkElement?.parentElement?.removeChild(linkElement);
} else if (document.adoptedStyleSheets && !isSafari()) {
document.adoptedStyleSheets = document.adoptedStyleSheets.filter(sh => (sh as Record<string, any>)._ui5StyleId !== getStyleId(name, value));
} else {
const styleElement = document.querySelector(`head > style[${name}="${value}"]`);
styleElement?.parentElement?.removeChild(styleElement);
}
document.adoptedStyleSheets = document.adoptedStyleSheets.filter(sh => (sh as Record<string, any>)._ui5StyleId !== getStyleId(name, value));
};

const createOrUpdateStyle = (data: StyleData, name: string, value = "", theme?: string) => {
Expand Down
4 changes: 1 addition & 3 deletions packages/base/src/UI5Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import isValidPropertyName from "./util/isValidPropertyName.js";
import { getSlotName, getSlottedNodesList } from "./util/SlotsHelper.js";
import arraysAreEqual from "./util/arraysAreEqual.js";
import { markAsRtlAware } from "./locale/RTLAwareRegistry.js";
import preloadLinks from "./theming/preloadLinks.js";
import executeTemplate from "./renderer/executeTemplate.js";
import type { TemplateFunction, TemplateFunctionResult } from "./renderer/executeTemplate.js";
import type { PromiseResolve, ComponentStylesData, ClassMap } from "./types.js";
Expand All @@ -35,7 +34,7 @@ let autoId = 0;
const elementTimeouts = new Map<string, Promise<void>>();
const uniqueDependenciesCache = new Map<typeof UI5Element, Array<typeof UI5Element>>();

type Renderer = (templateResult: TemplateFunctionResult, container: HTMLElement | DocumentFragment, styleStrOrHrefsArr: string | Array<string> | undefined, forStaticArea: boolean, options: RendererOptions) => void;
type Renderer = (templateResult: TemplateFunctionResult, container: HTMLElement | DocumentFragment, forStaticArea: boolean, options: RendererOptions) => void;

type RendererOptions = {
/**
Expand Down Expand Up @@ -1139,7 +1138,6 @@ abstract class UI5Element extends HTMLElement {
this._generateAccessors();
registerTag(tag);
customElements.define(tag, this as unknown as CustomElementConstructor);
preloadLinks(this);
}
return this;
}
Expand Down
Loading

0 comments on commit aa463d9

Please sign in to comment.