diff --git a/package.json b/package.json index 6cc49f5..3eb38ba 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@puzzle-js/client-lib", "main": "dist/index.js", - "version": "1.2.4", + "version": "1.3.0", "author": "", "license": "MIT", "repository": { diff --git a/src/core.ts b/src/core.ts index ea2c848..406da58 100644 --- a/src/core.ts +++ b/src/core.ts @@ -95,15 +95,16 @@ export class Core extends Module { } private static asyncLoadFragment(fragment: IPageFragmentConfig) { + if (fragment.asyncLoaded) return; + fragment.asyncLoaded = true; const queryString = this.prepareQueryString(fragment.attributes); - const key = `${fragment.source}${location.pathname}${queryString}`; + const key = `${fragment.source}${window.location.pathname}${queryString}`; if (!fragment.asyncDecentralized) { return this.fetchGatewayFragment(fragment) .then(res => this.asyncRenderResponse(fragment, res)); } - Core.gun .get(key, (gunResponse: any) => { if (gunResponse.err || !gunResponse.put) { @@ -141,7 +142,7 @@ export class Core extends Module { private static fetchGatewayFragment(fragment: IPageFragmentConfig) { const queryString = this.prepareQueryString(fragment.attributes); - const fragmentRequestUrl = `${fragment.source}${location.pathname}${queryString}`; + const fragmentRequestUrl = `${fragment.source}${window.location.pathname}${queryString}`; return fetch(fragmentRequestUrl, { credentials: 'include' }) @@ -183,7 +184,7 @@ export class Core extends Module { } private static prepareQueryString(fragmentAttributes: Record) { - const attributes = Object.assign(location.search.slice(1).split('&').reduce((dict: { [name: string]: string }, i) => { + const attributes = Object.assign(window.location.search.slice(1).split('&').reduce((dict: { [name: string]: string }, i) => { const [key, value] = i.split('='); if (typeof value !== "undefined") { dict[key] = value; @@ -269,6 +270,18 @@ export class Core extends Module { }); } + static renderAsyncFragment(fragmentName: string) { + const fragment = this.__pageConfiguration.fragments.find(item => item.name === fragmentName); + if (fragment) { + const selector = this.getFragmentContainerSelector(fragment, "main"); + const fragmentContainer = window.document.querySelector(selector); + if (fragmentContainer ) { + if (this.observer) this.observer.unobserve(fragmentContainer); + return this.asyncLoadFragment(fragment); + } + } + } + private static isIntersectionObserverSupported() { return 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window diff --git a/src/types.ts b/src/types.ts index c671697..fd3d958 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,6 +34,7 @@ export interface IPageFragmentConfig { asyncDecentralized: boolean; attributes: { [name: string]: string }; source: string | undefined; + asyncLoaded?: boolean; } export interface IPageLibDependency { diff --git a/test/core.spec.ts b/test/core.spec.ts index eca2502..cb34273 100644 --- a/test/core.spec.ts +++ b/test/core.spec.ts @@ -29,12 +29,12 @@ declare var global: Global; describe('Module - Core', () => { beforeEach(() => { global.window = (new JSDOM(``, {runScripts: "outside-only"})).window; - sandbox.verifyAndRestore(); }); afterEach(() => { delete global.window; PuzzleJs.clearListeners(); + sandbox.verifyAndRestore(); (Core as any)._pageConfiguration = undefined; }); @@ -170,7 +170,7 @@ describe('Module - Core', () => { []); }); - it('should create true load queue for js assets excluding conditional fragments', function () { + it('should render async fragment', async () => { const assets = [ { name: 'bundle1', @@ -198,7 +198,7 @@ describe('Module - Core', () => { if: "false" }, chunked: true, - clientAsync: false, + clientAsync: true, source: undefined, asyncDecentralized: false }], @@ -206,11 +206,18 @@ describe('Module - Core', () => { peers: [] } as IPageLibConfiguration; - const mockLoadJsSeries = sandbox.mock(AssetHelper); + const fragmentContainer = global.window.document.createElement('div'); + fragmentContainer.setAttribute('puzzle-fragment', 'test'); + global.window.document.body.appendChild(fragmentContainer); + + const stubFetchGatewayFragment = sandbox.stub(Core as any, "fetchGatewayFragment").resolves(); + const stubAsyncRenderResponse = sandbox.stub(Core as any, "asyncRenderResponse").resolves(); Core.config(JSON.stringify(config)); - Core.pageLoaded(); + await Core.renderAsyncFragment('test'); + await Core.renderAsyncFragment('test'); - mockLoadJsSeries.expects("loadJsSeries").calledWith([]); + expect(stubFetchGatewayFragment.calledOnce).to.eq(true); + expect(stubAsyncRenderResponse.calledOnce).to.eq(true); }); });