Skip to content

Commit

Permalink
feat!: ssr (#2762)
Browse files Browse the repository at this point in the history
* fix(core)!: remove side effects from core import

Removes `window.PfeConfig` and auto-reveal features
Adds server checks to `createContextWithRoot`

* feat(tools): ssr test page

* test(accordion): ssr tests

* test(avatar): ssr tests

* test(back-to-top): ssr

* test(background-image): ssr

* test(badge): ssr

* test(banner): ssr

* test(button): ssr

* test(card): ssr

* test(chip): ssr

* test(clipboard-copy): ssr

* test(code-block): ssr

* test(dropdown): ssr

* test(icon): ssr

* test(jump-links): ssr

* test(label): ssr

* test(modal): ssr

* test(panel): ssr

* test(popover): ssr

* test(progress): ssr

* test(progress-stepper): ssr

* test(select): ssr

* test(spinner): ssr

* test(switch): ssr

* test(table): ssr

* test(tabs): ssr

* test(text-area): ssr

* test(text-area): ssr

* test(tile): ssr

* test(timestamp): ssr

* test(tooltip): ssr

* feat(create-element): ssr tests

* feat(tools): automatic ssr demos

* fix(tools): shim module

* docs: changesets

* test: remove cruft

* fix(tools): ssr error reports

* test: playwright config for ssr

* chore: ssr test workflow

* fix(tools): ssr error status message

* chore: ssr test workflow

* chore: ssr test workflow

* chore: ignore reports

* fix(accordion): ssrability

* fix(back-to-top): ssrability

* docs: jsdoc for ssr tests

* chore: test workflow in ci

* fix(core): fix Logger for ssr

* style: whitespace

* chore: better elements build

* fix(core): more ssr-able controllers

* test(back-to-top): ssrable demos

* fix(tools): redirects for demos in dev server

* fix(tools): ssr files

* test(background-image): ssrable demos

* fix(tools): 11ty demo images

* fix(core): floating dom controller more ssrable

* feat(tools): export ssr helpers

* fix(code-block): ssrable

* fix(jump-links): ssrable

* fix(core): ssrable ScrollSpyController

* fix(progress-stepper): ssrable

* fix(popover): ssrable

* fix(core): ssrable lbc

* fix(icon): ssr

* fix(select): ssrable

* fix(table): ssrable

* fix(text-area): ssrable

* fix(text-input): ssrable

* fix(tooltip): ssrable

* chore: pr reports

* fix(tools): update playwright

* chore: ssr workflow

* chore: ssr workflow

* chore: actions versions

* chore: ssr workflow

* chore: ssr workflow

* chore: ssr workflow

* chore: ssr workflow

* chore: ssr workflow

* chore: ssr workflow

* chore: ssr workflow
  • Loading branch information
bennypowers authored Jun 25, 2024
1 parent 25eaebc commit 5091c5c
Show file tree
Hide file tree
Showing 89 changed files with 1,562 additions and 253 deletions.
4 changes: 4 additions & 0 deletions .changeset/few-lands-feel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
"@patternfly/pfe-core": major
---
Removed global `pfeLog` feature
4 changes: 4 additions & 0 deletions .changeset/mean-tires-ask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
"@patternfly/pfe-core": major
---
Removed `window.PfeConfig` global config object
4 changes: 4 additions & 0 deletions .changeset/polite-rules-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
"@patternfly/pfe-core": major
---
Removed global `auto-reveal` feature
4 changes: 4 additions & 0 deletions .changeset/public-yaks-tickle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
"@patternfly/pfe-core": patch
---
Context: `makeContextRoot` no longer crashes SSR processes
4 changes: 4 additions & 0 deletions .changeset/thirty-hounds-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
"@patternfly/pfe-core": major
---
Removed global `trackPerformance` feature
4 changes: 2 additions & 2 deletions .github/workflows/bundle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ jobs:
if: github.repository == 'patternfly/patternfly-elements'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3
- uses: actions/setup-node@v3
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ jobs:
if: github.repository == 'patternfly/patternfly-elements'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
Expand Down
78 changes: 69 additions & 9 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ env:
# Bring color into the GitHub terminal
FORCE_COLOR: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PLAYWRIGHT_REPORT_DIR: test-report

# https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/
ACTIONS_ALLOW_UNSECURE_COMMANDS: "true"
Expand All @@ -45,11 +46,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Configures the node version used on GitHub-hosted runners
- name: Configure node version
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
Expand All @@ -61,17 +62,16 @@ jobs:
id: lint
run: npm run lint


test:
name: Run test suite (Web Test Runner)
name: Unit Tests (Web Test Runner)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Configures the node version used on GitHub-hosted runners
- name: Configure node version
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
Expand All @@ -91,6 +91,67 @@ jobs:
report_paths: test-results/test-results.xml
fail_on_failure: true # fail the actions run if the tests failed

ssr:
name: SSR Tests (Playwright)
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.44.0-jammy
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci --prefer-offline
- run: npm run build

- name: Run tests
run: npx playwright test -g ssr --update-snapshots
env:
HOME: /root

- uses: actions/upload-artifact@v2
if: always()
with:
name: ${{ env.PLAYWRIGHT_REPORT_DIR }}
path: ${{ env.PLAYWRIGHT_REPORT_DIR }}/
retention-days: 30

publish_report:
name: Publish Playwright Report
# using always() is not ideal here, because it would also run if the workflow was cancelled
if: "success() || needs.ssr.result == 'failure'"
needs:
- ssr
runs-on: ubuntu-latest
continue-on-error: true
env:
HTML_REPORT_URL_PATH: reports/${{ github.ref_name }}/${{ github.run_id }}/${{ github.run_attempt }}
steps:
- uses: actions/checkout@v4
- name: Download zipped HTML report
uses: actions/download-artifact@v2
with:
name: ${{ env.PLAYWRIGHT_REPORT_DIR }}
path: ${{ env.PLAYWRIGHT_REPORT_DIR }}/
- name: Upload to Github Pages
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: ${{ env.PLAYWRIGHT_REPORT_DIR }}
target-folder: ${{ env.HTML_REPORT_URL_PATH }}
- name: Add comment to PR
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.inputs.issueNumber }}
append: true
header: "${{ github.sha }}"
hide: true
hide_details: true
message: |
**SSR Test Run for ${{ github.sha }}**: [Report](https://patternfly.github.io/patternfly-elements/${{ env.HTML_REPORT_URL_PATH }})
# Validate the build to main was successful; open an issue if not
build:
name: Compile project
runs-on: ubuntu-latest
Expand All @@ -116,13 +177,13 @@ jobs:
)
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

# Configures the node version used on GitHub-hosted runners
- name: Configure node version
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: npm
Expand All @@ -138,7 +199,6 @@ jobs:
id: release-dry
run: npm run prepublishOnly -ws --if-present

# Validate the build to main was successful; open an issue if not
validate:
name: Validate successful build on main
needs:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/visual-regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
Expand All @@ -42,7 +42,7 @@ jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Generate URLs
id: urls
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pfe.min.js
**/*.LEGAL.txt
*.tsbuildinfo
test-results
test-report

/elements/react

Expand Down
4 changes: 2 additions & 2 deletions core/pfe-core/controllers/floating-dom-controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Placement } from '@floating-ui/dom';
import type { ReactiveController, ReactiveControllerHost } from 'lit';
import type { LitElement, ReactiveController, ReactiveControllerHost } from 'lit';
import type { StyleInfo } from 'lit/directives/style-map.js';
import type { OffsetOptions as Offset } from '@floating-ui/core';

Expand Down Expand Up @@ -100,7 +100,7 @@ export class FloatingDOMController implements ReactiveController {
) {
host.addController(this);
this.#options = {
invoker: (host instanceof HTMLElement ? () => host : () => undefined),
invoker: (() => host as LitElement),
shift: true,
...options,
};
Expand Down
21 changes: 18 additions & 3 deletions core/pfe-core/controllers/internals-controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { ReactiveController, ReactiveControllerHost } from 'lit';
import {
isServer,
type ReactiveController,
type ReactiveControllerHost,
type LitElement,
} from 'lit';

function isARIAMixinProp(key: string): key is keyof ARIAMixin {
return key === 'role' || key.startsWith('aria');
Expand Down Expand Up @@ -146,7 +151,11 @@ export class InternalsController implements ReactiveController, ARIAMixin {

/** True when the control is disabled via it's containing fieldset element */
get formDisabled() {
return this.element?.matches(':disabled') || this._formDisabled;
if (isServer) {
return this._formDisabled;
} else {
return this.element?.matches(':disabled') || this._formDisabled;
}
}

get labels() {
Expand All @@ -166,7 +175,13 @@ export class InternalsController implements ReactiveController, ARIAMixin {
}

private get element() {
return this.host instanceof HTMLElement ? this.host : this.options?.getHTMLElement?.();
if (isServer) {
// FIXME(bennyp): a little white lie, which may break
// when the controller is applied to non-lit frameworks.
return this.host as LitElement;
} else {
return this.host instanceof HTMLElement ? this.host : this.options?.getHTMLElement?.();
}
}

private internals!: ElementInternals;
Expand Down
6 changes: 4 additions & 2 deletions core/pfe-core/controllers/listbox-controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ReactiveController, ReactiveControllerHost } from 'lit';
import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit';

export interface ListboxAccessibilityController<
Item extends HTMLElement
Expand Down Expand Up @@ -56,7 +56,9 @@ export class ListboxController<Item extends HTMLElement> implements ReactiveCont
if (!constructingAllowed) {
throw new Error('ListboxController must be constructed with `ListboxController.of()`');
}
if (!(host instanceof HTMLElement) && typeof _options.getHTMLElement !== 'function') {
if (!isServer
&& !(host instanceof HTMLElement)
&& typeof _options.getHTMLElement !== 'function') {
throw new Error(
`ListboxController requires the host to be an HTMLElement, or for the initializer to include a \`getHTMLElement()\` function`,
);
Expand Down
4 changes: 2 additions & 2 deletions core/pfe-core/controllers/logger.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ReactiveController, ReactiveControllerHost } from 'lit';
import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit';

export class Logger implements ReactiveController {
private static logDebug: boolean;

private static instances = new WeakMap<ReactiveControllerHost, Logger>();

private get prefix() {
if (this.host instanceof HTMLElement) {
if (!isServer && this.host instanceof HTMLElement) {
return `[${this.host.localName}${this.host.id ? `#${this.host.id}` : ''}]`;
} else {
return `[${this.host.constructor.name}]`;
Expand Down
2 changes: 1 addition & 1 deletion core/pfe-core/controllers/overflow-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class OverflowController implements ReactiveController {

static {
// on resize check for overflows to add or remove scroll buttons
window.addEventListener('resize', () => {
globalThis.addEventListener?.('resize', () => {
for (const instance of this.#instances) {
instance.onScroll();
}
Expand Down
6 changes: 3 additions & 3 deletions core/pfe-core/controllers/scroll-spy-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class ScrollSpyController implements ReactiveController {
#rootMargin?: string;
#threshold: number | number[];

#rootNode: Node;
#getRootNode: () => Node;
#getHash: (el: Element) => string | null;

get #linkChildren(): Element[] {
Expand Down Expand Up @@ -92,7 +92,7 @@ export class ScrollSpyController implements ReactiveController {
this.#rootMargin = options.rootMargin;
this.#activeAttribute = options.activeAttribute ?? 'active';
this.#threshold = options.threshold ?? 0.85;
this.#rootNode = options.rootNode ?? host.getRootNode();
this.#getRootNode = () => options.rootNode ?? host.getRootNode();
this.#getHash = options?.getHash ?? ((el: Element) => el.getAttribute('href'));
}

Expand All @@ -101,7 +101,7 @@ export class ScrollSpyController implements ReactiveController {
}

#initIo() {
const rootNode = this.#rootNode;
const rootNode = this.#getRootNode();
if (rootNode instanceof Document || rootNode instanceof ShadowRoot) {
const { rootMargin, threshold, root } = this;
this.#io = new IntersectionObserver(r => this.#onIo(r), { root, rootMargin, threshold });
Expand Down
Loading

0 comments on commit 5091c5c

Please sign in to comment.