From 6277f304ae572439ff3d9567c6b9e96fe1e2ce1a Mon Sep 17 00:00:00 2001 From: TatsuyaYamamoto Date: Wed, 2 Nov 2022 17:58:20 +0900 Subject: [PATCH 1/5] feat: receive cssUrls as appProps --- src/single-spa-css.ts | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/single-spa-css.ts b/src/single-spa-css.ts index 0ee2ade..55a02a8 100644 --- a/src/single-spa-css.ts +++ b/src/single-spa-css.ts @@ -13,9 +13,7 @@ const defaultOptions: Required = { }, }; -export default function singleSpaCss( - _opts: SingleSpaCssOpts -): CSSLifecycles { +export default function singleSpaCss(_opts: SingleSpaCssOpts): CSSLifecycles { if (!_opts || typeof _opts !== "object") { throw Error(`single-spa-css: opts must be an object`); } @@ -51,9 +49,10 @@ export default function singleSpaCss( const linkElements: LinkElements = {}; let linkElementsToUnmount: ElementsToUnmount[] = []; - function bootstrap(props: AppProps) { + function bootstrap(props: AppPropsWithCssExtra) { + const cssUrls = [...(props.cssUrls ?? []), ...allCssUrls]; return Promise.all( - allCssUrls.map( + cssUrls.map( (cssUrl) => new Promise((resolve, reject) => { const [url] = extractUrl(cssUrl); @@ -77,9 +76,11 @@ export default function singleSpaCss( ); } - function mount(props: AppProps) { + function mount(props: AppPropsWithCssExtra) { + const cssUrls = [...(props.cssUrls ?? []), ...allCssUrls]; + return Promise.all( - allCssUrls.map( + cssUrls.map( (cssUrl) => new Promise((resolve, reject) => { const [url, shouldUnmount] = extractUrl(cssUrl); @@ -122,7 +123,7 @@ export default function singleSpaCss( ); } - function unmount(props: AppProps) { + function unmount(props: AppPropsWithCssExtra) { const elements = linkElementsToUnmount; // reset this array immediately so that only one mounted instance tries to unmount @@ -178,8 +179,12 @@ type LinkElements = { type ElementsToUnmount = [HTMLLinkElement, string]; -type CSSLifecycles = { - bootstrap: LifeCycleFn; - mount: LifeCycleFn; - unmount: LifeCycleFn; +interface AppPropsWithCssExtra extends AppProps { + cssUrls?: CssUrl[]; +} + +type CSSLifecycles = { + bootstrap: LifeCycleFn; + mount: LifeCycleFn; + unmount: LifeCycleFn; }; From adc2feaeee84e1450783457dad8d7842464cb6d2 Mon Sep 17 00:00:00 2001 From: TatsuyaYamamoto Date: Wed, 2 Nov 2022 21:34:42 +0900 Subject: [PATCH 2/5] chore: check array type --- src/single-spa-css.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/single-spa-css.ts b/src/single-spa-css.ts index 55a02a8..7aa4c5d 100644 --- a/src/single-spa-css.ts +++ b/src/single-spa-css.ts @@ -50,7 +50,16 @@ export default function singleSpaCss(_opts: SingleSpaCssOpts): CSSLifecycles { let linkElementsToUnmount: ElementsToUnmount[] = []; function bootstrap(props: AppPropsWithCssExtra) { - const cssUrls = [...(props.cssUrls ?? []), ...allCssUrls]; + const cssUrls: CssUrl[] = [...allCssUrls]; + + if (props.cssUrls) { + if (!Array.isArray(props.cssUrls)) { + throw Error("single-spa-css: cssUrls must be an array"); + } + + cssUrls.push(...props.cssUrls); + } + return Promise.all( cssUrls.map( (cssUrl) => From be4127db662f90b09c81cc96a6e10eadc8e74012 Mon Sep 17 00:00:00 2001 From: TatsuyaYamamoto Date: Wed, 2 Nov 2022 21:42:44 +0900 Subject: [PATCH 3/5] fix: fix type --- src/single-spa-css.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/single-spa-css.ts b/src/single-spa-css.ts index 7aa4c5d..b8aff7c 100644 --- a/src/single-spa-css.ts +++ b/src/single-spa-css.ts @@ -13,7 +13,9 @@ const defaultOptions: Required = { }, }; -export default function singleSpaCss(_opts: SingleSpaCssOpts): CSSLifecycles { +export default function singleSpaCss( + _opts: SingleSpaCssOpts +): CSSLifecycles { if (!_opts || typeof _opts !== "object") { throw Error(`single-spa-css: opts must be an object`); } @@ -49,7 +51,7 @@ export default function singleSpaCss(_opts: SingleSpaCssOpts): CSSLifecycles { const linkElements: LinkElements = {}; let linkElementsToUnmount: ElementsToUnmount[] = []; - function bootstrap(props: AppPropsWithCssExtra) { + function bootstrap(props: AppProps & CssExtraProps & ExtraProps) { const cssUrls: CssUrl[] = [...allCssUrls]; if (props.cssUrls) { @@ -85,7 +87,7 @@ export default function singleSpaCss(_opts: SingleSpaCssOpts): CSSLifecycles { ); } - function mount(props: AppPropsWithCssExtra) { + function mount(props: AppProps & CssExtraProps & ExtraProps) { const cssUrls = [...(props.cssUrls ?? []), ...allCssUrls]; return Promise.all( @@ -132,7 +134,7 @@ export default function singleSpaCss(_opts: SingleSpaCssOpts): CSSLifecycles { ); } - function unmount(props: AppPropsWithCssExtra) { + function unmount(props: AppProps & CssExtraProps & ExtraProps) { const elements = linkElementsToUnmount; // reset this array immediately so that only one mounted instance tries to unmount @@ -188,12 +190,12 @@ type LinkElements = { type ElementsToUnmount = [HTMLLinkElement, string]; -interface AppPropsWithCssExtra extends AppProps { +type CssExtraProps = { cssUrls?: CssUrl[]; -} +}; -type CSSLifecycles = { - bootstrap: LifeCycleFn; - mount: LifeCycleFn; - unmount: LifeCycleFn; +type CSSLifecycles = { + bootstrap: LifeCycleFn; + mount: LifeCycleFn; + unmount: LifeCycleFn; }; From b7ac46621f147e3e77151315512bed1ee6219b7b Mon Sep 17 00:00:00 2001 From: TatsuyaYamamoto Date: Wed, 2 Nov 2022 21:50:08 +0900 Subject: [PATCH 4/5] test: add test case --- src/single-spa-css.test.ts | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/single-spa-css.test.ts b/src/single-spa-css.test.ts index 8d4c5ff..166f1d8 100644 --- a/src/single-spa-css.test.ts +++ b/src/single-spa-css.test.ts @@ -17,23 +17,42 @@ describe("single-spa-css", () => { expect(() => singleSpaCss("asdfsdf")).toThrowError(); }); - it(`throws if cssUrls is not an array`, () => { + it(`throws if opts.cssUrls is not an array`, () => { // @ts-ignore expect(() => singleSpaCss({ cssUrls: "/main.css" })).toThrowError(); }); - it(`preloads scripts during the bootstrap lifecycle`, async () => { + it(`throws if appProps.cssUrls is not an array`, () => { const url = "https://example.com/main.css"; const lifecycles = singleSpaCss<{}>({ cssUrls: [url], }); - expect(findPreloadEl(url)).not.toBeInTheDocument(); + expect(() => + lifecycles.bootstrap({ + ...createProps(), + // @ts-ignore + cssUrls: "/main.css", + }) + ).toThrowError(); + }); + + it(`preloads scripts during the bootstrap lifecycle`, async () => { + const url1 = "https://example.com/main_1.css"; + const url2 = "https://example.com/main_2.css"; + + const lifecycles = singleSpaCss<{}>({ + cssUrls: [url1], + }); + + expect(findPreloadEl(url1)).not.toBeInTheDocument(); + expect(findPreloadEl(url2)).not.toBeInTheDocument(); - await lifecycles.bootstrap(createProps()); + await lifecycles.bootstrap({ ...createProps(), cssUrls: [url2] }); - expect(findPreloadEl(url)).toBeInTheDocument(); + expect(findPreloadEl(url1)).toBeInTheDocument(); + expect(findPreloadEl(url2)).toBeInTheDocument(); }); it(`mounts elements and waits for them to load before resolving the mount promise. Then it unmounts them`, async () => { From d33c5cf5d4c2b07148cd627d0068dc237cb052a9 Mon Sep 17 00:00:00 2001 From: TatsuyaYamamoto Date: Wed, 2 Nov 2022 21:56:56 +0900 Subject: [PATCH 5/5] chore: rename --- src/single-spa-css.test.ts | 2 +- src/single-spa-css.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/single-spa-css.test.ts b/src/single-spa-css.test.ts index 166f1d8..01d6932 100644 --- a/src/single-spa-css.test.ts +++ b/src/single-spa-css.test.ts @@ -22,7 +22,7 @@ describe("single-spa-css", () => { expect(() => singleSpaCss({ cssUrls: "/main.css" })).toThrowError(); }); - it(`throws if appProps.cssUrls is not an array`, () => { + it(`throws if customProps.cssUrls is not an array`, () => { const url = "https://example.com/main.css"; const lifecycles = singleSpaCss<{}>({ diff --git a/src/single-spa-css.ts b/src/single-spa-css.ts index b8aff7c..79b583d 100644 --- a/src/single-spa-css.ts +++ b/src/single-spa-css.ts @@ -1,4 +1,4 @@ -import { AppProps, LifeCycleFn } from "single-spa"; +import { AppProps, LifeCycleFn, CustomProps } from "single-spa"; const defaultOptions: Required = { cssUrls: [], @@ -51,7 +51,7 @@ export default function singleSpaCss( const linkElements: LinkElements = {}; let linkElementsToUnmount: ElementsToUnmount[] = []; - function bootstrap(props: AppProps & CssExtraProps & ExtraProps) { + function bootstrap(props: AppProps & CssCustomProps & ExtraProps) { const cssUrls: CssUrl[] = [...allCssUrls]; if (props.cssUrls) { @@ -87,7 +87,7 @@ export default function singleSpaCss( ); } - function mount(props: AppProps & CssExtraProps & ExtraProps) { + function mount(props: AppProps & CssCustomProps & ExtraProps) { const cssUrls = [...(props.cssUrls ?? []), ...allCssUrls]; return Promise.all( @@ -134,7 +134,7 @@ export default function singleSpaCss( ); } - function unmount(props: AppProps & CssExtraProps & ExtraProps) { + function unmount(props: AppProps & CssCustomProps & ExtraProps) { const elements = linkElementsToUnmount; // reset this array immediately so that only one mounted instance tries to unmount @@ -190,12 +190,12 @@ type LinkElements = { type ElementsToUnmount = [HTMLLinkElement, string]; -type CssExtraProps = { +type CssCustomProps = { cssUrls?: CssUrl[]; }; type CSSLifecycles = { - bootstrap: LifeCycleFn; - mount: LifeCycleFn; - unmount: LifeCycleFn; + bootstrap: LifeCycleFn; + mount: LifeCycleFn; + unmount: LifeCycleFn; };