Skip to content

Commit

Permalink
feat(labs/ssr): Prevent exposure of window object on globalThis (#3431)
Browse files Browse the repository at this point in the history
  • Loading branch information
steveworkman committed Dec 13, 2022
1 parent 9f7e7e3 commit ff637f5
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 32 deletions.
7 changes: 7 additions & 0 deletions .changeset/loud-radios-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@lit-labs/ssr': major
---

The Lit SSR DOM shim no longer defines a global `window` variable. This was removed to improve compatibility with libraries that detect whether they are running in Node vs the browser by checking for the presence of `window`.

If you have code that runs during SSR which depends on the presence of `window`, you can either replace `window` with `globalThis`, or use `isSsr` to avoid running that code on the server (see https://lit.dev/docs/ssr/authoring/#browser-only-code).
5 changes: 0 additions & 5 deletions packages/labs/ssr/src/lib/dom-shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,6 @@ export const getWindow = ({
...props,
};

window.window = window;

if (includeJSBuiltIns) {
Object.assign(window, {
// No-op any async tasks
Expand Down Expand Up @@ -204,8 +202,5 @@ export const installWindowOnGlobal = (props: {[key: string]: unknown} = {}) => {
const window = getWindow({props});
// Copy initial window globals to node global
Object.assign(globalThis, window);
// Set up global reference to window so all globals added to window are
// added to the node global
globalThis.window = globalThis as typeof globalThis & Window;
}
};
3 changes: 2 additions & 1 deletion packages/labs/ssr/src/test/integration/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ export const ssrMiddleware = () => {
module = await import(`../tests/${testFile}-ssr.js`);
} else {
// mode === 'vm'
const window = getWindow({includeJSBuiltIns: true});
const loader = new ModuleLoader({
global: getWindow({includeJSBuiltIns: true}),
global: window,
});
module = (
await loader.importModule(
Expand Down
57 changes: 35 additions & 22 deletions packages/labs/ssr/src/test/lib/dom-shim_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,44 @@
* SPDX-License-Identifier: BSD-3-Clause
*/

import {getWindow} from '../../lib/dom-shim.js';
import {installWindowOnGlobal, getWindow} from '../../lib/dom-shim.js';
import {test} from 'uvu';
// eslint-disable-next-line import/extensions
import * as assert from 'uvu/assert';

const window = getWindow({}) as unknown as Window;
const {HTMLElement} = window.window;
function testWithHtmlElement(HTMLElement: any) {
test('elements without an attached shadow root should expose a null value from the "shadowRoot" property', () => {
class UnattachedShadowRoot extends HTMLElement {}
const element = new UnattachedShadowRoot();
assert.is(element.shadowRoot, null);
});
test('elements defined with an open shadow root should expose it\'s shadow root from the "shadowRoot" property', () => {
class OpenShadowRoot extends HTMLElement {}
const element = new OpenShadowRoot();
const shadow = element.attachShadow({mode: 'open'});
assert.is(shadow, element.shadowRoot);
assert.is(shadow.host, element);
});
test('elements defined with a closed shadow root should expose a null value from the "shadowRoot" property', () => {
class ClosedShadowRoot extends HTMLElement {}
const element = new ClosedShadowRoot();
element.attachShadow({mode: 'closed'});
assert.is(element.shadowRoot, null);
});

test('elements without an attached shadow root should expose a null value from the "shadowRoot" property', () => {
class UnattachedShadowRoot extends HTMLElement {}
const element = new UnattachedShadowRoot();
assert.is(element.shadowRoot, null);
});
test('elements defined with an open shadow root should expose it\'s shadow root from the "shadowRoot" property', () => {
class OpenShadowRoot extends HTMLElement {}
const element = new OpenShadowRoot();
const shadow = element.attachShadow({mode: 'open'});
assert.is(shadow, element.shadowRoot);
assert.is(shadow.host, element);
});
test('elements defined with a closed shadow root should expose a null value from the "shadowRoot" property', () => {
class ClosedShadowRoot extends HTMLElement {}
const element = new ClosedShadowRoot();
element.attachShadow({mode: 'closed'});
assert.is(element.shadowRoot, null);
});
test.run();
}

test.run();
function testWithGlobalShim() {
installWindowOnGlobal({});
const {HTMLElement} = globalThis;
testWithHtmlElement(HTMLElement);
}
function testWithWindow() {
const window = getWindow({});
const {HTMLElement} = window;
testWithHtmlElement(HTMLElement);
}

testWithWindow();
testWithGlobalShim();
9 changes: 5 additions & 4 deletions packages/labs/ssr/src/test/lib/render-lit_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import {RenderInfo} from '../../index.js';

import type * as testModule from '../test-files/render-test-module.js';

const window = getWindow({
includeJSBuiltIns: true,
props: {require: createRequire(import.meta.url)},
});
const loader = new ModuleLoader({
global: getWindow({
includeJSBuiltIns: true,
props: {require: createRequire(import.meta.url)},
}),
global: window,
});

/**
Expand Down

0 comments on commit ff637f5

Please sign in to comment.