From 412ab1a14bad408fe74cdc1de2407b0c15fa7061 Mon Sep 17 00:00:00 2001 From: Tolga Cesur Date: Tue, 6 Jul 2021 15:50:06 +0300 Subject: [PATCH] Implement on demand client async fragments --- package-lock.json | 2 +- package.json | 2 +- src/core.ts | 11 +++++--- src/types.ts | 1 + test/core.spec.ts | 65 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 74 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1fa44a2..a37a966 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@puzzle-js/client-lib", - "version": "1.4.6", + "version": "1.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 86fd37b..7f24e9e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@puzzle-js/client-lib", "main": "dist/index.js", - "version": "1.4.6", + "version": "1.5.0", "author": "", "license": "MIT", "repository": { diff --git a/src/core.ts b/src/core.ts index 8d4d5ce..3bb9227 100644 --- a/src/core.ts +++ b/src/core.ts @@ -31,13 +31,14 @@ export class Core extends Module { }); } - const forcedFragments = Core.__pageConfiguration.fragments.filter(i => i.clientAsync && i.clientAsyncForce); + const fragments = Core.__pageConfiguration.fragments.filter(i => !i.onDemand); + const forcedFragments = fragments.filter(i => i.clientAsync && i.clientAsyncForce); if (forcedFragments.length) { forcedFragments.forEach(fragment => Core.asyncLoadFragment(fragment)); } if (this.isIntersectionObserverSupported()) { - const asyncFragments = Core.__pageConfiguration.fragments.some(i => i.clientAsync); + const asyncFragments = fragments.some(i => i.clientAsync); if (asyncFragments) { this.observer = new IntersectionObserver(this.onIntersection.bind(this)); @@ -84,7 +85,7 @@ export class Core extends Module { @on(EVENT.ON_PAGE_LOAD) static asyncComponentRender() { - const asyncFragments = Core.__pageConfiguration.fragments.filter(i => i.clientAsync); + const asyncFragments = Core.__pageConfiguration.fragments.filter(i => i.clientAsync && !i.onDemand); asyncFragments.forEach(fragment => { if (this.observer) { @@ -100,7 +101,7 @@ export class Core extends Module { } private static asyncLoadFragment(fragment: IPageFragmentConfig) { - if (fragment.asyncLoaded) return; + if (fragment.asyncLoaded) return Promise.resolve(); fragment.asyncLoaded = true; const queryString = this.prepareQueryString(fragment.attributes); const key = `${fragment.source}${window.location.pathname}${queryString}`; @@ -302,6 +303,8 @@ export class Core extends Module { return this.asyncLoadFragment(fragment); } } + + return Promise.resolve(); } private static isIntersectionObserverSupported() { diff --git a/src/types.ts b/src/types.ts index e195524..fde1ce7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,6 +32,7 @@ export interface IPageFragmentConfig { chunked: boolean; clientAsync: boolean; clientAsyncForce: boolean | undefined; + onDemand: boolean | undefined; asyncDecentralized: boolean; attributes: { [name: string]: string }; source: string | undefined; diff --git a/test/core.spec.ts b/test/core.spec.ts index 6c7e177..183edf8 100644 --- a/test/core.spec.ts +++ b/test/core.spec.ts @@ -4,7 +4,6 @@ import {PuzzleJs} from "../src/puzzle"; import {Core} from "../src/core"; import {createPageLibConfiguration} from "./mock"; import sinon, { SinonStub } from "sinon"; -import {AssetHelper} from "../src/assetHelper"; import * as faker from "faker"; import {IPageLibAsset, IPageLibConfiguration, IPageLibDependency} from "../src/types"; import {RESOURCE_LOADING_TYPE, RESOURCE_TYPE} from "../src/enums"; @@ -203,6 +202,7 @@ describe('Module - Core', () => { chunked: true, clientAsync: true, clientAsyncForce: undefined, + onDemand: undefined, source: undefined, asyncDecentralized: false }], @@ -256,6 +256,7 @@ describe('Module - Core', () => { chunked: true, clientAsync: true, clientAsyncForce: true, + onDemand: undefined, source: undefined, asyncDecentralized: false }], @@ -278,4 +279,66 @@ describe('Module - Core', () => { expect(fetchStub.getCall(0).lastArg.headers).to.haveOwnProperty("originalurl"); expect(stubAsyncRenderResponse.calledOnce).to.eq(true); }); + + it('should return a promise object that is resolved if fragment does not exist', () => { + const assets = [] as IPageLibAsset[]; + const dependencies = [] as IPageLibDependency[]; + const config = { + dependencies, + assets, + fragments: [], + page: 'page', + peers: [] + } as IPageLibConfiguration; + + Core.config(JSON.stringify(config)); + const result = Core.renderAsyncFragment('test'); + + expect(result).to.be.a('promise'); + }); + + it('should return a promise object that is resolved if fragment is asyncLoaded', () => { + const assets = [ + { + name: 'bundle1', + dependent: ['vendor1'], + preLoaded: false, + link: 'bundle1.js', + fragment: 'test', + loadMethod: RESOURCE_LOADING_TYPE.ON_PAGE_RENDER, + type: RESOURCE_TYPE.JS + } + ] as IPageLibAsset[]; + const dependencies = [ + { + name: 'vendor1', + link: 'vendor1.js', + preLoaded: false + } + ] as IPageLibDependency[]; + const config = { + dependencies, + assets, + fragments: [{ + name: 'test', + attributes: { + if: "false" + }, + chunked: true, + clientAsync: true, + clientAsyncForce: undefined, + onDemand: undefined, + source: undefined, + asyncDecentralized: false, + asyncLoaded: true + }], + page: 'page', + peers: [] + } as IPageLibConfiguration; + + Core.config(JSON.stringify(config)); + const result = Core.renderAsyncFragment('test'); + + expect(result).to.be.a('promise'); + }); });