From 132bca6229e1ab122a30127524dcd6a99808f226 Mon Sep 17 00:00:00 2001 From: Katerina Zakimatova Date: Thu, 20 Jun 2024 12:39:20 +0200 Subject: [PATCH 1/3] allow-passing-entry-options-via-script-query --- packages/core/src/helpers/web.ts | 19 +++++++++++++++++++ packages/scripts/src/create-web-entrypoint.ts | 5 ++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/core/src/helpers/web.ts b/packages/core/src/helpers/web.ts index d57d407c2..a2571cfb1 100644 --- a/packages/core/src/helpers/web.ts +++ b/packages/core/src/helpers/web.ts @@ -9,3 +9,22 @@ export function injectScript(win: Window, rootComId: string, scriptUrl: string) win.document.head.appendChild(scriptEl); }); } + +export function getEngineEntryOptions(envName: string) { + const urlParams = new URLSearchParams(globalThis.location.search); + const currentScript = globalThis.document?.currentScript + const isHtmlScript = !!currentScript && 'src' in currentScript; + + const scriptQueryString = isHtmlScript && currentScript.src?.split?.('?')?.[1] || '' + const scriptUrlParams = new URLSearchParams(scriptQueryString) + const injectedOptions = globalThis.engineEntryOptions?.({ urlParams, envName }) ?? new URLSearchParams(''); + + const definedParams = new Set() + return new URLSearchParams([...injectedOptions, ...urlParams, ...scriptUrlParams].filter(([key]) => { + if (definedParams.has(key)) { + return false + } + definedParams.add(key) + return true + })) +} diff --git a/packages/scripts/src/create-web-entrypoint.ts b/packages/scripts/src/create-web-entrypoint.ts index 56901da5e..ac2a1563e 100644 --- a/packages/scripts/src/create-web-entrypoint.ts +++ b/packages/scripts/src/create-web-entrypoint.ts @@ -46,10 +46,9 @@ export function createMainEntrypoint({ ); return ` -import { main, COM } from '@wixc3/engine-core'; +import { main, COM, getEngineEntryOptions } from '@wixc3/engine-core'; -const urlParams = new URLSearchParams(globalThis.location.search); -const options = globalThis.engineEntryOptions?.({ urlParams, envName: ${stringify(env.name)} }) ?? urlParams; +const options = getEngineEntryOptions(${stringify(env.name)}) const runtimePublicPath = ${runtimePublicPath}; main({ featureName: ${stringify(featureName)}, From 035cf2222fd4262e5f4b2f13da75d33e9f968ee7 Mon Sep 17 00:00:00 2001 From: Katerina Zakimatova Date: Mon, 24 Jun 2024 17:51:31 +0200 Subject: [PATCH 2/3] add tests + improve getEngineEntryOptions --- packages/core/src/helpers/web.ts | 30 +++++++++---------- packages/core/src/types.ts | 2 ++ packages/core/test/helpers.spec.ts | 25 ++++++++++++++++ packages/scripts/src/create-web-entrypoint.ts | 2 +- 4 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 packages/core/test/helpers.spec.ts diff --git a/packages/core/src/helpers/web.ts b/packages/core/src/helpers/web.ts index a2571cfb1..24c81dd8c 100644 --- a/packages/core/src/helpers/web.ts +++ b/packages/core/src/helpers/web.ts @@ -1,3 +1,5 @@ +import { IRunOptions } from '../types'; + export function injectScript(win: Window, rootComId: string, scriptUrl: string) { return new Promise((res, rej) => { // This is the contract of the communication to get the root communication id @@ -10,21 +12,19 @@ export function injectScript(win: Window, rootComId: string, scriptUrl: string) }); } -export function getEngineEntryOptions(envName: string) { - const urlParams = new URLSearchParams(globalThis.location.search); - const currentScript = globalThis.document?.currentScript - const isHtmlScript = !!currentScript && 'src' in currentScript; +interface EngineWebEntryGlobalObj { + document?: Document, + location?: Location + + engineEntryOptions(options: { urlParams: URLSearchParams; envName: string }): IRunOptions; +} + +export function getEngineEntryOptions(envName: string, globalObj: EngineWebEntryGlobalObj): IRunOptions { + const urlParams = new URLSearchParams(globalObj?.location?.search); + const currentScript = globalObj?.document?.currentScript; - const scriptQueryString = isHtmlScript && currentScript.src?.split?.('?')?.[1] || '' - const scriptUrlParams = new URLSearchParams(scriptQueryString) - const injectedOptions = globalThis.engineEntryOptions?.({ urlParams, envName }) ?? new URLSearchParams(''); + const optionsFromScript = new URLSearchParams(currentScript && currentScript.dataset.engineRunOptions || undefined); + const injectedOptions = globalObj?.engineEntryOptions?.({ urlParams, envName }) ?? new URLSearchParams(''); - const definedParams = new Set() - return new URLSearchParams([...injectedOptions, ...urlParams, ...scriptUrlParams].filter(([key]) => { - if (definedParams.has(key)) { - return false - } - definedParams.add(key) - return true - })) + return new Map([...optionsFromScript, ...urlParams, ...injectedOptions]); } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 369ebbb35..849641dc4 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -171,6 +171,8 @@ export interface IRunOptions { has(key: string): boolean; get(key: string): string | string[] | boolean | null | undefined; entries(): IterableIterator<[string, string | string[] | boolean | null | undefined]>; + + [Symbol.iterator](): IterableIterator<[string, string | string[] | boolean | null | undefined]>; } export type RegisteringFeature< diff --git a/packages/core/test/helpers.spec.ts b/packages/core/test/helpers.spec.ts new file mode 100644 index 000000000..6e617432a --- /dev/null +++ b/packages/core/test/helpers.spec.ts @@ -0,0 +1,25 @@ +import { expect } from 'chai'; +import { getEngineEntryOptions } from '@wixc3/engine-core'; + +describe('helpers', () => { + describe('getEngineEntryOptions', () => { + it('it gets engine entry options from query string, from script url, from engineEntryOptions', () => { + const document = { currentScript: { dataset: { engineRunOptions: 'http://localhost:3000?one=0&two=1&script=123' } } } as unknown as Document; + const location = { search: 'one=2&two=2&search=123' } as Location; + const engineEntryOptions = ({ envName }: { envName: string }) => { + if (envName === 'thisTest') { + return new URLSearchParams([['injected', '123'], ['one', '1']]); + } + return new URLSearchParams(); + }; + const result = getEngineEntryOptions('thisTest', { document, location, engineEntryOptions }); + + expect(result.get('one'), 'Priorities injected options over search string and script url').to.eql('1'); + expect(result.get('two'), 'Priorities search params over script url').to.eql('2'); + expect(result.get('script'), 'Gets options from script url').to.eql('123'); + expect(result.get('search'), 'Gets options from search string').to.eql('123'); + expect(result.get('injected'), 'Gets options from engineEntryOptions').to.eql('123'); + }); + }); +}); + diff --git a/packages/scripts/src/create-web-entrypoint.ts b/packages/scripts/src/create-web-entrypoint.ts index ac2a1563e..8a64facbd 100644 --- a/packages/scripts/src/create-web-entrypoint.ts +++ b/packages/scripts/src/create-web-entrypoint.ts @@ -48,7 +48,7 @@ export function createMainEntrypoint({ return ` import { main, COM, getEngineEntryOptions } from '@wixc3/engine-core'; -const options = getEngineEntryOptions(${stringify(env.name)}) +const options = getEngineEntryOptions(${stringify(env.name)}, globalThis) const runtimePublicPath = ${runtimePublicPath}; main({ featureName: ${stringify(featureName)}, From 322f4bd68630379d600be67cc1c508c8e20b0fe9 Mon Sep 17 00:00:00 2001 From: Katerina Zakimatova Date: Tue, 25 Jun 2024 12:19:13 +0200 Subject: [PATCH 3/3] allow to override options with injected options --- packages/core/src/helpers/web.ts | 15 +++--- packages/core/test/helpers.spec.ts | 73 ++++++++++++++++++++++-------- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/packages/core/src/helpers/web.ts b/packages/core/src/helpers/web.ts index 24c81dd8c..45c8de8b6 100644 --- a/packages/core/src/helpers/web.ts +++ b/packages/core/src/helpers/web.ts @@ -13,10 +13,10 @@ export function injectScript(win: Window, rootComId: string, scriptUrl: string) } interface EngineWebEntryGlobalObj { - document?: Document, - location?: Location + document?: { currentScript: { dataset: { engineRunOptions?: string | null } } | null }, + location?: { search?: string } - engineEntryOptions(options: { urlParams: URLSearchParams; envName: string }): IRunOptions; + engineEntryOptions?: (options: { currentRunOptions: IRunOptions; envName: string }) => IRunOptions; } export function getEngineEntryOptions(envName: string, globalObj: EngineWebEntryGlobalObj): IRunOptions { @@ -24,7 +24,10 @@ export function getEngineEntryOptions(envName: string, globalObj: EngineWebEntry const currentScript = globalObj?.document?.currentScript; const optionsFromScript = new URLSearchParams(currentScript && currentScript.dataset.engineRunOptions || undefined); - const injectedOptions = globalObj?.engineEntryOptions?.({ urlParams, envName }) ?? new URLSearchParams(''); - - return new Map([...optionsFromScript, ...urlParams, ...injectedOptions]); + const optionsBeforeInject = new Map([...optionsFromScript, ...urlParams]); + const optionsAfterInject = globalObj?.engineEntryOptions?.({ + currentRunOptions: optionsBeforeInject, + envName + }); + return optionsAfterInject || optionsBeforeInject; } diff --git a/packages/core/test/helpers.spec.ts b/packages/core/test/helpers.spec.ts index 6e617432a..c04aa4b4a 100644 --- a/packages/core/test/helpers.spec.ts +++ b/packages/core/test/helpers.spec.ts @@ -1,25 +1,60 @@ import { expect } from 'chai'; -import { getEngineEntryOptions } from '@wixc3/engine-core'; +import { getEngineEntryOptions, IRunOptions } from '@wixc3/engine-core'; describe('helpers', () => { - describe('getEngineEntryOptions', () => { - it('it gets engine entry options from query string, from script url, from engineEntryOptions', () => { - const document = { currentScript: { dataset: { engineRunOptions: 'http://localhost:3000?one=0&two=1&script=123' } } } as unknown as Document; - const location = { search: 'one=2&two=2&search=123' } as Location; - const engineEntryOptions = ({ envName }: { envName: string }) => { - if (envName === 'thisTest') { - return new URLSearchParams([['injected', '123'], ['one', '1']]); - } - return new URLSearchParams(); - }; - const result = getEngineEntryOptions('thisTest', { document, location, engineEntryOptions }); + describe('getEngineEntryOptions', () => { + it('it gets engine entry options from query string, from script url, from engineEntryOptions', () => { + const document = { + currentScript: { dataset: { engineRunOptions: 'http://localhost:3000?one=0&two=1&script=123' } }, + }; + const location = { search: 'one=2&two=2&search=123' }; + const engineEntryOptions = ({ + envName, + currentRunOptions, + }: { + envName: string; + currentRunOptions: IRunOptions; + }) => { + if (envName === 'thisTest') { + return new Map([...currentRunOptions, ['injected', '123'], ['one', '1']]); + } + return new Map(); + }; + const result = getEngineEntryOptions('thisTest', { document, location, engineEntryOptions }); - expect(result.get('one'), 'Priorities injected options over search string and script url').to.eql('1'); - expect(result.get('two'), 'Priorities search params over script url').to.eql('2'); - expect(result.get('script'), 'Gets options from script url').to.eql('123'); - expect(result.get('search'), 'Gets options from search string').to.eql('123'); - expect(result.get('injected'), 'Gets options from engineEntryOptions').to.eql('123'); + expect(result.get('one'), 'Prioritises injected options over search string and script url').to.eql('1'); + expect(result.get('two'), 'Prioritises search params over script url').to.eql('2'); + expect(result.get('script'), 'Gets options from script url').to.eql('123'); + expect(result.get('search'), 'Gets options from search string').to.eql('123'); + expect(result.get('injected'), 'Gets options from engineEntryOptions').to.eql('123'); + }); + it('works without inject function', () => { + const document = { + currentScript: { dataset: { engineRunOptions: 'http://localhost:3000?one=0&script=123' } }, + }; + const location = { search: 'one=1&search=123' }; + const result = getEngineEntryOptions('thisTest', { document, location }); + + expect(result.get('one'), 'Prioritises injected options over search string and script url').to.eql('1'); + expect(result.get('script'), 'Gets options from script url').to.eql('123'); + expect(result.get('search'), 'Gets options from search string').to.eql('123'); + }); + it('allows to override options completely with getEngineEntryOptions', () => { + const document = { + currentScript: { dataset: { engineRunOptions: 'http://localhost:3000?script=123' } }, + }; + const location = { search: 'search=123' }; + const engineEntryOptions = ({ envName }: { envName: string }) => { + if (envName === 'thisTest') { + return new Map([['injected', '123']]); + } + return new Map(); + }; + const result = getEngineEntryOptions('thisTest', { document, location, engineEntryOptions }); + + expect(result.get('script'), 'Ignores options from script url').to.eql(undefined); + expect(result.get('search'), 'Ignores options from search string').to.eql(undefined); + expect(result.get('injected'), 'Gets options from engineEntryOptions').to.eql('123'); + }); }); - }); }); -