Skip to content

Commit

Permalink
fix: ensure doc.defaultView, url as string (#285)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley authored Mar 17, 2022
1 parent 2db1675 commit 3dcb7f3
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/server/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface DocumentOptions {
// (undocumented)
debug?: boolean;
// (undocumented)
url?: URL;
url?: URL | string;
}

// @alpha
Expand Down
29 changes: 3 additions & 26 deletions src/server/document.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { createTimer, ensureGlobals } from './utils';
import { dehydrate, FunctionComponent, JSXNode, render } from '@builder.io/qwik';
import qwikDom from '@builder.io/qwik-dom';
import { setServerPlatform } from './platform';
Expand All @@ -11,7 +12,6 @@ import type {
RenderToStringOptions,
RenderToStringResult,
} from './types';
import { createTimer } from './utils';

/**
* Create emulated `Global` for server environment. Does not implement a browser
Expand All @@ -22,27 +22,8 @@ export function createGlobal(opts?: GlobalOptions): QwikGlobal {
opts = opts || {};

const doc: QwikDocument = qwikDom.createDocument() as any;
const baseURI = opts.url === undefined ? BASE_URI : opts.url.href;
const loc = new URL(baseURI, BASE_URI);

Object.defineProperty(doc, 'baseURI', {
get: () => loc.href,
set: (url: string) => (loc.href = url),
});

const glb: any = {
document: doc,
location: loc,
CustomEvent: class CustomEvent {
type: string;
constructor(type: string, details: any) {
Object.assign(this, details);
this.type = type;
}
},
};

glb.document.defaultView = glb;
const glb = ensureGlobals(doc, opts);

return glb;
}
Expand All @@ -69,9 +50,7 @@ export async function renderToDocument(
rootNode: JSXNode<unknown> | FunctionComponent<any>,
opts: RenderToDocumentOptions
) {
if (!doc || doc.nodeType !== 9) {
throw new Error(`Invalid document`);
}
ensureGlobals(doc, opts);

await setServerPlatform(doc, opts);

Expand Down Expand Up @@ -108,5 +87,3 @@ export async function renderToString(rootNode: any, opts: RenderToStringOptions)

return result;
}

const BASE_URI = `http://document.qwik.dev/`;
4 changes: 2 additions & 2 deletions src/server/platform.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CorePlatform } from '@builder.io/qwik';
import { normalizeUrl } from './utils';
import { setPlatform } from '@builder.io/qwik';
import type { SerializeDocumentOptions } from './types';

const _setImmediate = typeof setImmediate === 'function' ? setImmediate : setTimeout;
// const _nextTick = typeof queueMicrotask === 'function' ? queueMicrotask : process.nextTick;

declare const require: (module: string) => Record<string, any>;

Expand All @@ -14,7 +14,7 @@ function createPlatform(document: any, opts: SerializeDocumentOptions) {
const doc: Document = document;
const symbols = opts.symbols;
if (opts?.url) {
doc.location.href = opts.url.href;
doc.location.href = normalizeUrl(opts.url).href;
}
const serverPlatform: CorePlatform = {
async importSymbol(_element, qrl, symbolName) {
Expand Down
2 changes: 1 addition & 1 deletion src/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface QwikDocument extends Document {}
* @public
*/
export interface DocumentOptions {
url?: URL;
url?: URL | string;
debug?: boolean;
}

Expand Down
56 changes: 56 additions & 0 deletions src/server/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { DocumentOptions } from './types';

/**
* Utility timer function for performance profiling.
* Returns a duration of 0 in environments that do not support performance.
Expand All @@ -14,3 +16,57 @@ export function createTimer() {
return delta / 1000000;
};
}

export function ensureGlobals(doc: any, opts: DocumentOptions) {
if (!doc[QWIK_DOC]) {
if (!doc || doc.nodeType !== 9) {
throw new Error(`Invalid document`);
}

doc[QWIK_DOC] = true;

const loc = normalizeUrl(opts.url);

Object.defineProperty(doc, 'baseURI', {
get: () => loc.href,
set: (url: string) => (loc.href = normalizeUrl(url).href),
});

doc.defaultView = {
get document() {
return doc;
},
get location() {
return loc;
},
get origin() {
return loc.origin;
},
CustomEvent: class CustomEvent {
type: string;
constructor(type: string, details: any) {
Object.assign(this, details);
this.type = type;
}
},
};
}

return doc.defaultView;
}

const QWIK_DOC = Symbol();

export function normalizeUrl(url: string | URL | undefined | null) {
if (url != null) {
if (typeof url === 'string') {
return new URL(url || '/', BASE_URI);
}
if (typeof url.href === 'string') {
return new URL(url.href || '/', BASE_URI);
}
}
return new URL(BASE_URI);
}

const BASE_URI = `http://document.qwik.dev/`;
92 changes: 92 additions & 0 deletions src/server/utils.unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { createDocument, createGlobal } from './document';
import { ensureGlobals, normalizeUrl } from './utils';

describe('normalizeUrl', () => {
it('no url', () => {
expect(normalizeUrl(null).href).toBe('http://document.qwik.dev/');
expect(normalizeUrl(undefined).href).toBe('http://document.qwik.dev/');
expect(normalizeUrl('').href).toBe('http://document.qwik.dev/');
expect(normalizeUrl({} as any).href).toBe('http://document.qwik.dev/');
});

it('string, full url', () => {
const url = normalizeUrl('https://my.qwik.dev/some-path?query=string#hash');
expect(url.pathname).toBe('/some-path');
expect(url.hash).toBe('#hash');
expect(url.searchParams.get('query')).toBe('string');
expect(url.origin).toBe('https://my.qwik.dev');
expect(url.href).toBe('https://my.qwik.dev/some-path?query=string#hash');
});

it('string, pathname', () => {
const url = normalizeUrl('/some-path?query=string#hash');
expect(url.pathname).toBe('/some-path');
expect(url.hash).toBe('#hash');
expect(url.searchParams.get('query')).toBe('string');
expect(url.origin).toBe('http://document.qwik.dev');
expect(url.href).toBe('http://document.qwik.dev/some-path?query=string#hash');
});
});

describe('ensureGlobals', () => {
it('baseURI', () => {
const glb = ensureGlobals({ nodeType: 9 }, { url: 'http://my.qwik.dev/my-path' });
expect(glb.document.baseURI).toBe('http://my.qwik.dev/my-path');

glb.document.baseURI = 'http://my.qwik.dev/new-path';
expect(glb.document.baseURI).toBe('http://my.qwik.dev/new-path');
});

it('location, no options', () => {
const glb = ensureGlobals({ nodeType: 9 }, {});
expect(glb.location.pathname).toBe('/');

glb.location.pathname = '/new-path';
expect(glb.location.pathname).toBe('/new-path');
});

it('location', () => {
const glb = ensureGlobals({ nodeType: 9 }, { url: '/my-path' });
expect(glb.location.pathname).toBe('/my-path');
});

it('origin, no options', () => {
const glb = ensureGlobals({ nodeType: 9 }, {});
expect(glb.origin).toBe('http://document.qwik.dev');
});

it('origin', () => {
const glb = ensureGlobals({ nodeType: 9 }, { url: '/my-path' });
expect(glb.origin).toBe('http://document.qwik.dev');
});

it('invalid document', () => {
expect(() => {
ensureGlobals({}, {});
}).toThrow();
});
});

describe('document ensureGlobals', () => {
it('qwik server createDocument()', () => {
const doc = createDocument();
expect(doc.defaultView).not.toBeUndefined();
expect(doc.defaultView!.document).toBe(doc);
});

it('qwik server createGlobal()', () => {
const gbl = createGlobal();
expect(gbl.document.defaultView).not.toBeUndefined();
expect(gbl.document.defaultView).toBe(gbl);
});

it('some other document', () => {
const doc: any = {
nodeType: 9,
};
ensureGlobals(doc, {});
ensureGlobals(doc, {}); // shouldn't reset
expect(doc.defaultView).not.toBeUndefined();
expect(doc.defaultView.document).toBe(doc);
});
});
2 changes: 1 addition & 1 deletion src/testing/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface DocumentOptions {
// (undocumented)
debug?: boolean;
// (undocumented)
url?: URL;
url?: URL | string;
}

// @alpha
Expand Down

0 comments on commit 3dcb7f3

Please sign in to comment.